LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - rbnf.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 820 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 89 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : *******************************************************************************
       5             : * Copyright (C) 1997-2015, International Business Machines Corporation
       6             : * and others. All Rights Reserved.
       7             : *******************************************************************************
       8             : */
       9             : 
      10             : #include "unicode/utypes.h"
      11             : #include "utypeinfo.h"  // for 'typeid' to work
      12             : 
      13             : #include "unicode/rbnf.h"
      14             : 
      15             : #if U_HAVE_RBNF
      16             : 
      17             : #include "unicode/normlzr.h"
      18             : #include "unicode/plurfmt.h"
      19             : #include "unicode/tblcoll.h"
      20             : #include "unicode/uchar.h"
      21             : #include "unicode/ucol.h"
      22             : #include "unicode/uloc.h"
      23             : #include "unicode/unum.h"
      24             : #include "unicode/ures.h"
      25             : #include "unicode/ustring.h"
      26             : #include "unicode/utf16.h"
      27             : #include "unicode/udata.h"
      28             : #include "unicode/udisplaycontext.h"
      29             : #include "unicode/brkiter.h"
      30             : #include "unicode/ucasemap.h"
      31             : 
      32             : #include "cmemory.h"
      33             : #include "cstring.h"
      34             : #include "patternprops.h"
      35             : #include "uresimp.h"
      36             : #include "nfrs.h"
      37             : #include "digitlst.h"
      38             : 
      39             : // debugging
      40             : // #define RBNF_DEBUG
      41             : 
      42             : #ifdef RBNF_DEBUG
      43             : #include <stdio.h>
      44             : #endif
      45             : 
      46             : #define U_ICUDATA_RBNF U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "rbnf"
      47             : 
      48             : static const UChar gPercentPercent[] =
      49             : {
      50             :     0x25, 0x25, 0
      51             : }; /* "%%" */
      52             : 
      53             : // All urbnf objects are created through openRules, so we init all of the
      54             : // Unicode string constants required by rbnf, nfrs, or nfr here.
      55             : static const UChar gLenientParse[] =
      56             : {
      57             :     0x25, 0x25, 0x6C, 0x65, 0x6E, 0x69, 0x65, 0x6E, 0x74, 0x2D, 0x70, 0x61, 0x72, 0x73, 0x65, 0x3A, 0
      58             : }; /* "%%lenient-parse:" */
      59             : static const UChar gSemiColon = 0x003B;
      60             : static const UChar gSemiPercent[] =
      61             : {
      62             :     0x3B, 0x25, 0
      63             : }; /* ";%" */
      64             : 
      65             : #define kSomeNumberOfBitsDiv2 22
      66             : #define kHalfMaxDouble (double)(1 << kSomeNumberOfBitsDiv2)
      67             : #define kMaxDouble (kHalfMaxDouble * kHalfMaxDouble)
      68             : 
      69             : U_NAMESPACE_BEGIN
      70             : 
      71           0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedNumberFormat)
      72             : 
      73             : /*
      74             : This is a utility class. It does not use ICU's RTTI.
      75             : If ICU's RTTI is needed again, you can uncomment the RTTI code and derive from UObject.
      76             : Please make sure that intltest passes on Windows in Release mode,
      77             : since the string pooling per compilation unit will mess up how RTTI works.
      78             : The RTTI code was also removed due to lack of code coverage.
      79             : */
      80             : class LocalizationInfo : public UMemory {
      81             : protected:
      82             :     virtual ~LocalizationInfo();
      83             :     uint32_t refcount;
      84             :     
      85             : public:
      86           0 :     LocalizationInfo() : refcount(0) {}
      87             :     
      88           0 :     LocalizationInfo* ref(void) {
      89           0 :         ++refcount;
      90           0 :         return this;
      91             :     }
      92             :     
      93           0 :     LocalizationInfo* unref(void) {
      94           0 :         if (refcount && --refcount == 0) {
      95           0 :             delete this;
      96             :         }
      97           0 :         return NULL;
      98             :     }
      99             :     
     100             :     virtual UBool operator==(const LocalizationInfo* rhs) const;
     101             :     inline  UBool operator!=(const LocalizationInfo* rhs) const { return !operator==(rhs); }
     102             :     
     103             :     virtual int32_t getNumberOfRuleSets(void) const = 0;
     104             :     virtual const UChar* getRuleSetName(int32_t index) const = 0;
     105             :     virtual int32_t getNumberOfDisplayLocales(void) const = 0;
     106             :     virtual const UChar* getLocaleName(int32_t index) const = 0;
     107             :     virtual const UChar* getDisplayName(int32_t localeIndex, int32_t ruleIndex) const = 0;
     108             :     
     109             :     virtual int32_t indexForLocale(const UChar* locale) const;
     110             :     virtual int32_t indexForRuleSet(const UChar* ruleset) const;
     111             :     
     112             : //    virtual UClassID getDynamicClassID() const = 0;
     113             : //    static UClassID getStaticClassID(void);
     114             : };
     115             : 
     116           0 : LocalizationInfo::~LocalizationInfo() {}
     117             : 
     118             : //UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(LocalizationInfo)
     119             : 
     120             : // if both strings are NULL, this returns TRUE
     121             : static UBool 
     122           0 : streq(const UChar* lhs, const UChar* rhs) {
     123           0 :     if (rhs == lhs) {
     124           0 :         return TRUE;
     125             :     }
     126           0 :     if (lhs && rhs) {
     127           0 :         return u_strcmp(lhs, rhs) == 0;
     128             :     }
     129           0 :     return FALSE;
     130             : }
     131             : 
     132             : UBool
     133           0 : LocalizationInfo::operator==(const LocalizationInfo* rhs) const {
     134           0 :     if (rhs) {
     135           0 :         if (this == rhs) {
     136           0 :             return TRUE;
     137             :         }
     138             :         
     139           0 :         int32_t rsc = getNumberOfRuleSets();
     140           0 :         if (rsc == rhs->getNumberOfRuleSets()) {
     141           0 :             for (int i = 0; i < rsc; ++i) {
     142           0 :                 if (!streq(getRuleSetName(i), rhs->getRuleSetName(i))) {
     143           0 :                     return FALSE;
     144             :                 }
     145             :             }
     146           0 :             int32_t dlc = getNumberOfDisplayLocales();
     147           0 :             if (dlc == rhs->getNumberOfDisplayLocales()) {
     148           0 :                 for (int i = 0; i < dlc; ++i) {
     149           0 :                     const UChar* locale = getLocaleName(i);
     150           0 :                     int32_t ix = rhs->indexForLocale(locale);
     151             :                     // if no locale, ix is -1, getLocaleName returns null, so streq returns false
     152           0 :                     if (!streq(locale, rhs->getLocaleName(ix))) {
     153           0 :                         return FALSE;
     154             :                     }
     155           0 :                     for (int j = 0; j < rsc; ++j) {
     156           0 :                         if (!streq(getDisplayName(i, j), rhs->getDisplayName(ix, j))) {
     157           0 :                             return FALSE;
     158             :                         }
     159             :                     }
     160             :                 }
     161           0 :                 return TRUE;
     162             :             }
     163             :         }
     164             :     }
     165           0 :     return FALSE;
     166             : }
     167             : 
     168             : int32_t
     169           0 : LocalizationInfo::indexForLocale(const UChar* locale) const {
     170           0 :     for (int i = 0; i < getNumberOfDisplayLocales(); ++i) {
     171           0 :         if (streq(locale, getLocaleName(i))) {
     172           0 :             return i;
     173             :         }
     174             :     }
     175           0 :     return -1;
     176             : }
     177             : 
     178             : int32_t
     179           0 : LocalizationInfo::indexForRuleSet(const UChar* ruleset) const {
     180           0 :     if (ruleset) {
     181           0 :         for (int i = 0; i < getNumberOfRuleSets(); ++i) {
     182           0 :             if (streq(ruleset, getRuleSetName(i))) {
     183           0 :                 return i;
     184             :             }
     185             :         }
     186             :     }
     187           0 :     return -1;
     188             : }
     189             : 
     190             : 
     191             : typedef void (*Fn_Deleter)(void*);
     192             : 
     193             : class VArray {
     194             :     void** buf;
     195             :     int32_t cap;
     196             :     int32_t size;
     197             :     Fn_Deleter deleter;
     198             : public:
     199           0 :     VArray() : buf(NULL), cap(0), size(0), deleter(NULL) {}
     200             :     
     201           0 :     VArray(Fn_Deleter del) : buf(NULL), cap(0), size(0), deleter(del) {}
     202             :     
     203           0 :     ~VArray() {
     204           0 :         if (deleter) {
     205           0 :             for (int i = 0; i < size; ++i) {
     206           0 :                 (*deleter)(buf[i]);
     207             :             }
     208             :         }
     209           0 :         uprv_free(buf); 
     210           0 :     }
     211             :     
     212           0 :     int32_t length() {
     213           0 :         return size;
     214             :     }
     215             :     
     216           0 :     void add(void* elem, UErrorCode& status) {
     217           0 :         if (U_SUCCESS(status)) {
     218           0 :             if (size == cap) {
     219           0 :                 if (cap == 0) {
     220           0 :                     cap = 1;
     221           0 :                 } else if (cap < 256) {
     222           0 :                     cap *= 2;
     223             :                 } else {
     224           0 :                     cap += 256;
     225             :                 }
     226           0 :                 if (buf == NULL) {
     227           0 :                     buf = (void**)uprv_malloc(cap * sizeof(void*));
     228             :                 } else {
     229           0 :                     buf = (void**)uprv_realloc(buf, cap * sizeof(void*));
     230             :                 }
     231           0 :                 if (buf == NULL) {
     232             :                     // if we couldn't realloc, we leak the memory we've already allocated, but we're in deep trouble anyway
     233           0 :                     status = U_MEMORY_ALLOCATION_ERROR;
     234           0 :                     return;
     235             :                 }
     236           0 :                 void* start = &buf[size];
     237           0 :                 size_t count = (cap - size) * sizeof(void*);
     238           0 :                 uprv_memset(start, 0, count); // fill with nulls, just because
     239             :             }
     240           0 :             buf[size++] = elem;
     241             :         }
     242             :     }
     243             :     
     244           0 :     void** release(void) {
     245           0 :         void** result = buf;
     246           0 :         buf = NULL;
     247           0 :         cap = 0;
     248           0 :         size = 0;
     249           0 :         return result;
     250             :     }
     251             : };
     252             : 
     253             : class LocDataParser;
     254             : 
     255             : class StringLocalizationInfo : public LocalizationInfo {
     256             :     UChar* info;
     257             :     UChar*** data;
     258             :     int32_t numRuleSets;
     259             :     int32_t numLocales;
     260             : 
     261             : friend class LocDataParser;
     262             : 
     263           0 :     StringLocalizationInfo(UChar* i, UChar*** d, int32_t numRS, int32_t numLocs)
     264           0 :         : info(i), data(d), numRuleSets(numRS), numLocales(numLocs)
     265             :     {
     266           0 :     }
     267             :     
     268             : public:
     269             :     static StringLocalizationInfo* create(const UnicodeString& info, UParseError& perror, UErrorCode& status);
     270             :     
     271             :     virtual ~StringLocalizationInfo();
     272           0 :     virtual int32_t getNumberOfRuleSets(void) const { return numRuleSets; }
     273             :     virtual const UChar* getRuleSetName(int32_t index) const;
     274           0 :     virtual int32_t getNumberOfDisplayLocales(void) const { return numLocales; }
     275             :     virtual const UChar* getLocaleName(int32_t index) const;
     276             :     virtual const UChar* getDisplayName(int32_t localeIndex, int32_t ruleIndex) const;
     277             :     
     278             : //    virtual UClassID getDynamicClassID() const;
     279             : //    static UClassID getStaticClassID(void);
     280             :     
     281             : private:
     282             :     void init(UErrorCode& status) const;
     283             : };
     284             : 
     285             : 
     286             : enum {
     287             :     OPEN_ANGLE = 0x003c, /* '<' */
     288             :     CLOSE_ANGLE = 0x003e, /* '>' */
     289             :     COMMA = 0x002c,
     290             :     TICK = 0x0027,
     291             :     QUOTE = 0x0022,
     292             :     SPACE = 0x0020
     293             : };
     294             : 
     295             : /**
     296             :  * Utility for parsing a localization string and returning a StringLocalizationInfo*.
     297             :  */
     298             : class LocDataParser {
     299             :     UChar* data;
     300             :     const UChar* e;
     301             :     UChar* p;
     302             :     UChar ch;
     303             :     UParseError& pe;
     304             :     UErrorCode& ec;
     305             :     
     306             : public:
     307           0 :     LocDataParser(UParseError& parseError, UErrorCode& status) 
     308           0 :         : data(NULL), e(NULL), p(NULL), ch(0xffff), pe(parseError), ec(status) {}
     309           0 :     ~LocDataParser() {}
     310             :     
     311             :     /*
     312             :     * On a successful parse, return a StringLocalizationInfo*, otherwise delete locData, set perror and status,
     313             :     * and return NULL.  The StringLocalizationInfo will adopt locData if it is created.
     314             :     */
     315             :     StringLocalizationInfo* parse(UChar* data, int32_t len);
     316             :     
     317             : private:
     318             :     
     319           0 :     void inc(void) { ++p; ch = 0xffff; }
     320           0 :     UBool checkInc(UChar c) { if (p < e && (ch == c || *p == c)) { inc(); return TRUE; } return FALSE; }
     321           0 :     UBool check(UChar c) { return p < e && (ch == c || *p == c); }
     322           0 :     void skipWhitespace(void) { while (p < e && PatternProps::isWhiteSpace(ch != 0xffff ? ch : *p)) inc();}
     323           0 :     UBool inList(UChar c, const UChar* list) const {
     324           0 :         if (*list == SPACE && PatternProps::isWhiteSpace(c)) return TRUE;
     325           0 :         while (*list && *list != c) ++list; return *list == c;
     326             :     }
     327             :     void parseError(const char* msg);
     328             :     
     329             :     StringLocalizationInfo* doParse(void);
     330             :         
     331             :     UChar** nextArray(int32_t& requiredLength);
     332             :     UChar*  nextString(void);
     333             : };
     334             : 
     335             : #ifdef RBNF_DEBUG
     336             : #define ERROR(msg) parseError(msg); return NULL;
     337             : #define EXPLANATION_ARG explanationArg
     338             : #else
     339             : #define ERROR(msg) parseError(NULL); return NULL;
     340             : #define EXPLANATION_ARG
     341             : #endif
     342             :         
     343             : 
     344             : static const UChar DQUOTE_STOPLIST[] = { 
     345             :     QUOTE, 0
     346             : };
     347             : 
     348             : static const UChar SQUOTE_STOPLIST[] = { 
     349             :     TICK, 0
     350             : };
     351             : 
     352             : static const UChar NOQUOTE_STOPLIST[] = { 
     353             :     SPACE, COMMA, CLOSE_ANGLE, OPEN_ANGLE, TICK, QUOTE, 0
     354             : };
     355             : 
     356             : static void
     357           0 : DeleteFn(void* p) {
     358           0 :   uprv_free(p);
     359           0 : }
     360             : 
     361             : StringLocalizationInfo*
     362           0 : LocDataParser::parse(UChar* _data, int32_t len) {
     363           0 :     if (U_FAILURE(ec)) {
     364           0 :         if (_data) uprv_free(_data);
     365           0 :         return NULL;
     366             :     }
     367             : 
     368           0 :     pe.line = 0;
     369           0 :     pe.offset = -1;
     370           0 :     pe.postContext[0] = 0;
     371           0 :     pe.preContext[0] = 0;
     372             : 
     373           0 :     if (_data == NULL) {
     374           0 :         ec = U_ILLEGAL_ARGUMENT_ERROR;
     375           0 :         return NULL;
     376             :     }
     377             : 
     378           0 :     if (len <= 0) {
     379           0 :         ec = U_ILLEGAL_ARGUMENT_ERROR;
     380           0 :         uprv_free(_data);
     381           0 :         return NULL;
     382             :     }
     383             : 
     384           0 :     data = _data;
     385           0 :     e = data + len;
     386           0 :     p = _data;
     387           0 :     ch = 0xffff;
     388             : 
     389           0 :     return doParse();
     390             : }
     391             : 
     392             : 
     393             : StringLocalizationInfo*
     394           0 : LocDataParser::doParse(void) {
     395           0 :     skipWhitespace();
     396           0 :     if (!checkInc(OPEN_ANGLE)) {
     397           0 :         ERROR("Missing open angle");
     398             :     } else {
     399           0 :         VArray array(DeleteFn);
     400           0 :         UBool mightHaveNext = TRUE;
     401           0 :         int32_t requiredLength = -1;
     402           0 :         while (mightHaveNext) {
     403           0 :             mightHaveNext = FALSE;
     404           0 :             UChar** elem = nextArray(requiredLength);
     405           0 :             skipWhitespace();
     406           0 :             UBool haveComma = check(COMMA);
     407           0 :             if (elem) {
     408           0 :                 array.add(elem, ec);
     409           0 :                 if (haveComma) {
     410           0 :                     inc();
     411           0 :                     mightHaveNext = TRUE;
     412             :                 }
     413           0 :             } else if (haveComma) {
     414           0 :                 ERROR("Unexpected character");
     415             :             }
     416             :         }
     417             : 
     418           0 :         skipWhitespace();
     419           0 :         if (!checkInc(CLOSE_ANGLE)) {
     420           0 :             if (check(OPEN_ANGLE)) {
     421           0 :                 ERROR("Missing comma in outer array");
     422             :             } else {
     423           0 :                 ERROR("Missing close angle bracket in outer array");
     424             :             }
     425             :         }
     426             : 
     427           0 :         skipWhitespace();
     428           0 :         if (p != e) {
     429           0 :             ERROR("Extra text after close of localization data");
     430             :         }
     431             : 
     432           0 :         array.add(NULL, ec);
     433           0 :         if (U_SUCCESS(ec)) {
     434           0 :             int32_t numLocs = array.length() - 2; // subtract first, NULL
     435           0 :             UChar*** result = (UChar***)array.release();
     436             :             
     437           0 :             return new StringLocalizationInfo(data, result, requiredLength-2, numLocs); // subtract first, NULL
     438             :         }
     439             :     }
     440             :   
     441           0 :     ERROR("Unknown error");
     442             : }
     443             : 
     444             : UChar**
     445           0 : LocDataParser::nextArray(int32_t& requiredLength) {
     446           0 :     if (U_FAILURE(ec)) {
     447           0 :         return NULL;
     448             :     }
     449             :     
     450           0 :     skipWhitespace();
     451           0 :     if (!checkInc(OPEN_ANGLE)) {
     452           0 :         ERROR("Missing open angle");
     453             :     }
     454             : 
     455           0 :     VArray array;
     456           0 :     UBool mightHaveNext = TRUE;
     457           0 :     while (mightHaveNext) {
     458           0 :         mightHaveNext = FALSE;
     459           0 :         UChar* elem = nextString();
     460           0 :         skipWhitespace();
     461           0 :         UBool haveComma = check(COMMA);
     462           0 :         if (elem) {
     463           0 :             array.add(elem, ec);
     464           0 :             if (haveComma) {
     465           0 :                 inc();
     466           0 :                 mightHaveNext = TRUE;
     467             :             }
     468           0 :         } else if (haveComma) {
     469           0 :             ERROR("Unexpected comma");
     470             :         }
     471             :     }
     472           0 :     skipWhitespace();
     473           0 :     if (!checkInc(CLOSE_ANGLE)) {
     474           0 :         if (check(OPEN_ANGLE)) {
     475           0 :             ERROR("Missing close angle bracket in inner array");
     476             :         } else {
     477           0 :             ERROR("Missing comma in inner array");
     478             :         }
     479             :     }
     480             : 
     481           0 :     array.add(NULL, ec);
     482           0 :     if (U_SUCCESS(ec)) {
     483           0 :         if (requiredLength == -1) {
     484           0 :             requiredLength = array.length() + 1;
     485           0 :         } else if (array.length() != requiredLength) {
     486           0 :             ec = U_ILLEGAL_ARGUMENT_ERROR;
     487           0 :             ERROR("Array not of required length");
     488             :         }
     489             :         
     490           0 :         return (UChar**)array.release();
     491             :     }
     492           0 :     ERROR("Unknown Error");
     493             : }
     494             : 
     495             : UChar*
     496           0 : LocDataParser::nextString() {
     497           0 :     UChar* result = NULL;
     498             :     
     499           0 :     skipWhitespace();
     500           0 :     if (p < e) {
     501             :         const UChar* terminators;
     502           0 :         UChar c = *p;
     503           0 :         UBool haveQuote = c == QUOTE || c == TICK;
     504           0 :         if (haveQuote) {
     505           0 :             inc();
     506           0 :             terminators = c == QUOTE ? DQUOTE_STOPLIST : SQUOTE_STOPLIST;
     507             :         } else {
     508           0 :             terminators = NOQUOTE_STOPLIST;
     509             :         }
     510           0 :         UChar* start = p;
     511           0 :         while (p < e && !inList(*p, terminators)) ++p;
     512           0 :         if (p == e) {
     513           0 :             ERROR("Unexpected end of data");
     514             :         }
     515             :         
     516           0 :         UChar x = *p;
     517           0 :         if (p > start) {
     518           0 :             ch = x;
     519           0 :             *p = 0x0; // terminate by writing to data
     520           0 :             result = start; // just point into data
     521             :         }
     522           0 :         if (haveQuote) {
     523           0 :             if (x != c) {
     524           0 :                 ERROR("Missing matching quote");
     525           0 :             } else if (p == start) {
     526           0 :                 ERROR("Empty string");
     527             :             }
     528           0 :             inc();
     529           0 :         } else if (x == OPEN_ANGLE || x == TICK || x == QUOTE) {
     530           0 :             ERROR("Unexpected character in string");
     531             :         }
     532             :     }
     533             : 
     534             :     // ok for there to be no next string
     535           0 :     return result;
     536             : }
     537             : 
     538           0 : void LocDataParser::parseError(const char* EXPLANATION_ARG)
     539             : {
     540           0 :     if (!data) {
     541           0 :         return;
     542             :     }
     543             : 
     544           0 :     const UChar* start = p - U_PARSE_CONTEXT_LEN - 1;
     545           0 :     if (start < data) {
     546           0 :         start = data;
     547             :     }
     548           0 :     for (UChar* x = p; --x >= start;) {
     549           0 :         if (!*x) {
     550           0 :             start = x+1;
     551           0 :             break;
     552             :         }
     553             :     }
     554           0 :     const UChar* limit = p + U_PARSE_CONTEXT_LEN - 1;
     555           0 :     if (limit > e) {
     556           0 :         limit = e;
     557             :     }
     558           0 :     u_strncpy(pe.preContext, start, (int32_t)(p-start));
     559           0 :     pe.preContext[p-start] = 0;
     560           0 :     u_strncpy(pe.postContext, p, (int32_t)(limit-p));
     561           0 :     pe.postContext[limit-p] = 0;
     562           0 :     pe.offset = (int32_t)(p - data);
     563             :     
     564             : #ifdef RBNF_DEBUG
     565             :     fprintf(stderr, "%s at or near character %ld: ", EXPLANATION_ARG, p-data);
     566             : 
     567             :     UnicodeString msg;
     568             :     msg.append(start, p - start);
     569             :     msg.append((UChar)0x002f); /* SOLIDUS/SLASH */
     570             :     msg.append(p, limit-p);
     571             :     msg.append(UNICODE_STRING_SIMPLE("'"));
     572             :     
     573             :     char buf[128];
     574             :     int32_t len = msg.extract(0, msg.length(), buf, 128);
     575             :     if (len >= 128) {
     576             :         buf[127] = 0;
     577             :     } else {
     578             :         buf[len] = 0;
     579             :     }
     580             :     fprintf(stderr, "%s\n", buf);
     581             :     fflush(stderr);
     582             : #endif
     583             :     
     584           0 :     uprv_free(data);
     585           0 :     data = NULL;
     586           0 :     p = NULL;
     587           0 :     e = NULL;
     588             :     
     589           0 :     if (U_SUCCESS(ec)) {
     590           0 :         ec = U_PARSE_ERROR;
     591             :     }
     592             : }
     593             : 
     594             : //UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringLocalizationInfo)
     595             : 
     596             : StringLocalizationInfo* 
     597           0 : StringLocalizationInfo::create(const UnicodeString& info, UParseError& perror, UErrorCode& status) {
     598           0 :     if (U_FAILURE(status)) {
     599           0 :         return NULL;
     600             :     }
     601             :     
     602           0 :     int32_t len = info.length();
     603           0 :     if (len == 0) {
     604           0 :         return NULL; // no error;
     605             :     }
     606             :     
     607           0 :     UChar* p = (UChar*)uprv_malloc(len * sizeof(UChar));
     608           0 :     if (!p) {
     609           0 :         status = U_MEMORY_ALLOCATION_ERROR;
     610           0 :         return NULL;
     611             :     }
     612           0 :     info.extract(p, len, status);
     613           0 :     if (!U_FAILURE(status)) {
     614           0 :         status = U_ZERO_ERROR; // clear warning about non-termination
     615             :     }
     616             :     
     617           0 :     LocDataParser parser(perror, status);
     618           0 :     return parser.parse(p, len);
     619             : }
     620             : 
     621           0 : StringLocalizationInfo::~StringLocalizationInfo() {
     622           0 :     for (UChar*** p = (UChar***)data; *p; ++p) {
     623             :         // remaining data is simply pointer into our unicode string data.
     624           0 :         if (*p) uprv_free(*p);
     625             :     }
     626           0 :     if (data) uprv_free(data);
     627           0 :     if (info) uprv_free(info);
     628           0 : }
     629             : 
     630             : 
     631             : const UChar*
     632           0 : StringLocalizationInfo::getRuleSetName(int32_t index) const {
     633           0 :     if (index >= 0 && index < getNumberOfRuleSets()) {
     634           0 :         return data[0][index];
     635             :     }
     636           0 :     return NULL;
     637             : }
     638             : 
     639             : const UChar*
     640           0 : StringLocalizationInfo::getLocaleName(int32_t index) const {
     641           0 :     if (index >= 0 && index < getNumberOfDisplayLocales()) {
     642           0 :         return data[index+1][0];
     643             :     }
     644           0 :     return NULL;
     645             : }
     646             : 
     647             : const UChar*
     648           0 : StringLocalizationInfo::getDisplayName(int32_t localeIndex, int32_t ruleIndex) const {
     649           0 :     if (localeIndex >= 0 && localeIndex < getNumberOfDisplayLocales() &&
     650           0 :         ruleIndex >= 0 && ruleIndex < getNumberOfRuleSets()) {
     651           0 :         return data[localeIndex+1][ruleIndex+1];
     652             :     }
     653           0 :     return NULL;
     654             : }
     655             : 
     656             : // ----------
     657             : 
     658           0 : RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, 
     659             :                                              const UnicodeString& locs,
     660           0 :                                              const Locale& alocale, UParseError& perror, UErrorCode& status)
     661             :   : ruleSets(NULL)
     662             :   , ruleSetDescriptions(NULL)
     663             :   , numRuleSets(0)
     664             :   , defaultRuleSet(NULL)
     665             :   , locale(alocale)
     666             :   , collator(NULL)
     667             :   , decimalFormatSymbols(NULL)
     668             :   , defaultInfinityRule(NULL)
     669             :   , defaultNaNRule(NULL)
     670             :   , lenient(FALSE)
     671             :   , lenientParseRules(NULL)
     672             :   , localizations(NULL)
     673             :   , capitalizationInfoSet(FALSE)
     674             :   , capitalizationForUIListMenu(FALSE)
     675             :   , capitalizationForStandAlone(FALSE)
     676           0 :   , capitalizationBrkIter(NULL)
     677             : {
     678           0 :   LocalizationInfo* locinfo = StringLocalizationInfo::create(locs, perror, status);
     679           0 :   init(description, locinfo, perror, status);
     680           0 : }
     681             : 
     682           0 : RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, 
     683             :                                              const UnicodeString& locs,
     684           0 :                                              UParseError& perror, UErrorCode& status)
     685             :   : ruleSets(NULL)
     686             :   , ruleSetDescriptions(NULL)
     687             :   , numRuleSets(0)
     688             :   , defaultRuleSet(NULL)
     689             :   , locale(Locale::getDefault())
     690             :   , collator(NULL)
     691             :   , decimalFormatSymbols(NULL)
     692             :   , defaultInfinityRule(NULL)
     693             :   , defaultNaNRule(NULL)
     694             :   , lenient(FALSE)
     695             :   , lenientParseRules(NULL)
     696             :   , localizations(NULL)
     697             :   , capitalizationInfoSet(FALSE)
     698             :   , capitalizationForUIListMenu(FALSE)
     699             :   , capitalizationForStandAlone(FALSE)
     700           0 :   , capitalizationBrkIter(NULL)
     701             : {
     702           0 :   LocalizationInfo* locinfo = StringLocalizationInfo::create(locs, perror, status);
     703           0 :   init(description, locinfo, perror, status);
     704           0 : }
     705             : 
     706           0 : RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, 
     707             :                                              LocalizationInfo* info,
     708           0 :                                              const Locale& alocale, UParseError& perror, UErrorCode& status)
     709             :   : ruleSets(NULL)
     710             :   , ruleSetDescriptions(NULL)
     711             :   , numRuleSets(0)
     712             :   , defaultRuleSet(NULL)
     713             :   , locale(alocale)
     714             :   , collator(NULL)
     715             :   , decimalFormatSymbols(NULL)
     716             :   , defaultInfinityRule(NULL)
     717             :   , defaultNaNRule(NULL)
     718             :   , lenient(FALSE)
     719             :   , lenientParseRules(NULL)
     720             :   , localizations(NULL)
     721             :   , capitalizationInfoSet(FALSE)
     722             :   , capitalizationForUIListMenu(FALSE)
     723             :   , capitalizationForStandAlone(FALSE)
     724           0 :   , capitalizationBrkIter(NULL)
     725             : {
     726           0 :   init(description, info, perror, status);
     727           0 : }
     728             : 
     729           0 : RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, 
     730             :                          UParseError& perror, 
     731           0 :                          UErrorCode& status) 
     732             :   : ruleSets(NULL)
     733             :   , ruleSetDescriptions(NULL)
     734             :   , numRuleSets(0)
     735             :   , defaultRuleSet(NULL)
     736             :   , locale(Locale::getDefault())
     737             :   , collator(NULL)
     738             :   , decimalFormatSymbols(NULL)
     739             :   , defaultInfinityRule(NULL)
     740             :   , defaultNaNRule(NULL)
     741             :   , lenient(FALSE)
     742             :   , lenientParseRules(NULL)
     743             :   , localizations(NULL)
     744             :   , capitalizationInfoSet(FALSE)
     745             :   , capitalizationForUIListMenu(FALSE)
     746             :   , capitalizationForStandAlone(FALSE)
     747           0 :   , capitalizationBrkIter(NULL)
     748             : {
     749           0 :     init(description, NULL, perror, status);
     750           0 : }
     751             : 
     752           0 : RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, 
     753             :                          const Locale& aLocale,
     754             :                          UParseError& perror, 
     755           0 :                          UErrorCode& status) 
     756             :   : ruleSets(NULL)
     757             :   , ruleSetDescriptions(NULL)
     758             :   , numRuleSets(0)
     759             :   , defaultRuleSet(NULL)
     760             :   , locale(aLocale)
     761             :   , collator(NULL)
     762             :   , decimalFormatSymbols(NULL)
     763             :   , defaultInfinityRule(NULL)
     764             :   , defaultNaNRule(NULL)
     765             :   , lenient(FALSE)
     766             :   , lenientParseRules(NULL)
     767             :   , localizations(NULL)
     768             :   , capitalizationInfoSet(FALSE)
     769             :   , capitalizationForUIListMenu(FALSE)
     770             :   , capitalizationForStandAlone(FALSE)
     771           0 :   , capitalizationBrkIter(NULL)
     772             : {
     773           0 :     init(description, NULL, perror, status);
     774           0 : }
     775             : 
     776           0 : RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& alocale, UErrorCode& status)
     777             :   : ruleSets(NULL)
     778             :   , ruleSetDescriptions(NULL)
     779             :   , numRuleSets(0)
     780             :   , defaultRuleSet(NULL)
     781             :   , locale(alocale)
     782             :   , collator(NULL)
     783             :   , decimalFormatSymbols(NULL)
     784             :   , defaultInfinityRule(NULL)
     785             :   , defaultNaNRule(NULL)
     786             :   , lenient(FALSE)
     787             :   , lenientParseRules(NULL)
     788             :   , localizations(NULL)
     789             :   , capitalizationInfoSet(FALSE)
     790             :   , capitalizationForUIListMenu(FALSE)
     791             :   , capitalizationForStandAlone(FALSE)
     792           0 :   , capitalizationBrkIter(NULL)
     793             : {
     794           0 :     if (U_FAILURE(status)) {
     795           0 :         return;
     796             :     }
     797             : 
     798           0 :     const char* rules_tag = "RBNFRules";
     799           0 :     const char* fmt_tag = "";
     800           0 :     switch (tag) {
     801           0 :     case URBNF_SPELLOUT: fmt_tag = "SpelloutRules"; break;
     802           0 :     case URBNF_ORDINAL: fmt_tag = "OrdinalRules"; break;
     803           0 :     case URBNF_DURATION: fmt_tag = "DurationRules"; break;
     804           0 :     case URBNF_NUMBERING_SYSTEM: fmt_tag = "NumberingSystemRules"; break;
     805           0 :     default: status = U_ILLEGAL_ARGUMENT_ERROR; return;
     806             :     }
     807             : 
     808             :     // TODO: read localization info from resource
     809           0 :     LocalizationInfo* locinfo = NULL;
     810             : 
     811           0 :     UResourceBundle* nfrb = ures_open(U_ICUDATA_RBNF, locale.getName(), &status);
     812           0 :     if (U_SUCCESS(status)) {
     813           0 :         setLocaleIDs(ures_getLocaleByType(nfrb, ULOC_VALID_LOCALE, &status),
     814           0 :                      ures_getLocaleByType(nfrb, ULOC_ACTUAL_LOCALE, &status));
     815             : 
     816           0 :         UResourceBundle* rbnfRules = ures_getByKeyWithFallback(nfrb, rules_tag, NULL, &status);
     817           0 :         if (U_FAILURE(status)) {
     818           0 :             ures_close(nfrb);
     819             :         }
     820           0 :         UResourceBundle* ruleSets = ures_getByKeyWithFallback(rbnfRules, fmt_tag, NULL, &status);
     821           0 :         if (U_FAILURE(status)) {
     822           0 :             ures_close(rbnfRules);
     823           0 :             ures_close(nfrb);
     824           0 :             return;
     825             :         }
     826             : 
     827           0 :         UnicodeString desc;
     828           0 :         while (ures_hasNext(ruleSets)) {
     829           0 :            desc.append(ures_getNextUnicodeString(ruleSets,NULL,&status));
     830             :         }
     831             :         UParseError perror;
     832             : 
     833           0 :         init(desc, locinfo, perror, status);
     834             : 
     835           0 :         ures_close(ruleSets);
     836           0 :         ures_close(rbnfRules);
     837             :     }
     838           0 :     ures_close(nfrb);
     839             : }
     840             : 
     841           0 : RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs)
     842             :   : NumberFormat(rhs)
     843             :   , ruleSets(NULL)
     844             :   , ruleSetDescriptions(NULL)
     845             :   , numRuleSets(0)
     846             :   , defaultRuleSet(NULL)
     847             :   , locale(rhs.locale)
     848             :   , collator(NULL)
     849             :   , decimalFormatSymbols(NULL)
     850             :   , defaultInfinityRule(NULL)
     851             :   , defaultNaNRule(NULL)
     852             :   , lenient(FALSE)
     853             :   , lenientParseRules(NULL)
     854             :   , localizations(NULL)
     855             :   , capitalizationInfoSet(FALSE)
     856             :   , capitalizationForUIListMenu(FALSE)
     857             :   , capitalizationForStandAlone(FALSE)
     858           0 :   , capitalizationBrkIter(NULL)
     859             : {
     860           0 :     this->operator=(rhs);
     861           0 : }
     862             : 
     863             : // --------
     864             : 
     865             : RuleBasedNumberFormat&
     866           0 : RuleBasedNumberFormat::operator=(const RuleBasedNumberFormat& rhs)
     867             : {
     868           0 :     if (this == &rhs) {
     869           0 :         return *this;
     870             :     }
     871           0 :     NumberFormat::operator=(rhs);
     872           0 :     UErrorCode status = U_ZERO_ERROR;
     873           0 :     dispose();
     874           0 :     locale = rhs.locale;
     875           0 :     lenient = rhs.lenient;
     876             : 
     877             :     UParseError perror;
     878           0 :     setDecimalFormatSymbols(*rhs.getDecimalFormatSymbols());
     879           0 :     init(rhs.originalDescription, rhs.localizations ? rhs.localizations->ref() : NULL, perror, status);
     880           0 :     setDefaultRuleSet(rhs.getDefaultRuleSetName(), status);
     881             : 
     882           0 :     capitalizationInfoSet = rhs.capitalizationInfoSet;
     883           0 :     capitalizationForUIListMenu = rhs.capitalizationForUIListMenu;
     884           0 :     capitalizationForStandAlone = rhs.capitalizationForStandAlone;
     885             : #if !UCONFIG_NO_BREAK_ITERATION
     886             :     capitalizationBrkIter = (rhs.capitalizationBrkIter!=NULL)? rhs.capitalizationBrkIter->clone(): NULL;
     887             : #endif
     888             : 
     889           0 :     return *this;
     890             : }
     891             : 
     892           0 : RuleBasedNumberFormat::~RuleBasedNumberFormat()
     893             : {
     894           0 :     dispose();
     895           0 : }
     896             : 
     897             : Format*
     898           0 : RuleBasedNumberFormat::clone(void) const
     899             : {
     900           0 :     return new RuleBasedNumberFormat(*this);
     901             : }
     902             : 
     903             : UBool
     904           0 : RuleBasedNumberFormat::operator==(const Format& other) const
     905             : {
     906           0 :     if (this == &other) {
     907           0 :         return TRUE;
     908             :     }
     909             : 
     910           0 :     if (typeid(*this) == typeid(other)) {
     911           0 :         const RuleBasedNumberFormat& rhs = (const RuleBasedNumberFormat&)other;
     912             :         // test for capitalization info equality is adequately handled
     913             :         // by the NumberFormat test for fCapitalizationContext equality;
     914             :         // the info here is just derived from that.
     915           0 :         if (locale == rhs.locale &&
     916           0 :             lenient == rhs.lenient &&
     917           0 :             (localizations == NULL 
     918           0 :                 ? rhs.localizations == NULL 
     919           0 :                 : (rhs.localizations == NULL 
     920             :                     ? FALSE
     921           0 :                     : *localizations == rhs.localizations))) {
     922             : 
     923           0 :             NFRuleSet** p = ruleSets;
     924           0 :             NFRuleSet** q = rhs.ruleSets;
     925           0 :             if (p == NULL) {
     926           0 :                 return q == NULL;
     927           0 :             } else if (q == NULL) {
     928           0 :                 return FALSE;
     929             :             }
     930           0 :             while (*p && *q && (**p == **q)) {
     931           0 :                 ++p;
     932           0 :                 ++q;
     933             :             }
     934           0 :             return *q == NULL && *p == NULL;
     935             :         }
     936             :     }
     937             : 
     938           0 :     return FALSE;
     939             : }
     940             : 
     941             : UnicodeString
     942           0 : RuleBasedNumberFormat::getRules() const
     943             : {
     944           0 :     UnicodeString result;
     945           0 :     if (ruleSets != NULL) {
     946           0 :         for (NFRuleSet** p = ruleSets; *p; ++p) {
     947           0 :             (*p)->appendRules(result);
     948             :         }
     949             :     }
     950           0 :     return result;
     951             : }
     952             : 
     953             : UnicodeString
     954           0 : RuleBasedNumberFormat::getRuleSetName(int32_t index) const
     955             : {
     956           0 :     if (localizations) {
     957           0 :         UnicodeString string(TRUE, localizations->getRuleSetName(index), (int32_t)-1);
     958           0 :         return string;
     959             :     }
     960           0 :     else if (ruleSets) {
     961           0 :         UnicodeString result;
     962           0 :         for (NFRuleSet** p = ruleSets; *p; ++p) {
     963           0 :             NFRuleSet* rs = *p;
     964           0 :             if (rs->isPublic()) {
     965           0 :                 if (--index == -1) {
     966           0 :                     rs->getName(result);
     967           0 :                     return result;
     968             :                 }
     969             :             }
     970             :         }
     971             :     }
     972           0 :     UnicodeString empty;
     973           0 :     return empty;
     974             : }
     975             : 
     976             : int32_t
     977           0 : RuleBasedNumberFormat::getNumberOfRuleSetNames() const
     978             : {
     979           0 :     int32_t result = 0;
     980           0 :     if (localizations) {
     981           0 :         result = localizations->getNumberOfRuleSets();
     982             :     }
     983           0 :     else if (ruleSets) {
     984           0 :         for (NFRuleSet** p = ruleSets; *p; ++p) {
     985           0 :             if ((**p).isPublic()) {
     986           0 :                 ++result;
     987             :             }
     988             :         }
     989             :     }
     990           0 :     return result;
     991             : }
     992             : 
     993             : int32_t 
     994           0 : RuleBasedNumberFormat::getNumberOfRuleSetDisplayNameLocales(void) const {
     995           0 :     if (localizations) {
     996           0 :         return localizations->getNumberOfDisplayLocales();
     997             :     }
     998           0 :     return 0;
     999             : }
    1000             : 
    1001             : Locale 
    1002           0 : RuleBasedNumberFormat::getRuleSetDisplayNameLocale(int32_t index, UErrorCode& status) const {
    1003           0 :     if (U_FAILURE(status)) {
    1004           0 :         return Locale("");
    1005             :     }
    1006           0 :     if (localizations && index >= 0 && index < localizations->getNumberOfDisplayLocales()) {
    1007           0 :         UnicodeString name(TRUE, localizations->getLocaleName(index), -1);
    1008             :         char buffer[64];
    1009           0 :         int32_t cap = name.length() + 1;
    1010           0 :         char* bp = buffer;
    1011           0 :         if (cap > 64) {
    1012           0 :             bp = (char *)uprv_malloc(cap);
    1013           0 :             if (bp == NULL) {
    1014           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
    1015           0 :                 return Locale("");
    1016             :             }
    1017             :         }
    1018           0 :         name.extract(0, name.length(), bp, cap, UnicodeString::kInvariant);
    1019           0 :         Locale retLocale(bp);
    1020           0 :         if (bp != buffer) {
    1021           0 :             uprv_free(bp);
    1022             :         }
    1023           0 :         return retLocale;
    1024             :     }
    1025           0 :     status = U_ILLEGAL_ARGUMENT_ERROR;
    1026           0 :     Locale retLocale;
    1027           0 :     return retLocale;
    1028             : }
    1029             : 
    1030             : UnicodeString 
    1031           0 : RuleBasedNumberFormat::getRuleSetDisplayName(int32_t index, const Locale& localeParam) {
    1032           0 :     if (localizations && index >= 0 && index < localizations->getNumberOfRuleSets()) {
    1033           0 :         UnicodeString localeName(localeParam.getBaseName(), -1, UnicodeString::kInvariant); 
    1034           0 :         int32_t len = localeName.length();
    1035           0 :         UChar* localeStr = localeName.getBuffer(len + 1);
    1036           0 :         while (len >= 0) {
    1037           0 :             localeStr[len] = 0;
    1038           0 :             int32_t ix = localizations->indexForLocale(localeStr);
    1039           0 :             if (ix >= 0) {
    1040           0 :                 UnicodeString name(TRUE, localizations->getDisplayName(ix, index), -1);
    1041           0 :                 return name;
    1042             :             }
    1043             :             
    1044             :             // trim trailing portion, skipping over ommitted sections
    1045           0 :             do { --len;} while (len > 0 && localeStr[len] != 0x005f); // underscore
    1046           0 :             while (len > 0 && localeStr[len-1] == 0x005F) --len;
    1047             :         }
    1048           0 :         UnicodeString name(TRUE, localizations->getRuleSetName(index), -1);
    1049           0 :         return name;
    1050             :     }
    1051           0 :     UnicodeString bogus;
    1052           0 :     bogus.setToBogus();
    1053           0 :     return bogus;
    1054             : }
    1055             : 
    1056             : UnicodeString 
    1057           0 : RuleBasedNumberFormat::getRuleSetDisplayName(const UnicodeString& ruleSetName, const Locale& localeParam) {
    1058           0 :     if (localizations) {
    1059           0 :         UnicodeString rsn(ruleSetName);
    1060           0 :         int32_t ix = localizations->indexForRuleSet(rsn.getTerminatedBuffer());
    1061           0 :         return getRuleSetDisplayName(ix, localeParam);
    1062             :     }
    1063           0 :     UnicodeString bogus;
    1064           0 :     bogus.setToBogus();
    1065           0 :     return bogus;
    1066             : }
    1067             : 
    1068             : NFRuleSet*
    1069           0 : RuleBasedNumberFormat::findRuleSet(const UnicodeString& name, UErrorCode& status) const
    1070             : {
    1071           0 :     if (U_SUCCESS(status) && ruleSets) {
    1072           0 :         for (NFRuleSet** p = ruleSets; *p; ++p) {
    1073           0 :             NFRuleSet* rs = *p;
    1074           0 :             if (rs->isNamed(name)) {
    1075           0 :                 return rs;
    1076             :             }
    1077             :         }
    1078           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
    1079             :     }
    1080           0 :     return NULL;
    1081             : }
    1082             : 
    1083             : UnicodeString&
    1084           0 : RuleBasedNumberFormat::format(const DigitList &number,
    1085             :                       UnicodeString &appendTo,
    1086             :                       FieldPositionIterator *posIter,
    1087             :                       UErrorCode &status) const {
    1088           0 :     if (U_FAILURE(status)) {
    1089           0 :         return appendTo;
    1090             :     }
    1091           0 :     DigitList copy(number);
    1092           0 :     if (copy.fitsIntoInt64(false)) {
    1093           0 :         format(((DigitList &)number).getInt64(), appendTo, posIter, status);
    1094             :     }
    1095             :     else {
    1096           0 :         copy.roundAtExponent(0);
    1097           0 :         if (copy.fitsIntoInt64(false)) {
    1098           0 :             format(number.getDouble(), appendTo, posIter, status);
    1099             :         }
    1100             :         else {
    1101             :             // We're outside of our normal range that this framework can handle.
    1102             :             // The DecimalFormat will provide more accurate results.
    1103             : 
    1104             :             // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
    1105           0 :             NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status);
    1106           0 :             Formattable f;
    1107           0 :             f.adoptDigitList(new DigitList(number));
    1108           0 :             decimalFormat->format(f, appendTo, posIter, status);
    1109           0 :             delete decimalFormat;
    1110             :         }
    1111             :     }
    1112           0 :     return appendTo;
    1113             : }
    1114             : 
    1115             : 
    1116             : UnicodeString&
    1117           0 : RuleBasedNumberFormat::format(const DigitList &number,
    1118             :                      UnicodeString& appendTo,
    1119             :                      FieldPosition& pos,
    1120             :                      UErrorCode &status) const {
    1121           0 :     if (U_FAILURE(status)) {
    1122           0 :         return appendTo;
    1123             :     }
    1124           0 :     DigitList copy(number);
    1125           0 :     if (copy.fitsIntoInt64(false)) {
    1126           0 :         format(((DigitList &)number).getInt64(), appendTo, pos, status);
    1127             :     }
    1128             :     else {
    1129           0 :         copy.roundAtExponent(0);
    1130           0 :         if (copy.fitsIntoInt64(false)) {
    1131           0 :             format(number.getDouble(), appendTo, pos, status);
    1132             :         }
    1133             :         else {
    1134             :             // We're outside of our normal range that this framework can handle.
    1135             :             // The DecimalFormat will provide more accurate results.
    1136             : 
    1137             :             // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
    1138           0 :             NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status);
    1139           0 :             Formattable f;
    1140           0 :             f.adoptDigitList(new DigitList(number));
    1141           0 :             decimalFormat->format(f, appendTo, pos, status);
    1142           0 :             delete decimalFormat;
    1143             :         }
    1144             :     }
    1145           0 :     return appendTo;
    1146             : }
    1147             : 
    1148             : UnicodeString&
    1149           0 : RuleBasedNumberFormat::format(int32_t number,
    1150             :                               UnicodeString& toAppendTo,
    1151             :                               FieldPosition& pos) const
    1152             : {
    1153           0 :     return format((int64_t)number, toAppendTo, pos);
    1154             : }
    1155             : 
    1156             : 
    1157             : UnicodeString&
    1158           0 : RuleBasedNumberFormat::format(int64_t number,
    1159             :                               UnicodeString& toAppendTo,
    1160             :                               FieldPosition& /* pos */) const
    1161             : {
    1162           0 :     if (defaultRuleSet) {
    1163           0 :         UErrorCode status = U_ZERO_ERROR;
    1164           0 :         format(number, defaultRuleSet, toAppendTo, status);
    1165             :     }
    1166           0 :     return toAppendTo;
    1167             : }
    1168             : 
    1169             : 
    1170             : UnicodeString&
    1171           0 : RuleBasedNumberFormat::format(double number,
    1172             :                               UnicodeString& toAppendTo,
    1173             :                               FieldPosition& /* pos */) const
    1174             : {
    1175           0 :     int32_t startPos = toAppendTo.length();
    1176           0 :     UErrorCode status = U_ZERO_ERROR;
    1177           0 :     if (defaultRuleSet) {
    1178           0 :         defaultRuleSet->format(number, toAppendTo, toAppendTo.length(), 0, status);
    1179             :     }
    1180           0 :     return adjustForCapitalizationContext(startPos, toAppendTo, status);
    1181             : }
    1182             : 
    1183             : 
    1184             : UnicodeString&
    1185           0 : RuleBasedNumberFormat::format(int32_t number,
    1186             :                               const UnicodeString& ruleSetName,
    1187             :                               UnicodeString& toAppendTo,
    1188             :                               FieldPosition& pos,
    1189             :                               UErrorCode& status) const
    1190             : {
    1191           0 :     return format((int64_t)number, ruleSetName, toAppendTo, pos, status);
    1192             : }
    1193             : 
    1194             : 
    1195             : UnicodeString&
    1196           0 : RuleBasedNumberFormat::format(int64_t number,
    1197             :                               const UnicodeString& ruleSetName,
    1198             :                               UnicodeString& toAppendTo,
    1199             :                               FieldPosition& /* pos */,
    1200             :                               UErrorCode& status) const
    1201             : {
    1202           0 :     if (U_SUCCESS(status)) {
    1203           0 :         if (ruleSetName.indexOf(gPercentPercent, 2, 0) == 0) {
    1204             :             // throw new IllegalArgumentException("Can't use internal rule set");
    1205           0 :             status = U_ILLEGAL_ARGUMENT_ERROR;
    1206             :         } else {
    1207           0 :             NFRuleSet *rs = findRuleSet(ruleSetName, status);
    1208           0 :             if (rs) {
    1209           0 :                 format(number, rs, toAppendTo, status);
    1210             :             }
    1211             :         }
    1212             :     }
    1213           0 :     return toAppendTo;
    1214             : }
    1215             : 
    1216             : 
    1217             : UnicodeString&
    1218           0 : RuleBasedNumberFormat::format(double number,
    1219             :                               const UnicodeString& ruleSetName,
    1220             :                               UnicodeString& toAppendTo,
    1221             :                               FieldPosition& /* pos */,
    1222             :                               UErrorCode& status) const
    1223             : {
    1224           0 :     if (U_SUCCESS(status)) {
    1225           0 :         if (ruleSetName.indexOf(gPercentPercent, 2, 0) == 0) {
    1226             :             // throw new IllegalArgumentException("Can't use internal rule set");
    1227           0 :             status = U_ILLEGAL_ARGUMENT_ERROR;
    1228             :         } else {
    1229           0 :             NFRuleSet *rs = findRuleSet(ruleSetName, status);
    1230           0 :             if (rs) {
    1231           0 :                 int32_t startPos = toAppendTo.length();
    1232           0 :                 rs->format(number, toAppendTo, toAppendTo.length(), 0, status);
    1233           0 :                 adjustForCapitalizationContext(startPos, toAppendTo, status);
    1234             :             }
    1235             :         }
    1236             :     }
    1237           0 :     return toAppendTo;
    1238             : }
    1239             : 
    1240             : /**
    1241             :  * Bottleneck through which all the public format() methods
    1242             :  * that take a long pass. By the time we get here, we know
    1243             :  * which rule set we're using to do the formatting.
    1244             :  * @param number The number to format
    1245             :  * @param ruleSet The rule set to use to format the number
    1246             :  * @return The text that resulted from formatting the number
    1247             :  */
    1248             : UnicodeString&
    1249           0 : RuleBasedNumberFormat::format(int64_t number, NFRuleSet *ruleSet, UnicodeString& toAppendTo, UErrorCode& status) const
    1250             : {
    1251             :     // all API format() routines that take a double vector through
    1252             :     // here.  We have these two identical functions-- one taking a
    1253             :     // double and one taking a long-- the couple digits of precision
    1254             :     // that long has but double doesn't (both types are 8 bytes long,
    1255             :     // but double has to borrow some of the mantissa bits to hold
    1256             :     // the exponent).
    1257             :     // Create an empty string buffer where the result will
    1258             :     // be built, and pass it to the rule set (along with an insertion
    1259             :     // position of 0 and the number being formatted) to the rule set
    1260             :     // for formatting
    1261             : 
    1262           0 :     if (U_SUCCESS(status)) {
    1263           0 :         if (number == U_INT64_MIN) {
    1264             :             // We can't handle this value right now. Provide an accurate default value.
    1265             : 
    1266             :             // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
    1267           0 :             NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status);
    1268           0 :             Formattable f;
    1269           0 :             FieldPosition pos(FieldPosition::DONT_CARE);
    1270           0 :             DigitList *digitList = new DigitList();
    1271           0 :             digitList->set(number);
    1272           0 :             f.adoptDigitList(digitList);
    1273           0 :             decimalFormat->format(f, toAppendTo, pos, status);
    1274           0 :             delete decimalFormat;
    1275             :         }
    1276             :         else {
    1277           0 :             int32_t startPos = toAppendTo.length();
    1278           0 :             ruleSet->format(number, toAppendTo, toAppendTo.length(), 0, status);
    1279           0 :             adjustForCapitalizationContext(startPos, toAppendTo, status);
    1280             :         }
    1281             :     }
    1282           0 :     return toAppendTo;
    1283             : }
    1284             : 
    1285             : UnicodeString&
    1286           0 : RuleBasedNumberFormat::adjustForCapitalizationContext(int32_t startPos,
    1287             :                                                       UnicodeString& currentResult,
    1288             :                                                       UErrorCode& status) const
    1289             : {
    1290             : #if !UCONFIG_NO_BREAK_ITERATION
    1291             :     UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
    1292             :     if (capitalizationContext != UDISPCTX_CAPITALIZATION_NONE && startPos == 0 && currentResult.length() > 0) {
    1293             :         // capitalize currentResult according to context
    1294             :         UChar32 ch = currentResult.char32At(0);
    1295             :         if (u_islower(ch) && U_SUCCESS(status) && capitalizationBrkIter != NULL &&
    1296             :               ( capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
    1297             :                 (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
    1298             :                 (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
    1299             :             // titlecase first word of currentResult, here use sentence iterator unlike current implementations
    1300             :             // in LocaleDisplayNamesImpl::adjustForUsageAndContext and RelativeDateFormat::format
    1301             :             currentResult.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
    1302             :         }
    1303             :     }
    1304             : #endif
    1305           0 :     return currentResult;
    1306             : }
    1307             : 
    1308             : 
    1309             : void
    1310           0 : RuleBasedNumberFormat::parse(const UnicodeString& text,
    1311             :                              Formattable& result,
    1312             :                              ParsePosition& parsePosition) const
    1313             : {
    1314           0 :     if (!ruleSets) {
    1315           0 :         parsePosition.setErrorIndex(0);
    1316           0 :         return;
    1317             :     }
    1318             : 
    1319           0 :     UnicodeString workingText(text, parsePosition.getIndex());
    1320           0 :     ParsePosition workingPos(0);
    1321             : 
    1322           0 :     ParsePosition high_pp(0);
    1323           0 :     Formattable high_result;
    1324             : 
    1325           0 :     for (NFRuleSet** p = ruleSets; *p; ++p) {
    1326           0 :         NFRuleSet *rp = *p;
    1327           0 :         if (rp->isPublic() && rp->isParseable()) {
    1328           0 :             ParsePosition working_pp(0);
    1329           0 :             Formattable working_result;
    1330             : 
    1331           0 :             rp->parse(workingText, working_pp, kMaxDouble, working_result);
    1332           0 :             if (working_pp.getIndex() > high_pp.getIndex()) {
    1333           0 :                 high_pp = working_pp;
    1334           0 :                 high_result = working_result;
    1335             : 
    1336           0 :                 if (high_pp.getIndex() == workingText.length()) {
    1337           0 :                     break;
    1338             :                 }
    1339             :             }
    1340             :         }
    1341             :     }
    1342             : 
    1343           0 :     int32_t startIndex = parsePosition.getIndex();
    1344           0 :     parsePosition.setIndex(startIndex + high_pp.getIndex());
    1345           0 :     if (high_pp.getIndex() > 0) {
    1346           0 :         parsePosition.setErrorIndex(-1);
    1347             :     } else {
    1348           0 :         int32_t errorIndex = (high_pp.getErrorIndex()>0)? high_pp.getErrorIndex(): 0;
    1349           0 :         parsePosition.setErrorIndex(startIndex + errorIndex);
    1350             :     }
    1351           0 :     result = high_result;
    1352           0 :     if (result.getType() == Formattable::kDouble) {
    1353           0 :         double d = result.getDouble();
    1354           0 :         if (!uprv_isNaN(d) && d == uprv_trunc(d) && INT32_MIN <= d && d <= INT32_MAX) {
    1355             :             // Note: casting a double to an int when the double is too large or small
    1356             :             //       to fit the destination is undefined behavior. The explicit range checks,
    1357             :             //       above, are required. Just casting and checking the result value is undefined.
    1358           0 :             result.setLong(static_cast<int32_t>(d));
    1359             :         }
    1360             :     }
    1361             : }
    1362             : 
    1363             : #if !UCONFIG_NO_COLLATION
    1364             : 
    1365             : void
    1366           0 : RuleBasedNumberFormat::setLenient(UBool enabled)
    1367             : {
    1368           0 :     lenient = enabled;
    1369           0 :     if (!enabled && collator) {
    1370           0 :         delete collator;
    1371           0 :         collator = NULL;
    1372             :     }
    1373           0 : }
    1374             : 
    1375             : #endif
    1376             : 
    1377             : void 
    1378           0 : RuleBasedNumberFormat::setDefaultRuleSet(const UnicodeString& ruleSetName, UErrorCode& status) {
    1379           0 :     if (U_SUCCESS(status)) {
    1380           0 :         if (ruleSetName.isEmpty()) {
    1381           0 :           if (localizations) {
    1382           0 :               UnicodeString name(TRUE, localizations->getRuleSetName(0), -1);
    1383           0 :               defaultRuleSet = findRuleSet(name, status);
    1384             :           } else {
    1385           0 :             initDefaultRuleSet();
    1386             :           }
    1387           0 :         } else if (ruleSetName.startsWith(UNICODE_STRING_SIMPLE("%%"))) {
    1388           0 :             status = U_ILLEGAL_ARGUMENT_ERROR;
    1389             :         } else {
    1390           0 :             NFRuleSet* result = findRuleSet(ruleSetName, status);
    1391           0 :             if (result != NULL) {
    1392           0 :                 defaultRuleSet = result;
    1393             :             }
    1394             :         }
    1395             :     }
    1396           0 : }
    1397             : 
    1398             : UnicodeString
    1399           0 : RuleBasedNumberFormat::getDefaultRuleSetName() const {
    1400           0 :     UnicodeString result;
    1401           0 :     if (defaultRuleSet && defaultRuleSet->isPublic()) {
    1402           0 :         defaultRuleSet->getName(result);
    1403             :     } else {
    1404           0 :         result.setToBogus();
    1405             :     }
    1406           0 :     return result;
    1407             : }
    1408             : 
    1409             : void 
    1410           0 : RuleBasedNumberFormat::initDefaultRuleSet()
    1411             : {
    1412           0 :     defaultRuleSet = NULL;
    1413           0 :     if (!ruleSets) {
    1414           0 :         return;
    1415             :     }
    1416             : 
    1417           0 :     const UnicodeString spellout(UNICODE_STRING_SIMPLE("%spellout-numbering"));
    1418           0 :     const UnicodeString ordinal(UNICODE_STRING_SIMPLE("%digits-ordinal"));
    1419           0 :     const UnicodeString duration(UNICODE_STRING_SIMPLE("%duration"));
    1420             : 
    1421           0 :     NFRuleSet**p = &ruleSets[0];
    1422           0 :     while (*p) {
    1423           0 :         if ((*p)->isNamed(spellout) || (*p)->isNamed(ordinal) || (*p)->isNamed(duration)) {
    1424           0 :             defaultRuleSet = *p;
    1425           0 :             return;
    1426             :         } else {
    1427           0 :             ++p;
    1428             :         }
    1429             :     }
    1430             : 
    1431           0 :     defaultRuleSet = *--p;
    1432           0 :     if (!defaultRuleSet->isPublic()) {
    1433           0 :         while (p != ruleSets) {
    1434           0 :             if ((*--p)->isPublic()) {
    1435           0 :                 defaultRuleSet = *p;
    1436           0 :                 break;
    1437             :             }
    1438             :         }
    1439             :     }
    1440             : }
    1441             : 
    1442             : 
    1443             : void
    1444           0 : RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* localizationInfos,
    1445             :                             UParseError& pErr, UErrorCode& status)
    1446             : {
    1447             :     // TODO: implement UParseError
    1448           0 :     uprv_memset(&pErr, 0, sizeof(UParseError));
    1449             :     // Note: this can leave ruleSets == NULL, so remaining code should check
    1450           0 :     if (U_FAILURE(status)) {
    1451           0 :         return;
    1452             :     }
    1453             : 
    1454           0 :     initializeDecimalFormatSymbols(status);
    1455           0 :     initializeDefaultInfinityRule(status);
    1456           0 :     initializeDefaultNaNRule(status);
    1457           0 :     if (U_FAILURE(status)) {
    1458           0 :         return;
    1459             :     }
    1460             : 
    1461           0 :     this->localizations = localizationInfos == NULL ? NULL : localizationInfos->ref();
    1462             : 
    1463           0 :     UnicodeString description(rules);
    1464           0 :     if (!description.length()) {
    1465           0 :         status = U_MEMORY_ALLOCATION_ERROR;
    1466           0 :         return;
    1467             :     }
    1468             : 
    1469             :     // start by stripping the trailing whitespace from all the rules
    1470             :     // (this is all the whitespace follwing each semicolon in the
    1471             :     // description).  This allows us to look for rule-set boundaries
    1472             :     // by searching for ";%" without having to worry about whitespace
    1473             :     // between the ; and the %
    1474           0 :     stripWhitespace(description);
    1475             : 
    1476             :     // check to see if there's a set of lenient-parse rules.  If there
    1477             :     // is, pull them out into our temporary holding place for them,
    1478             :     // and delete them from the description before the real desciption-
    1479             :     // parsing code sees them
    1480           0 :     int32_t lp = description.indexOf(gLenientParse, -1, 0);
    1481           0 :     if (lp != -1) {
    1482             :         // we've got to make sure we're not in the middle of a rule
    1483             :         // (where "%%lenient-parse" would actually get treated as
    1484             :         // rule text)
    1485           0 :         if (lp == 0 || description.charAt(lp - 1) == gSemiColon) {
    1486             :             // locate the beginning and end of the actual collation
    1487             :             // rules (there may be whitespace between the name and
    1488             :             // the first token in the description)
    1489           0 :             int lpEnd = description.indexOf(gSemiPercent, 2, lp);
    1490             : 
    1491           0 :             if (lpEnd == -1) {
    1492           0 :                 lpEnd = description.length() - 1;
    1493             :             }
    1494           0 :             int lpStart = lp + u_strlen(gLenientParse);
    1495           0 :             while (PatternProps::isWhiteSpace(description.charAt(lpStart))) {
    1496           0 :                 ++lpStart;
    1497             :             }
    1498             : 
    1499             :             // copy out the lenient-parse rules and delete them
    1500             :             // from the description
    1501           0 :             lenientParseRules = new UnicodeString();
    1502             :             /* test for NULL */
    1503           0 :             if (lenientParseRules == 0) {
    1504           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
    1505           0 :                 return;
    1506             :             }
    1507           0 :             lenientParseRules->setTo(description, lpStart, lpEnd - lpStart);
    1508             : 
    1509           0 :             description.remove(lp, lpEnd + 1 - lp);
    1510             :         }
    1511             :     }
    1512             : 
    1513             :     // pre-flight parsing the description and count the number of
    1514             :     // rule sets (";%" marks the end of one rule set and the beginning
    1515             :     // of the next)
    1516           0 :     numRuleSets = 0;
    1517           0 :     for (int32_t p = description.indexOf(gSemiPercent, 2, 0); p != -1; p = description.indexOf(gSemiPercent, 2, p)) {
    1518           0 :         ++numRuleSets;
    1519           0 :         ++p;
    1520             :     }
    1521           0 :     ++numRuleSets;
    1522             : 
    1523             :     // our rule list is an array of the appropriate size
    1524           0 :     ruleSets = (NFRuleSet **)uprv_malloc((numRuleSets + 1) * sizeof(NFRuleSet *));
    1525             :     /* test for NULL */
    1526           0 :     if (ruleSets == 0) {
    1527           0 :         status = U_MEMORY_ALLOCATION_ERROR;
    1528           0 :         return;
    1529             :     }
    1530             : 
    1531           0 :     for (int i = 0; i <= numRuleSets; ++i) {
    1532           0 :         ruleSets[i] = NULL;
    1533             :     }
    1534             : 
    1535             :     // divide up the descriptions into individual rule-set descriptions
    1536             :     // and store them in a temporary array.  At each step, we also
    1537             :     // new up a rule set, but all this does is initialize its name
    1538             :     // and remove it from its description.  We can't actually parse
    1539             :     // the rest of the descriptions and finish initializing everything
    1540             :     // because we have to know the names and locations of all the rule
    1541             :     // sets before we can actually set everything up
    1542           0 :     if(!numRuleSets) {
    1543           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
    1544           0 :         return;
    1545             :     }
    1546             : 
    1547           0 :     ruleSetDescriptions = new UnicodeString[numRuleSets];
    1548           0 :     if (ruleSetDescriptions == 0) {
    1549           0 :         status = U_MEMORY_ALLOCATION_ERROR;
    1550           0 :         return;
    1551             :     }
    1552             : 
    1553             :     {
    1554           0 :         int curRuleSet = 0;
    1555           0 :         int32_t start = 0;
    1556           0 :         for (int32_t p = description.indexOf(gSemiPercent, 2, 0); p != -1; p = description.indexOf(gSemiPercent, 2, start)) {
    1557           0 :             ruleSetDescriptions[curRuleSet].setTo(description, start, p + 1 - start);
    1558           0 :             ruleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
    1559           0 :             if (ruleSets[curRuleSet] == 0) {
    1560           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
    1561           0 :                 return;
    1562             :             }
    1563           0 :             ++curRuleSet;
    1564           0 :             start = p + 1;
    1565             :         }
    1566           0 :         ruleSetDescriptions[curRuleSet].setTo(description, start, description.length() - start);
    1567           0 :         ruleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
    1568           0 :         if (ruleSets[curRuleSet] == 0) {
    1569           0 :             status = U_MEMORY_ALLOCATION_ERROR;
    1570           0 :             return;
    1571             :         }
    1572             :     }
    1573             : 
    1574             :     // now we can take note of the formatter's default rule set, which
    1575             :     // is the last public rule set in the description (it's the last
    1576             :     // rather than the first so that a user can create a new formatter
    1577             :     // from an existing formatter and change its default behavior just
    1578             :     // by appending more rule sets to the end)
    1579             : 
    1580             :     // {dlf} Initialization of a fraction rule set requires the default rule
    1581             :     // set to be known.  For purposes of initialization, this is always the 
    1582             :     // last public rule set, no matter what the localization data says.
    1583           0 :     initDefaultRuleSet();
    1584             : 
    1585             :     // finally, we can go back through the temporary descriptions
    1586             :     // list and finish seting up the substructure (and we throw
    1587             :     // away the temporary descriptions as we go)
    1588             :     {
    1589           0 :         for (int i = 0; i < numRuleSets; i++) {
    1590           0 :             ruleSets[i]->parseRules(ruleSetDescriptions[i], status);
    1591             :         }
    1592             :     }
    1593             : 
    1594             :     // Now that the rules are initialized, the 'real' default rule
    1595             :     // set can be adjusted by the localization data.
    1596             : 
    1597             :     // The C code keeps the localization array as is, rather than building
    1598             :     // a separate array of the public rule set names, so we have less work
    1599             :     // to do here-- but we still need to check the names.
    1600             :     
    1601           0 :     if (localizationInfos) {
    1602             :         // confirm the names, if any aren't in the rules, that's an error
    1603             :         // it is ok if the rules contain public rule sets that are not in this list
    1604           0 :         for (int32_t i = 0; i < localizationInfos->getNumberOfRuleSets(); ++i) {
    1605           0 :             UnicodeString name(TRUE, localizationInfos->getRuleSetName(i), -1);
    1606           0 :             NFRuleSet* rs = findRuleSet(name, status);
    1607           0 :             if (rs == NULL) {
    1608           0 :                 break; // error
    1609             :             }
    1610           0 :             if (i == 0) {
    1611           0 :                 defaultRuleSet = rs;
    1612             :             }
    1613             :         }
    1614             :     } else {
    1615           0 :         defaultRuleSet = getDefaultRuleSet();
    1616             :     }
    1617           0 :     originalDescription = rules;
    1618             : }
    1619             : 
    1620             : // override the NumberFormat implementation in order to
    1621             : // lazily initialize relevant items
    1622             : void
    1623           0 : RuleBasedNumberFormat::setContext(UDisplayContext value, UErrorCode& status)
    1624             : {
    1625           0 :     NumberFormat::setContext(value, status);
    1626           0 :     if (U_SUCCESS(status)) {
    1627           0 :         if (!capitalizationInfoSet &&
    1628           0 :                 (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE)) {
    1629           0 :             initCapitalizationContextInfo(locale);
    1630           0 :             capitalizationInfoSet = TRUE;
    1631             :         }
    1632             : #if !UCONFIG_NO_BREAK_ITERATION
    1633             :         if ( capitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
    1634             :                 (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
    1635             :                 (value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
    1636             :             UErrorCode status = U_ZERO_ERROR;
    1637             :             capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
    1638             :             if (U_FAILURE(status)) {
    1639             :                 delete capitalizationBrkIter;
    1640             :                 capitalizationBrkIter = NULL;
    1641             :             }
    1642             :         }
    1643             : #endif
    1644             :     }
    1645           0 : }
    1646             : 
    1647             : void
    1648           0 : RuleBasedNumberFormat::initCapitalizationContextInfo(const Locale& thelocale)
    1649             : {
    1650             : #if !UCONFIG_NO_BREAK_ITERATION
    1651             :     const char * localeID = (thelocale != NULL)? thelocale.getBaseName(): NULL;
    1652             :     UErrorCode status = U_ZERO_ERROR;
    1653             :     UResourceBundle *rb = ures_open(NULL, localeID, &status);
    1654             :     rb = ures_getByKeyWithFallback(rb, "contextTransforms", rb, &status);
    1655             :     rb = ures_getByKeyWithFallback(rb, "number-spellout", rb, &status);
    1656             :     if (U_SUCCESS(status) && rb != NULL) {
    1657             :         int32_t len = 0;
    1658             :         const int32_t * intVector = ures_getIntVector(rb, &len, &status);
    1659             :         if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
    1660             :             capitalizationForUIListMenu = intVector[0];
    1661             :             capitalizationForStandAlone = intVector[1];
    1662             :         }
    1663             :     }
    1664             :     ures_close(rb);
    1665             : #endif
    1666           0 : }
    1667             : 
    1668             : void
    1669           0 : RuleBasedNumberFormat::stripWhitespace(UnicodeString& description)
    1670             : {
    1671             :     // iterate through the characters...
    1672           0 :     UnicodeString result;
    1673             : 
    1674           0 :     int start = 0;
    1675           0 :     while (start != -1 && start < description.length()) {
    1676             :         // seek to the first non-whitespace character...
    1677           0 :         while (start < description.length()
    1678           0 :             && PatternProps::isWhiteSpace(description.charAt(start))) {
    1679           0 :             ++start;
    1680             :         }
    1681             : 
    1682             :         // locate the next semicolon in the text and copy the text from
    1683             :         // our current position up to that semicolon into the result
    1684           0 :         int32_t p = description.indexOf(gSemiColon, start);
    1685           0 :         if (p == -1) {
    1686             :             // or if we don't find a semicolon, just copy the rest of
    1687             :             // the string into the result
    1688           0 :             result.append(description, start, description.length() - start);
    1689           0 :             start = -1;
    1690             :         }
    1691           0 :         else if (p < description.length()) {
    1692           0 :             result.append(description, start, p + 1 - start);
    1693           0 :             start = p + 1;
    1694             :         }
    1695             : 
    1696             :         // when we get here, we've seeked off the end of the sring, and
    1697             :         // we terminate the loop (we continue until *start* is -1 rather
    1698             :         // than until *p* is -1, because otherwise we'd miss the last
    1699             :         // rule in the description)
    1700             :         else {
    1701           0 :             start = -1;
    1702             :         }
    1703             :     }
    1704             : 
    1705           0 :     description.setTo(result);
    1706           0 : }
    1707             : 
    1708             : 
    1709             : void
    1710           0 : RuleBasedNumberFormat::dispose()
    1711             : {
    1712           0 :     if (ruleSets) {
    1713           0 :         for (NFRuleSet** p = ruleSets; *p; ++p) {
    1714           0 :             delete *p;
    1715             :         }
    1716           0 :         uprv_free(ruleSets);
    1717           0 :         ruleSets = NULL;
    1718             :     }
    1719             : 
    1720           0 :     if (ruleSetDescriptions) {
    1721           0 :         delete [] ruleSetDescriptions;
    1722           0 :         ruleSetDescriptions = NULL;
    1723             :     }
    1724             : 
    1725             : #if !UCONFIG_NO_COLLATION
    1726           0 :     delete collator;
    1727             : #endif
    1728           0 :     collator = NULL;
    1729             : 
    1730           0 :     delete decimalFormatSymbols;
    1731           0 :     decimalFormatSymbols = NULL;
    1732             : 
    1733           0 :     delete defaultInfinityRule;
    1734           0 :     defaultInfinityRule = NULL;
    1735             : 
    1736           0 :     delete defaultNaNRule;
    1737           0 :     defaultNaNRule = NULL;
    1738             : 
    1739           0 :     delete lenientParseRules;
    1740           0 :     lenientParseRules = NULL;
    1741             : 
    1742             : #if !UCONFIG_NO_BREAK_ITERATION
    1743             :     delete capitalizationBrkIter;
    1744             :     capitalizationBrkIter = NULL;
    1745             : #endif
    1746             : 
    1747           0 :     if (localizations) {
    1748           0 :         localizations = localizations->unref();
    1749             :     }
    1750           0 : }
    1751             : 
    1752             : 
    1753             : //-----------------------------------------------------------------------
    1754             : // package-internal API
    1755             : //-----------------------------------------------------------------------
    1756             : 
    1757             : /**
    1758             :  * Returns the collator to use for lenient parsing.  The collator is lazily created:
    1759             :  * this function creates it the first time it's called.
    1760             :  * @return The collator to use for lenient parsing, or null if lenient parsing
    1761             :  * is turned off.
    1762             : */
    1763             : const RuleBasedCollator*
    1764           0 : RuleBasedNumberFormat::getCollator() const
    1765             : {
    1766             : #if !UCONFIG_NO_COLLATION
    1767           0 :     if (!ruleSets) {
    1768           0 :         return NULL;
    1769             :     }
    1770             : 
    1771             :     // lazy-evaluate the collator
    1772           0 :     if (collator == NULL && lenient) {
    1773             :         // create a default collator based on the formatter's locale,
    1774             :         // then pull out that collator's rules, append any additional
    1775             :         // rules specified in the description, and create a _new_
    1776             :         // collator based on the combinaiton of those rules
    1777             : 
    1778           0 :         UErrorCode status = U_ZERO_ERROR;
    1779             : 
    1780           0 :         Collator* temp = Collator::createInstance(locale, status);
    1781             :         RuleBasedCollator* newCollator;
    1782           0 :         if (U_SUCCESS(status) && (newCollator = dynamic_cast<RuleBasedCollator*>(temp)) != NULL) {
    1783           0 :             if (lenientParseRules) {
    1784           0 :                 UnicodeString rules(newCollator->getRules());
    1785           0 :                 rules.append(*lenientParseRules);
    1786             : 
    1787           0 :                 newCollator = new RuleBasedCollator(rules, status);
    1788             :                 // Exit if newCollator could not be created.
    1789           0 :                 if (newCollator == NULL) {
    1790           0 :                     return NULL;
    1791             :                 }
    1792             :             } else {
    1793           0 :                 temp = NULL;
    1794             :             }
    1795           0 :             if (U_SUCCESS(status)) {
    1796           0 :                 newCollator->setAttribute(UCOL_DECOMPOSITION_MODE, UCOL_ON, status);
    1797             :                 // cast away const
    1798           0 :                 ((RuleBasedNumberFormat*)this)->collator = newCollator;
    1799             :             } else {
    1800           0 :                 delete newCollator;
    1801             :             }
    1802             :         }
    1803           0 :         delete temp;
    1804             :     }
    1805             : #endif
    1806             : 
    1807             :     // if lenient-parse mode is off, this will be null
    1808             :     // (see setLenientParseMode())
    1809           0 :     return collator;
    1810             : }
    1811             : 
    1812             : 
    1813             : DecimalFormatSymbols*
    1814           0 : RuleBasedNumberFormat::initializeDecimalFormatSymbols(UErrorCode &status)
    1815             : {
    1816             :     // lazy-evaluate the DecimalFormatSymbols object.  This object
    1817             :     // is shared by all DecimalFormat instances belonging to this
    1818             :     // formatter
    1819           0 :     if (decimalFormatSymbols == NULL) {
    1820           0 :         DecimalFormatSymbols* temp = new DecimalFormatSymbols(locale, status);
    1821           0 :         if (U_SUCCESS(status)) {
    1822           0 :             decimalFormatSymbols = temp;
    1823             :         }
    1824             :         else {
    1825           0 :             delete temp;
    1826             :         }
    1827             :     }
    1828           0 :     return decimalFormatSymbols;
    1829             : }
    1830             : 
    1831             : /**
    1832             :  * Returns the DecimalFormatSymbols object that should be used by all DecimalFormat
    1833             :  * instances owned by this formatter.
    1834             : */
    1835             : const DecimalFormatSymbols*
    1836           0 : RuleBasedNumberFormat::getDecimalFormatSymbols() const
    1837             : {
    1838           0 :     return decimalFormatSymbols;
    1839             : }
    1840             : 
    1841             : NFRule*
    1842           0 : RuleBasedNumberFormat::initializeDefaultInfinityRule(UErrorCode &status)
    1843             : {
    1844           0 :     if (U_FAILURE(status)) {
    1845           0 :         return NULL;
    1846             :     }
    1847           0 :     if (defaultInfinityRule == NULL) {
    1848           0 :         UnicodeString rule(UNICODE_STRING_SIMPLE("Inf: "));
    1849           0 :         rule.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kInfinitySymbol));
    1850           0 :         NFRule* temp = new NFRule(this, rule, status);
    1851           0 :         if (U_SUCCESS(status)) {
    1852           0 :             defaultInfinityRule = temp;
    1853             :         }
    1854             :         else {
    1855           0 :             delete temp;
    1856             :         }
    1857             :     }
    1858           0 :     return defaultInfinityRule;
    1859             : }
    1860             : 
    1861             : const NFRule*
    1862           0 : RuleBasedNumberFormat::getDefaultInfinityRule() const
    1863             : {
    1864           0 :     return defaultInfinityRule;
    1865             : }
    1866             : 
    1867             : NFRule*
    1868           0 : RuleBasedNumberFormat::initializeDefaultNaNRule(UErrorCode &status)
    1869             : {
    1870           0 :     if (U_FAILURE(status)) {
    1871           0 :         return NULL;
    1872             :     }
    1873           0 :     if (defaultNaNRule == NULL) {
    1874           0 :         UnicodeString rule(UNICODE_STRING_SIMPLE("NaN: "));
    1875           0 :         rule.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kNaNSymbol));
    1876           0 :         NFRule* temp = new NFRule(this, rule, status);
    1877           0 :         if (U_SUCCESS(status)) {
    1878           0 :             defaultNaNRule = temp;
    1879             :         }
    1880             :         else {
    1881           0 :             delete temp;
    1882             :         }
    1883             :     }
    1884           0 :     return defaultNaNRule;
    1885             : }
    1886             : 
    1887             : const NFRule*
    1888           0 : RuleBasedNumberFormat::getDefaultNaNRule() const
    1889             : {
    1890           0 :     return defaultNaNRule;
    1891             : }
    1892             : 
    1893             : // De-owning the current localized symbols and adopt the new symbols.
    1894             : void
    1895           0 : RuleBasedNumberFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt)
    1896             : {
    1897           0 :     if (symbolsToAdopt == NULL) {
    1898           0 :         return; // do not allow caller to set decimalFormatSymbols to NULL
    1899             :     }
    1900             : 
    1901           0 :     if (decimalFormatSymbols != NULL) {
    1902           0 :         delete decimalFormatSymbols;
    1903             :     }
    1904             : 
    1905           0 :     decimalFormatSymbols = symbolsToAdopt;
    1906             : 
    1907             :     {
    1908             :         // Apply the new decimalFormatSymbols by reparsing the rulesets
    1909           0 :         UErrorCode status = U_ZERO_ERROR;
    1910             : 
    1911           0 :         delete defaultInfinityRule;
    1912           0 :         defaultInfinityRule = NULL;
    1913           0 :         initializeDefaultInfinityRule(status); // Reset with the new DecimalFormatSymbols
    1914             : 
    1915           0 :         delete defaultNaNRule;
    1916           0 :         defaultNaNRule = NULL;
    1917           0 :         initializeDefaultNaNRule(status); // Reset with the new DecimalFormatSymbols
    1918             : 
    1919           0 :         if (ruleSets) {
    1920           0 :             for (int32_t i = 0; i < numRuleSets; i++) {
    1921           0 :                 ruleSets[i]->setDecimalFormatSymbols(*symbolsToAdopt, status);
    1922             :             }
    1923             :         }
    1924             :     }
    1925             : }
    1926             : 
    1927             : // Setting the symbols is equlivalent to adopting a newly created localized symbols.
    1928             : void
    1929           0 : RuleBasedNumberFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
    1930             : {
    1931           0 :     adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols));
    1932           0 : }
    1933             : 
    1934             : PluralFormat *
    1935           0 : RuleBasedNumberFormat::createPluralFormat(UPluralType pluralType,
    1936             :                                           const UnicodeString &pattern,
    1937             :                                           UErrorCode& status) const
    1938             : {
    1939           0 :     return new PluralFormat(locale, pluralType, pattern, status);
    1940             : }
    1941             : 
    1942             : U_NAMESPACE_END
    1943             : 
    1944             : /* U_HAVE_RBNF */
    1945             : #endif

Generated by: LCOV version 1.13