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