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