1/* 2 ****************************************************************************** 3 * Copyright (C) 1996-2011, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ****************************************************************************** 6 */ 7 8/** 9 * File tblcoll.cpp 10 * 11 * Created by: Helena Shih 12 * 13 * Modification History: 14 * 15 * Date Name Description 16 * 2/5/97 aliu Added streamIn and streamOut methods. Added 17 * constructor which reads RuleBasedCollator object from 18 * a binary file. Added writeToFile method which streams 19 * RuleBasedCollator out to a binary file. The streamIn 20 * and streamOut methods use istream and ostream objects 21 * in binary mode. 22 * 2/11/97 aliu Moved declarations out of for loop initializer. 23 * Added Mac compatibility #ifdef for ios::nocreate. 24 * 2/12/97 aliu Modified to use TableCollationData sub-object to 25 * hold invariant data. 26 * 2/13/97 aliu Moved several methods into this class from Collation. 27 * Added a private RuleBasedCollator(Locale&) constructor, 28 * to be used by Collator::getInstance(). General 29 * clean up. Made use of UErrorCode variables consistent. 30 * 2/20/97 helena Added clone, operator==, operator!=, operator=, and copy 31 * constructor and getDynamicClassID. 32 * 3/5/97 aliu Changed compaction cycle to improve performance. We 33 * use the maximum allowable value which is kBlockCount. 34 * Modified getRules() to load rules dynamically. Changed 35 * constructFromFile() call to accomodate this (added 36 * parameter to specify whether binary loading is to 37 * take place). 38 * 05/06/97 helena Added memory allocation error check. 39 * 6/20/97 helena Java class name change. 40 * 6/23/97 helena Adding comments to make code more readable. 41 * 09/03/97 helena Added createCollationKeyValues(). 42 * 06/26/98 erm Changes for CollationKeys using byte arrays. 43 * 08/10/98 erm Synched with 1.2 version of RuleBasedCollator.java 44 * 04/23/99 stephen Removed EDecompositionMode, merged with 45 * Normalizer::EMode 46 * 06/14/99 stephen Removed kResourceBundleSuffix 47 * 06/22/99 stephen Fixed logic in constructFromFile() since .ctx 48 * files are no longer used. 49 * 11/02/99 helena Collator performance enhancements. Special case 50 * for NO_OP situations. 51 * 11/17/99 srl More performance enhancements. Inlined some internal functions. 52 * 12/15/99 aliu Update to support Thai collation. Move NormalizerIterator 53 * to implementation file. 54 * 01/29/01 synwee Modified into a C++ wrapper calling C APIs (ucol.h) 55 */ 56 57#include <typeinfo> // for 'typeid' to work 58 59#include "unicode/utypes.h" 60 61#if !UCONFIG_NO_COLLATION 62 63#include "unicode/tblcoll.h" 64#include "unicode/coleitr.h" 65#include "unicode/ures.h" 66#include "unicode/uset.h" 67#include "ucol_imp.h" 68#include "uresimp.h" 69#include "uhash.h" 70#include "cmemory.h" 71#include "cstring.h" 72#include "putilimp.h" 73 74/* public RuleBasedCollator constructor ---------------------------------- */ 75 76U_NAMESPACE_BEGIN 77 78/** 79* Copy constructor, aliasing, not write-through 80*/ 81RuleBasedCollator::RuleBasedCollator(const RuleBasedCollator& that) 82: Collator(that) 83, dataIsOwned(FALSE) 84, isWriteThroughAlias(FALSE) 85, ucollator(NULL) 86{ 87 RuleBasedCollator::operator=(that); 88} 89 90RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules, 91 UErrorCode& status) : 92dataIsOwned(FALSE) 93{ 94 construct(rules, 95 UCOL_DEFAULT_STRENGTH, 96 UCOL_DEFAULT, 97 status); 98} 99 100RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules, 101 ECollationStrength collationStrength, 102 UErrorCode& status) : dataIsOwned(FALSE) 103{ 104 construct(rules, 105 getUCollationStrength(collationStrength), 106 UCOL_DEFAULT, 107 status); 108} 109 110RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules, 111 UColAttributeValue decompositionMode, 112 UErrorCode& status) : 113dataIsOwned(FALSE) 114{ 115 construct(rules, 116 UCOL_DEFAULT_STRENGTH, 117 decompositionMode, 118 status); 119} 120 121RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules, 122 ECollationStrength collationStrength, 123 UColAttributeValue decompositionMode, 124 UErrorCode& status) : dataIsOwned(FALSE) 125{ 126 construct(rules, 127 getUCollationStrength(collationStrength), 128 decompositionMode, 129 status); 130} 131RuleBasedCollator::RuleBasedCollator(const uint8_t *bin, int32_t length, 132 const RuleBasedCollator *base, 133 UErrorCode &status) : 134dataIsOwned(TRUE), 135isWriteThroughAlias(FALSE) 136{ 137 ucollator = ucol_openBinary(bin, length, base->ucollator, &status); 138} 139 140void 141RuleBasedCollator::setRuleStringFromCollator() 142{ 143 int32_t length; 144 const UChar *r = ucol_getRules(ucollator, &length); 145 146 if (r && length > 0) { 147 // alias the rules string 148 urulestring.setTo(TRUE, r, length); 149 } 150 else { 151 urulestring.truncate(0); // Clear string. 152 } 153} 154 155// not aliasing, not write-through 156void 157RuleBasedCollator::construct(const UnicodeString& rules, 158 UColAttributeValue collationStrength, 159 UColAttributeValue decompositionMode, 160 UErrorCode& status) 161{ 162 ucollator = ucol_openRules(rules.getBuffer(), rules.length(), 163 decompositionMode, collationStrength, 164 NULL, &status); 165 166 dataIsOwned = TRUE; // since we own a collator now, we need to get rid of it 167 isWriteThroughAlias = FALSE; 168 169 if(ucollator == NULL) { 170 if(U_SUCCESS(status)) { 171 status = U_MEMORY_ALLOCATION_ERROR; 172 } 173 return; // Failure 174 } 175 176 setRuleStringFromCollator(); 177} 178 179/* RuleBasedCollator public destructor ----------------------------------- */ 180 181RuleBasedCollator::~RuleBasedCollator() 182{ 183 if (dataIsOwned) 184 { 185 ucol_close(ucollator); 186 } 187 ucollator = 0; 188} 189 190/* RuleBaseCollator public methods --------------------------------------- */ 191 192UBool RuleBasedCollator::operator==(const Collator& that) const 193{ 194 /* only checks for address equals here */ 195 if (Collator::operator==(that)) 196 return TRUE; 197 198 if (typeid(*this) != typeid(that)) 199 return FALSE; /* not the same class */ 200 201 RuleBasedCollator& thatAlias = (RuleBasedCollator&)that; 202 203 // weiv: use C function, commented code below is wrong 204 return ucol_equals(this->ucollator, thatAlias.ucollator); 205 /* 206 synwee : orginal code does not check for data compatibility 207 */ 208 /* 209 if (ucollator != thatAlias.ucollator) 210 return FALSE; 211 212 return TRUE; 213 */ 214} 215 216UBool RuleBasedCollator::operator!=(const Collator& other) const 217{ 218 return !(*this == other); 219} 220 221// aliasing, not write-through 222RuleBasedCollator& RuleBasedCollator::operator=(const RuleBasedCollator& that) 223{ 224 if (this != &that) 225 { 226 if (dataIsOwned) 227 { 228 ucol_close(ucollator); 229 } 230 231 urulestring.truncate(0); // empty the rule string 232 dataIsOwned = TRUE; 233 isWriteThroughAlias = FALSE; 234 235 UErrorCode intStatus = U_ZERO_ERROR; 236 int32_t buffersize = U_COL_SAFECLONE_BUFFERSIZE; 237 ucollator = ucol_safeClone(that.ucollator, NULL, &buffersize, 238 &intStatus); 239 if (U_SUCCESS(intStatus)) { 240 setRuleStringFromCollator(); 241 } 242 } 243 return *this; 244} 245 246// aliasing, not write-through 247Collator* RuleBasedCollator::clone() const 248{ 249 return new RuleBasedCollator(*this); 250} 251 252 253CollationElementIterator* RuleBasedCollator::createCollationElementIterator 254 (const UnicodeString& source) const 255{ 256 UErrorCode status = U_ZERO_ERROR; 257 CollationElementIterator *result = new CollationElementIterator(source, this, 258 status); 259 if (U_FAILURE(status)) { 260 delete result; 261 return NULL; 262 } 263 264 return result; 265} 266 267/** 268* Create a CollationElementIterator object that will iterate over the 269* elements in a string, using the collation rules defined in this 270* RuleBasedCollator 271*/ 272CollationElementIterator* RuleBasedCollator::createCollationElementIterator 273 (const CharacterIterator& source) const 274{ 275 UErrorCode status = U_ZERO_ERROR; 276 CollationElementIterator *result = new CollationElementIterator(source, this, 277 status); 278 279 if (U_FAILURE(status)) { 280 delete result; 281 return NULL; 282 } 283 284 return result; 285} 286 287/** 288* Return a string representation of this collator's rules. The string can 289* later be passed to the constructor that takes a UnicodeString argument, 290* which will construct a collator that's functionally identical to this one. 291* You can also allow users to edit the string in order to change the collation 292* data, or you can print it out for inspection, or whatever. 293*/ 294const UnicodeString& RuleBasedCollator::getRules() const 295{ 296 return urulestring; 297} 298 299void RuleBasedCollator::getRules(UColRuleOption delta, UnicodeString &buffer) 300{ 301 int32_t rulesize = ucol_getRulesEx(ucollator, delta, NULL, -1); 302 303 if (rulesize > 0) { 304 UChar *rules = (UChar*) uprv_malloc( sizeof(UChar) * (rulesize) ); 305 if(rules != NULL) { 306 ucol_getRulesEx(ucollator, delta, rules, rulesize); 307 buffer.setTo(rules, rulesize); 308 uprv_free(rules); 309 } else { // couldn't allocate 310 buffer.remove(); 311 } 312 } 313 else { 314 buffer.remove(); 315 } 316} 317 318UnicodeSet * 319RuleBasedCollator::getTailoredSet(UErrorCode &status) const 320{ 321 if(U_FAILURE(status)) { 322 return NULL; 323 } 324 return (UnicodeSet *)ucol_getTailoredSet(this->ucollator, &status); 325} 326 327 328void RuleBasedCollator::getVersion(UVersionInfo versionInfo) const 329{ 330 if (versionInfo!=NULL){ 331 ucol_getVersion(ucollator, versionInfo); 332 } 333} 334 335Collator::EComparisonResult RuleBasedCollator::compare( 336 const UnicodeString& source, 337 const UnicodeString& target, 338 int32_t length) const 339{ 340 UErrorCode status = U_ZERO_ERROR; 341 return getEComparisonResult(compare(source.getBuffer(), uprv_min(length,source.length()), target.getBuffer(), uprv_min(length,target.length()), status)); 342} 343 344UCollationResult RuleBasedCollator::compare( 345 const UnicodeString& source, 346 const UnicodeString& target, 347 int32_t length, 348 UErrorCode &status) const 349{ 350 return compare(source.getBuffer(), uprv_min(length,source.length()), target.getBuffer(), uprv_min(length,target.length()), status); 351} 352 353Collator::EComparisonResult RuleBasedCollator::compare(const UChar* source, 354 int32_t sourceLength, 355 const UChar* target, 356 int32_t targetLength) 357 const 358{ 359 return getEComparisonResult(ucol_strcoll(ucollator, source, sourceLength, 360 target, targetLength)); 361} 362 363UCollationResult RuleBasedCollator::compare(const UChar* source, 364 int32_t sourceLength, 365 const UChar* target, 366 int32_t targetLength, 367 UErrorCode &status) const 368{ 369 if(U_SUCCESS(status)) { 370 return ucol_strcoll(ucollator, source, sourceLength, target, targetLength); 371 } else { 372 return UCOL_EQUAL; 373 } 374} 375 376/** 377* Compare two strings using this collator 378*/ 379Collator::EComparisonResult RuleBasedCollator::compare( 380 const UnicodeString& source, 381 const UnicodeString& target) const 382{ 383 return getEComparisonResult(ucol_strcoll(ucollator, source.getBuffer(), source.length(), 384 target.getBuffer(), target.length())); 385} 386 387UCollationResult RuleBasedCollator::compare( 388 const UnicodeString& source, 389 const UnicodeString& target, 390 UErrorCode &status) const 391{ 392 if(U_SUCCESS(status)) { 393 return ucol_strcoll(ucollator, source.getBuffer(), source.length(), 394 target.getBuffer(), target.length()); 395 } else { 396 return UCOL_EQUAL; 397 } 398} 399 400UCollationResult RuleBasedCollator::compare(UCharIterator &sIter, 401 UCharIterator &tIter, 402 UErrorCode &status) const { 403 if(U_SUCCESS(status)) { 404 return ucol_strcollIter(ucollator, &sIter, &tIter, &status); 405 } else { 406 return UCOL_EQUAL; 407 } 408} 409 410/** 411* Retrieve a collation key for the specified string. The key can be compared 412* with other collation keys using a bitwise comparison (e.g. memcmp) to find 413* the ordering of their respective source strings. This is handy when doing a 414* sort, where each sort key must be compared many times. 415* 416* The basic algorithm here is to find all of the collation elements for each 417* character in the source string, convert them to an ASCII representation, and 418* put them into the collation key. But it's trickier than that. Each 419* collation element in a string has three components: primary ('A' vs 'B'), 420* secondary ('u' vs '\u00FC'), and tertiary ('A' vs 'a'), and a primary difference 421* at the end of a string takes precedence over a secondary or tertiary 422* difference earlier in the string. 423* 424* To account for this, we put all of the primary orders at the beginning of 425* the string, followed by the secondary and tertiary orders. Each set of 426* orders is terminated by nulls so that a key for a string which is a initial 427* substring of another key will compare less without any special case. 428* 429* Here's a hypothetical example, with the collation element represented as a 430* three-digit number, one digit for primary, one for secondary, etc. 431* 432* String: A a B \u00C9 433* Collation Elements: 101 100 201 511 434* Collation Key: 1125<null>0001<null>1011<null> 435* 436* To make things even trickier, secondary differences (accent marks) are 437* compared starting at the *end* of the string in languages with French 438* secondary ordering. But when comparing the accent marks on a single base 439* character, they are compared from the beginning. To handle this, we reverse 440* all of the accents that belong to each base character, then we reverse the 441* entire string of secondary orderings at the end. 442*/ 443CollationKey& RuleBasedCollator::getCollationKey( 444 const UnicodeString& source, 445 CollationKey& sortkey, 446 UErrorCode& status) const 447{ 448 return getCollationKey(source.getBuffer(), source.length(), sortkey, status); 449} 450 451CollationKey& RuleBasedCollator::getCollationKey(const UChar* source, 452 int32_t sourceLen, 453 CollationKey& sortkey, 454 UErrorCode& status) const 455{ 456 if (U_FAILURE(status)) { 457 return sortkey.setToBogus(); 458 } 459 if (sourceLen < -1 || (source == NULL && sourceLen != 0)) { 460 status = U_ILLEGAL_ARGUMENT_ERROR; 461 return sortkey.setToBogus(); 462 } 463 464 if (sourceLen < 0) { 465 sourceLen = u_strlen(source); 466 } 467 if (sourceLen == 0) { 468 return sortkey.reset(); 469 } 470 471 uint8_t *result; 472 int32_t resultCapacity; 473 if (sortkey.fCapacity >= (sourceLen * 3)) { 474 // Try to reuse the CollationKey.fBytes. 475 result = sortkey.fBytes; 476 resultCapacity = sortkey.fCapacity; 477 } else { 478 result = NULL; 479 resultCapacity = 0; 480 } 481 int32_t resultLen = ucol_getSortKeyWithAllocation(ucollator, source, sourceLen, 482 result, resultCapacity, &status); 483 484 if (U_SUCCESS(status)) { 485 if (result == sortkey.fBytes) { 486 sortkey.setLength(resultLen); 487 } else { 488 sortkey.adopt(result, resultCapacity, resultLen); 489 } 490 } else { 491 if (result != sortkey.fBytes) { 492 uprv_free(result); 493 } 494 sortkey.setToBogus(); 495 } 496 return sortkey; 497} 498 499/** 500 * Return the maximum length of any expansion sequences that end with the 501 * specified comparison order. 502 * @param order a collation order returned by previous or next. 503 * @return the maximum length of any expansion seuences ending with the 504 * specified order or 1 if collation order does not occur at the end of any 505 * expansion sequence. 506 * @see CollationElementIterator#getMaxExpansion 507 */ 508int32_t RuleBasedCollator::getMaxExpansion(int32_t order) const 509{ 510 uint8_t result; 511 UCOL_GETMAXEXPANSION(ucollator, (uint32_t)order, result); 512 return result; 513} 514 515uint8_t* RuleBasedCollator::cloneRuleData(int32_t &length, 516 UErrorCode &status) 517{ 518 return ucol_cloneRuleData(ucollator, &length, &status); 519} 520 521 522int32_t RuleBasedCollator::cloneBinary(uint8_t *buffer, int32_t capacity, UErrorCode &status) 523{ 524 return ucol_cloneBinary(ucollator, buffer, capacity, &status); 525} 526 527void RuleBasedCollator::setAttribute(UColAttribute attr, 528 UColAttributeValue value, 529 UErrorCode &status) 530{ 531 if (U_FAILURE(status)) 532 return; 533 checkOwned(); 534 ucol_setAttribute(ucollator, attr, value, &status); 535} 536 537UColAttributeValue RuleBasedCollator::getAttribute(UColAttribute attr, 538 UErrorCode &status) 539{ 540 if (U_FAILURE(status)) 541 return UCOL_DEFAULT; 542 return ucol_getAttribute(ucollator, attr, &status); 543} 544 545uint32_t RuleBasedCollator::setVariableTop(const UChar *varTop, int32_t len, UErrorCode &status) { 546 checkOwned(); 547 return ucol_setVariableTop(ucollator, varTop, len, &status); 548} 549 550uint32_t RuleBasedCollator::setVariableTop(const UnicodeString varTop, UErrorCode &status) { 551 checkOwned(); 552 return ucol_setVariableTop(ucollator, varTop.getBuffer(), varTop.length(), &status); 553} 554 555void RuleBasedCollator::setVariableTop(const uint32_t varTop, UErrorCode &status) { 556 checkOwned(); 557 ucol_restoreVariableTop(ucollator, varTop, &status); 558} 559 560uint32_t RuleBasedCollator::getVariableTop(UErrorCode &status) const { 561 return ucol_getVariableTop(ucollator, &status); 562} 563 564Collator* RuleBasedCollator::safeClone(void) 565{ 566 UErrorCode intStatus = U_ZERO_ERROR; 567 int32_t buffersize = U_COL_SAFECLONE_BUFFERSIZE; 568 UCollator *ucol = ucol_safeClone(ucollator, NULL, &buffersize, 569 &intStatus); 570 if (U_FAILURE(intStatus)) { 571 return NULL; 572 } 573 574 RuleBasedCollator *result = new RuleBasedCollator(); 575 // Null pointer check 576 if (result != NULL) { 577 result->ucollator = ucol; 578 result->dataIsOwned = TRUE; 579 result->isWriteThroughAlias = FALSE; 580 setRuleStringFromCollator(); 581 } 582 583 return result; 584} 585 586 587int32_t RuleBasedCollator::getSortKey(const UnicodeString& source, 588 uint8_t *result, int32_t resultLength) 589 const 590{ 591 return ucol_getSortKey(ucollator, source.getBuffer(), source.length(), result, resultLength); 592} 593 594int32_t RuleBasedCollator::getSortKey(const UChar *source, 595 int32_t sourceLength, uint8_t *result, 596 int32_t resultLength) const 597{ 598 return ucol_getSortKey(ucollator, source, sourceLength, result, resultLength); 599} 600 601Collator::ECollationStrength RuleBasedCollator::getStrength(void) const 602{ 603 UErrorCode intStatus = U_ZERO_ERROR; 604 return getECollationStrength(ucol_getAttribute(ucollator, UCOL_STRENGTH, 605 &intStatus)); 606} 607 608void RuleBasedCollator::setStrength(ECollationStrength newStrength) 609{ 610 checkOwned(); 611 UErrorCode intStatus = U_ZERO_ERROR; 612 UCollationStrength strength = getUCollationStrength(newStrength); 613 ucol_setAttribute(ucollator, UCOL_STRENGTH, strength, &intStatus); 614} 615 616int32_t RuleBasedCollator::getReorderCodes(int32_t *dest, 617 int32_t destCapacity, 618 UErrorCode& status) const 619{ 620 return ucol_getReorderCodes(ucollator, dest, destCapacity, &status); 621} 622 623void RuleBasedCollator::setReorderCodes(const int32_t *reorderCodes, 624 int32_t reorderCodesLength, 625 UErrorCode& status) 626{ 627 checkOwned(); 628 ucol_setReorderCodes(ucollator, reorderCodes, reorderCodesLength, &status); 629} 630 631int32_t RuleBasedCollator::getEquivalentReorderCodes(int32_t reorderCode, 632 int32_t* dest, 633 int32_t destCapacity, 634 UErrorCode& status) 635{ 636 return ucol_getEquivalentReorderCodes(reorderCode, dest, destCapacity, &status); 637} 638 639/** 640* Create a hash code for this collation. Just hash the main rule table -- that 641* should be good enough for almost any use. 642*/ 643int32_t RuleBasedCollator::hashCode() const 644{ 645 int32_t length; 646 const UChar *rules = ucol_getRules(ucollator, &length); 647 return uhash_hashUCharsN(rules, length); 648} 649 650/** 651* return the locale of this collator 652*/ 653const Locale RuleBasedCollator::getLocale(ULocDataLocaleType type, UErrorCode &status) const { 654 const char *result = ucol_getLocaleByType(ucollator, type, &status); 655 if(result == NULL) { 656 Locale res(""); 657 res.setToBogus(); 658 return res; 659 } else { 660 return Locale(result); 661 } 662} 663 664void 665RuleBasedCollator::setLocales(const Locale& requestedLocale, const Locale& validLocale, const Locale& actualLocale) { 666 checkOwned(); 667 char* rloc = uprv_strdup(requestedLocale.getName()); 668 if (rloc) { 669 char* vloc = uprv_strdup(validLocale.getName()); 670 if (vloc) { 671 char* aloc = uprv_strdup(actualLocale.getName()); 672 if (aloc) { 673 ucol_setReqValidLocales(ucollator, rloc, vloc, aloc); 674 return; 675 } 676 uprv_free(vloc); 677 } 678 uprv_free(rloc); 679 } 680} 681 682// RuleBaseCollatorNew private constructor ---------------------------------- 683 684RuleBasedCollator::RuleBasedCollator() 685 : dataIsOwned(FALSE), isWriteThroughAlias(FALSE), ucollator(NULL) 686{ 687} 688 689RuleBasedCollator::RuleBasedCollator(const Locale& desiredLocale, 690 UErrorCode& status) 691 : dataIsOwned(FALSE), isWriteThroughAlias(FALSE), ucollator(NULL) 692{ 693 if (U_FAILURE(status)) 694 return; 695 696 /* 697 Try to load, in order: 698 1. The desired locale's collation. 699 2. A fallback of the desired locale. 700 3. The default locale's collation. 701 4. A fallback of the default locale. 702 5. The default collation rules, which contains en_US collation rules. 703 704 To reiterate, we try: 705 Specific: 706 language+country+variant 707 language+country 708 language 709 Default: 710 language+country+variant 711 language+country 712 language 713 Root: (aka DEFAULTRULES) 714 steps 1-5 are handled by resource bundle fallback mechanism. 715 however, in a very unprobable situation that no resource bundle 716 data exists, step 5 is repeated with hardcoded default rules. 717 */ 718 719 setUCollator(desiredLocale, status); 720 721 if (U_FAILURE(status)) 722 { 723 status = U_ZERO_ERROR; 724 725 setUCollator(kRootLocaleName, status); 726 if (status == U_ZERO_ERROR) { 727 status = U_USING_DEFAULT_WARNING; 728 } 729 } 730 731 if (U_SUCCESS(status)) 732 { 733 setRuleStringFromCollator(); 734 } 735} 736 737void 738RuleBasedCollator::setUCollator(const char *locale, 739 UErrorCode &status) 740{ 741 if (U_FAILURE(status)) { 742 return; 743 } 744 if (ucollator && dataIsOwned) 745 ucol_close(ucollator); 746 ucollator = ucol_open_internal(locale, &status); 747 dataIsOwned = TRUE; 748 isWriteThroughAlias = FALSE; 749} 750 751 752void 753RuleBasedCollator::checkOwned() { 754 if (!(dataIsOwned || isWriteThroughAlias)) { 755 UErrorCode status = U_ZERO_ERROR; 756 ucollator = ucol_safeClone(ucollator, NULL, NULL, &status); 757 setRuleStringFromCollator(); 758 dataIsOwned = TRUE; 759 isWriteThroughAlias = FALSE; 760 } 761} 762 763UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedCollator) 764 765U_NAMESPACE_END 766 767#endif /* #if !UCONFIG_NO_COLLATION */ 768