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
|