michael@0: /* michael@0: ****************************************************************************** michael@0: * Copyright (C) 1996-2013, International Business Machines Corporation and michael@0: * others. All Rights Reserved. michael@0: ****************************************************************************** michael@0: */ michael@0: michael@0: /** michael@0: * File tblcoll.cpp michael@0: * michael@0: * Created by: Helena Shih michael@0: * michael@0: * Modification History: michael@0: * michael@0: * Date Name Description michael@0: * 2/5/97 aliu Added streamIn and streamOut methods. Added michael@0: * constructor which reads RuleBasedCollator object from michael@0: * a binary file. Added writeToFile method which streams michael@0: * RuleBasedCollator out to a binary file. The streamIn michael@0: * and streamOut methods use istream and ostream objects michael@0: * in binary mode. michael@0: * 2/11/97 aliu Moved declarations out of for loop initializer. michael@0: * Added Mac compatibility #ifdef for ios::nocreate. michael@0: * 2/12/97 aliu Modified to use TableCollationData sub-object to michael@0: * hold invariant data. michael@0: * 2/13/97 aliu Moved several methods into this class from Collation. michael@0: * Added a private RuleBasedCollator(Locale&) constructor, michael@0: * to be used by Collator::getInstance(). General michael@0: * clean up. Made use of UErrorCode variables consistent. michael@0: * 2/20/97 helena Added clone, operator==, operator!=, operator=, and copy michael@0: * constructor and getDynamicClassID. michael@0: * 3/5/97 aliu Changed compaction cycle to improve performance. We michael@0: * use the maximum allowable value which is kBlockCount. michael@0: * Modified getRules() to load rules dynamically. Changed michael@0: * constructFromFile() call to accomodate this (added michael@0: * parameter to specify whether binary loading is to michael@0: * take place). michael@0: * 05/06/97 helena Added memory allocation error check. michael@0: * 6/20/97 helena Java class name change. michael@0: * 6/23/97 helena Adding comments to make code more readable. michael@0: * 09/03/97 helena Added createCollationKeyValues(). michael@0: * 06/26/98 erm Changes for CollationKeys using byte arrays. michael@0: * 08/10/98 erm Synched with 1.2 version of RuleBasedCollator.java michael@0: * 04/23/99 stephen Removed EDecompositionMode, merged with michael@0: * Normalizer::EMode michael@0: * 06/14/99 stephen Removed kResourceBundleSuffix michael@0: * 06/22/99 stephen Fixed logic in constructFromFile() since .ctx michael@0: * files are no longer used. michael@0: * 11/02/99 helena Collator performance enhancements. Special case michael@0: * for NO_OP situations. michael@0: * 11/17/99 srl More performance enhancements. Inlined some internal functions. michael@0: * 12/15/99 aliu Update to support Thai collation. Move NormalizerIterator michael@0: * to implementation file. michael@0: * 01/29/01 synwee Modified into a C++ wrapper calling C APIs (ucol.h) michael@0: */ michael@0: michael@0: #include "unicode/utypes.h" michael@0: michael@0: #if !UCONFIG_NO_COLLATION michael@0: michael@0: #include "unicode/tblcoll.h" michael@0: #include "unicode/coleitr.h" michael@0: #include "unicode/ures.h" michael@0: #include "unicode/uset.h" michael@0: #include "ucol_imp.h" michael@0: #include "uresimp.h" michael@0: #include "uhash.h" michael@0: #include "cmemory.h" michael@0: #include "cstring.h" michael@0: #include "putilimp.h" michael@0: #include "ustr_imp.h" michael@0: michael@0: /* public RuleBasedCollator constructor ---------------------------------- */ michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: /** michael@0: * Copy constructor, aliasing, not write-through michael@0: */ michael@0: RuleBasedCollator::RuleBasedCollator(const RuleBasedCollator& that) michael@0: : Collator(that) michael@0: , dataIsOwned(FALSE) michael@0: , isWriteThroughAlias(FALSE) michael@0: , ucollator(NULL) michael@0: { michael@0: RuleBasedCollator::operator=(that); michael@0: } michael@0: michael@0: RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules, michael@0: UErrorCode& status) : michael@0: dataIsOwned(FALSE) michael@0: { michael@0: construct(rules, michael@0: UCOL_DEFAULT_STRENGTH, michael@0: UCOL_DEFAULT, michael@0: status); michael@0: } michael@0: michael@0: RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules, michael@0: ECollationStrength collationStrength, michael@0: UErrorCode& status) : dataIsOwned(FALSE) michael@0: { michael@0: construct(rules, michael@0: (UColAttributeValue)collationStrength, michael@0: UCOL_DEFAULT, michael@0: status); michael@0: } michael@0: michael@0: RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules, michael@0: UColAttributeValue decompositionMode, michael@0: UErrorCode& status) : michael@0: dataIsOwned(FALSE) michael@0: { michael@0: construct(rules, michael@0: UCOL_DEFAULT_STRENGTH, michael@0: decompositionMode, michael@0: status); michael@0: } michael@0: michael@0: RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules, michael@0: ECollationStrength collationStrength, michael@0: UColAttributeValue decompositionMode, michael@0: UErrorCode& status) : dataIsOwned(FALSE) michael@0: { michael@0: construct(rules, michael@0: (UColAttributeValue)collationStrength, michael@0: decompositionMode, michael@0: status); michael@0: } michael@0: RuleBasedCollator::RuleBasedCollator(const uint8_t *bin, int32_t length, michael@0: const RuleBasedCollator *base, michael@0: UErrorCode &status) : michael@0: dataIsOwned(TRUE), michael@0: isWriteThroughAlias(FALSE) michael@0: { michael@0: ucollator = ucol_openBinary(bin, length, base->ucollator, &status); michael@0: } michael@0: michael@0: void michael@0: RuleBasedCollator::setRuleStringFromCollator() michael@0: { michael@0: int32_t length; michael@0: const UChar *r = ucol_getRules(ucollator, &length); michael@0: michael@0: if (r && length > 0) { michael@0: // alias the rules string michael@0: urulestring.setTo(TRUE, r, length); michael@0: } michael@0: else { michael@0: urulestring.truncate(0); // Clear string. michael@0: } michael@0: } michael@0: michael@0: // not aliasing, not write-through michael@0: void michael@0: RuleBasedCollator::construct(const UnicodeString& rules, michael@0: UColAttributeValue collationStrength, michael@0: UColAttributeValue decompositionMode, michael@0: UErrorCode& status) michael@0: { michael@0: ucollator = ucol_openRules(rules.getBuffer(), rules.length(), michael@0: decompositionMode, collationStrength, michael@0: NULL, &status); michael@0: michael@0: dataIsOwned = TRUE; // since we own a collator now, we need to get rid of it michael@0: isWriteThroughAlias = FALSE; michael@0: michael@0: if(ucollator == NULL) { michael@0: if(U_SUCCESS(status)) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: } michael@0: return; // Failure michael@0: } michael@0: michael@0: setRuleStringFromCollator(); michael@0: } michael@0: michael@0: /* RuleBasedCollator public destructor ----------------------------------- */ michael@0: michael@0: RuleBasedCollator::~RuleBasedCollator() michael@0: { michael@0: if (dataIsOwned) michael@0: { michael@0: ucol_close(ucollator); michael@0: } michael@0: ucollator = 0; michael@0: } michael@0: michael@0: /* RuleBaseCollator public methods --------------------------------------- */ michael@0: michael@0: UBool RuleBasedCollator::operator==(const Collator& that) const michael@0: { michael@0: /* only checks for address equals here */ michael@0: if (this == &that) { michael@0: return TRUE; michael@0: } michael@0: if (!Collator::operator==(that)) { michael@0: return FALSE; /* not the same class */ michael@0: } michael@0: michael@0: RuleBasedCollator& thatAlias = (RuleBasedCollator&)that; michael@0: michael@0: return ucol_equals(this->ucollator, thatAlias.ucollator); michael@0: } michael@0: michael@0: // aliasing, not write-through michael@0: RuleBasedCollator& RuleBasedCollator::operator=(const RuleBasedCollator& that) michael@0: { michael@0: if (this == &that) { return *this; } michael@0: michael@0: UErrorCode intStatus = U_ZERO_ERROR; michael@0: UCollator *ucol = ucol_safeClone(that.ucollator, NULL, NULL, &intStatus); michael@0: if (U_FAILURE(intStatus)) { return *this; } michael@0: michael@0: if (dataIsOwned) { michael@0: ucol_close(ucollator); michael@0: } michael@0: ucollator = ucol; michael@0: dataIsOwned = TRUE; michael@0: isWriteThroughAlias = FALSE; michael@0: setRuleStringFromCollator(); michael@0: return *this; michael@0: } michael@0: michael@0: // aliasing, not write-through michael@0: Collator* RuleBasedCollator::clone() const michael@0: { michael@0: RuleBasedCollator* coll = new RuleBasedCollator(*this); michael@0: // There is a small chance that the internal ucol_safeClone() call fails. michael@0: if (coll != NULL && coll->ucollator == NULL) { michael@0: delete coll; michael@0: return NULL; michael@0: } michael@0: return coll; michael@0: } michael@0: michael@0: michael@0: CollationElementIterator* RuleBasedCollator::createCollationElementIterator michael@0: (const UnicodeString& source) const michael@0: { michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: CollationElementIterator *result = new CollationElementIterator(source, this, michael@0: status); michael@0: if (U_FAILURE(status)) { michael@0: delete result; michael@0: return NULL; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: /** michael@0: * Create a CollationElementIterator object that will iterate over the michael@0: * elements in a string, using the collation rules defined in this michael@0: * RuleBasedCollator michael@0: */ michael@0: CollationElementIterator* RuleBasedCollator::createCollationElementIterator michael@0: (const CharacterIterator& source) const michael@0: { michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: CollationElementIterator *result = new CollationElementIterator(source, this, michael@0: status); michael@0: michael@0: if (U_FAILURE(status)) { michael@0: delete result; michael@0: return NULL; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: /** michael@0: * Return a string representation of this collator's rules. The string can michael@0: * later be passed to the constructor that takes a UnicodeString argument, michael@0: * which will construct a collator that's functionally identical to this one. michael@0: * You can also allow users to edit the string in order to change the collation michael@0: * data, or you can print it out for inspection, or whatever. michael@0: */ michael@0: const UnicodeString& RuleBasedCollator::getRules() const michael@0: { michael@0: return urulestring; michael@0: } michael@0: michael@0: void RuleBasedCollator::getRules(UColRuleOption delta, UnicodeString &buffer) michael@0: { michael@0: int32_t rulesize = ucol_getRulesEx(ucollator, delta, NULL, -1); michael@0: michael@0: if (rulesize > 0) { michael@0: UChar *rules = (UChar*) uprv_malloc( sizeof(UChar) * (rulesize) ); michael@0: if(rules != NULL) { michael@0: ucol_getRulesEx(ucollator, delta, rules, rulesize); michael@0: buffer.setTo(rules, rulesize); michael@0: uprv_free(rules); michael@0: } else { // couldn't allocate michael@0: buffer.remove(); michael@0: } michael@0: } michael@0: else { michael@0: buffer.remove(); michael@0: } michael@0: } michael@0: michael@0: UnicodeSet * michael@0: RuleBasedCollator::getTailoredSet(UErrorCode &status) const michael@0: { michael@0: if(U_FAILURE(status)) { michael@0: return NULL; michael@0: } michael@0: return (UnicodeSet *)ucol_getTailoredSet(this->ucollator, &status); michael@0: } michael@0: michael@0: michael@0: void RuleBasedCollator::getVersion(UVersionInfo versionInfo) const michael@0: { michael@0: if (versionInfo!=NULL){ michael@0: ucol_getVersion(ucollator, versionInfo); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Compare two strings using this collator michael@0: */ michael@0: UCollationResult RuleBasedCollator::compare( michael@0: const UnicodeString& source, michael@0: const UnicodeString& target, michael@0: int32_t length, michael@0: UErrorCode &status) const michael@0: { michael@0: return compare(source.getBuffer(), uprv_min(length,source.length()), target.getBuffer(), uprv_min(length,target.length()), status); michael@0: } michael@0: michael@0: UCollationResult RuleBasedCollator::compare(const UChar* source, michael@0: int32_t sourceLength, michael@0: const UChar* target, michael@0: int32_t targetLength, michael@0: UErrorCode &status) const michael@0: { michael@0: if(U_SUCCESS(status)) { michael@0: return ucol_strcoll(ucollator, source, sourceLength, target, targetLength); michael@0: } else { michael@0: return UCOL_EQUAL; michael@0: } michael@0: } michael@0: michael@0: UCollationResult RuleBasedCollator::compare( michael@0: const UnicodeString& source, michael@0: const UnicodeString& target, michael@0: UErrorCode &status) const michael@0: { michael@0: if(U_SUCCESS(status)) { michael@0: return ucol_strcoll(ucollator, source.getBuffer(), source.length(), michael@0: target.getBuffer(), target.length()); michael@0: } else { michael@0: return UCOL_EQUAL; michael@0: } michael@0: } michael@0: michael@0: UCollationResult RuleBasedCollator::compare(UCharIterator &sIter, michael@0: UCharIterator &tIter, michael@0: UErrorCode &status) const { michael@0: if(U_SUCCESS(status)) { michael@0: return ucol_strcollIter(ucollator, &sIter, &tIter, &status); michael@0: } else { michael@0: return UCOL_EQUAL; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Retrieve a collation key for the specified string. The key can be compared michael@0: * with other collation keys using a bitwise comparison (e.g. memcmp) to find michael@0: * the ordering of their respective source strings. This is handy when doing a michael@0: * sort, where each sort key must be compared many times. michael@0: * michael@0: * The basic algorithm here is to find all of the collation elements for each michael@0: * character in the source string, convert them to an ASCII representation, and michael@0: * put them into the collation key. But it's trickier than that. Each michael@0: * collation element in a string has three components: primary ('A' vs 'B'), michael@0: * secondary ('u' vs '\u00FC'), and tertiary ('A' vs 'a'), and a primary difference michael@0: * at the end of a string takes precedence over a secondary or tertiary michael@0: * difference earlier in the string. michael@0: * michael@0: * To account for this, we put all of the primary orders at the beginning of michael@0: * the string, followed by the secondary and tertiary orders. Each set of michael@0: * orders is terminated by nulls so that a key for a string which is a initial michael@0: * substring of another key will compare less without any special case. michael@0: * michael@0: * Here's a hypothetical example, with the collation element represented as a michael@0: * three-digit number, one digit for primary, one for secondary, etc. michael@0: * michael@0: * String: A a B \u00C9 michael@0: * Collation Elements: 101 100 201 511 michael@0: * Collation Key: 112500011011 michael@0: * michael@0: * To make things even trickier, secondary differences (accent marks) are michael@0: * compared starting at the *end* of the string in languages with French michael@0: * secondary ordering. But when comparing the accent marks on a single base michael@0: * character, they are compared from the beginning. To handle this, we reverse michael@0: * all of the accents that belong to each base character, then we reverse the michael@0: * entire string of secondary orderings at the end. michael@0: */ michael@0: CollationKey& RuleBasedCollator::getCollationKey( michael@0: const UnicodeString& source, michael@0: CollationKey& sortkey, michael@0: UErrorCode& status) const michael@0: { michael@0: return getCollationKey(source.getBuffer(), source.length(), sortkey, status); michael@0: } michael@0: michael@0: CollationKey& RuleBasedCollator::getCollationKey(const UChar* source, michael@0: int32_t sourceLen, michael@0: CollationKey& sortkey, michael@0: UErrorCode& status) const michael@0: { michael@0: if (U_FAILURE(status)) { michael@0: return sortkey.setToBogus(); michael@0: } michael@0: if (sourceLen < -1 || (source == NULL && sourceLen != 0)) { michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return sortkey.setToBogus(); michael@0: } michael@0: michael@0: if (sourceLen < 0) { michael@0: sourceLen = u_strlen(source); michael@0: } michael@0: if (sourceLen == 0) { michael@0: return sortkey.reset(); michael@0: } michael@0: michael@0: int32_t resultLen = ucol_getCollationKey(ucollator, source, sourceLen, sortkey, status); michael@0: michael@0: if (U_SUCCESS(status)) { michael@0: sortkey.setLength(resultLen); michael@0: } else { michael@0: sortkey.setToBogus(); michael@0: } michael@0: return sortkey; michael@0: } michael@0: michael@0: /** michael@0: * Return the maximum length of any expansion sequences that end with the michael@0: * specified comparison order. michael@0: * @param order a collation order returned by previous or next. michael@0: * @return the maximum length of any expansion seuences ending with the michael@0: * specified order or 1 if collation order does not occur at the end of any michael@0: * expansion sequence. michael@0: * @see CollationElementIterator#getMaxExpansion michael@0: */ michael@0: int32_t RuleBasedCollator::getMaxExpansion(int32_t order) const michael@0: { michael@0: uint8_t result; michael@0: UCOL_GETMAXEXPANSION(ucollator, (uint32_t)order, result); michael@0: return result; michael@0: } michael@0: michael@0: uint8_t* RuleBasedCollator::cloneRuleData(int32_t &length, michael@0: UErrorCode &status) michael@0: { michael@0: if (U_FAILURE(status)) { return NULL; } michael@0: LocalMemory buffer((uint8_t *)uprv_malloc(20000)); michael@0: if (buffer.isNull()) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: length = cloneBinary(buffer.getAlias(), 20000, status); michael@0: if (status == U_BUFFER_OVERFLOW_ERROR) { michael@0: if (buffer.allocateInsteadAndCopy(length, 0) == NULL) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: status = U_ZERO_ERROR; michael@0: length = cloneBinary(buffer.getAlias(), length, status); michael@0: } michael@0: if (U_FAILURE(status)) { return NULL; } michael@0: return buffer.orphan(); michael@0: } michael@0: michael@0: michael@0: int32_t RuleBasedCollator::cloneBinary(uint8_t *buffer, int32_t capacity, UErrorCode &status) michael@0: { michael@0: return ucol_cloneBinary(ucollator, buffer, capacity, &status); michael@0: } michael@0: michael@0: void RuleBasedCollator::setAttribute(UColAttribute attr, michael@0: UColAttributeValue value, michael@0: UErrorCode &status) michael@0: { michael@0: if (U_FAILURE(status)) michael@0: return; michael@0: checkOwned(); michael@0: ucol_setAttribute(ucollator, attr, value, &status); michael@0: } michael@0: michael@0: UColAttributeValue RuleBasedCollator::getAttribute(UColAttribute attr, michael@0: UErrorCode &status) const michael@0: { michael@0: if (U_FAILURE(status)) michael@0: return UCOL_DEFAULT; michael@0: return ucol_getAttribute(ucollator, attr, &status); michael@0: } michael@0: michael@0: uint32_t RuleBasedCollator::setVariableTop(const UChar *varTop, int32_t len, UErrorCode &status) { michael@0: checkOwned(); michael@0: return ucol_setVariableTop(ucollator, varTop, len, &status); michael@0: } michael@0: michael@0: uint32_t RuleBasedCollator::setVariableTop(const UnicodeString &varTop, UErrorCode &status) { michael@0: checkOwned(); michael@0: return ucol_setVariableTop(ucollator, varTop.getBuffer(), varTop.length(), &status); michael@0: } michael@0: michael@0: void RuleBasedCollator::setVariableTop(uint32_t varTop, UErrorCode &status) { michael@0: checkOwned(); michael@0: ucol_restoreVariableTop(ucollator, varTop, &status); michael@0: } michael@0: michael@0: uint32_t RuleBasedCollator::getVariableTop(UErrorCode &status) const { michael@0: return ucol_getVariableTop(ucollator, &status); michael@0: } michael@0: michael@0: int32_t RuleBasedCollator::getSortKey(const UnicodeString& source, michael@0: uint8_t *result, int32_t resultLength) michael@0: const michael@0: { michael@0: return ucol_getSortKey(ucollator, source.getBuffer(), source.length(), result, resultLength); michael@0: } michael@0: michael@0: int32_t RuleBasedCollator::getSortKey(const UChar *source, michael@0: int32_t sourceLength, uint8_t *result, michael@0: int32_t resultLength) const michael@0: { michael@0: return ucol_getSortKey(ucollator, source, sourceLength, result, resultLength); michael@0: } michael@0: michael@0: int32_t RuleBasedCollator::getReorderCodes(int32_t *dest, michael@0: int32_t destCapacity, michael@0: UErrorCode& status) const michael@0: { michael@0: return ucol_getReorderCodes(ucollator, dest, destCapacity, &status); michael@0: } michael@0: michael@0: void RuleBasedCollator::setReorderCodes(const int32_t *reorderCodes, michael@0: int32_t reorderCodesLength, michael@0: UErrorCode& status) michael@0: { michael@0: checkOwned(); michael@0: ucol_setReorderCodes(ucollator, reorderCodes, reorderCodesLength, &status); michael@0: } michael@0: michael@0: int32_t RuleBasedCollator::getEquivalentReorderCodes(int32_t reorderCode, michael@0: int32_t* dest, michael@0: int32_t destCapacity, michael@0: UErrorCode& status) michael@0: { michael@0: return ucol_getEquivalentReorderCodes(reorderCode, dest, destCapacity, &status); michael@0: } michael@0: michael@0: /** michael@0: * Create a hash code for this collation. Just hash the main rule table -- that michael@0: * should be good enough for almost any use. michael@0: */ michael@0: int32_t RuleBasedCollator::hashCode() const michael@0: { michael@0: int32_t length; michael@0: const UChar *rules = ucol_getRules(ucollator, &length); michael@0: return ustr_hashUCharsN(rules, length); michael@0: } michael@0: michael@0: /** michael@0: * return the locale of this collator michael@0: */ michael@0: Locale RuleBasedCollator::getLocale(ULocDataLocaleType type, UErrorCode &status) const { michael@0: const char *result = ucol_getLocaleByType(ucollator, type, &status); michael@0: if(result == NULL) { michael@0: Locale res(""); michael@0: res.setToBogus(); michael@0: return res; michael@0: } else { michael@0: return Locale(result); michael@0: } michael@0: } michael@0: michael@0: void michael@0: RuleBasedCollator::setLocales(const Locale& requestedLocale, const Locale& validLocale, const Locale& actualLocale) { michael@0: checkOwned(); michael@0: char* rloc = uprv_strdup(requestedLocale.getName()); michael@0: if (rloc) { michael@0: char* vloc = uprv_strdup(validLocale.getName()); michael@0: if (vloc) { michael@0: char* aloc = uprv_strdup(actualLocale.getName()); michael@0: if (aloc) { michael@0: ucol_setReqValidLocales(ucollator, rloc, vloc, aloc); michael@0: return; michael@0: } michael@0: uprv_free(vloc); michael@0: } michael@0: uprv_free(rloc); michael@0: } michael@0: } michael@0: michael@0: // RuleBaseCollatorNew private constructor ---------------------------------- michael@0: michael@0: RuleBasedCollator::RuleBasedCollator() michael@0: : dataIsOwned(FALSE), isWriteThroughAlias(FALSE), ucollator(NULL) michael@0: { michael@0: } michael@0: michael@0: RuleBasedCollator::RuleBasedCollator(const Locale& desiredLocale, michael@0: UErrorCode& status) michael@0: : dataIsOwned(FALSE), isWriteThroughAlias(FALSE), ucollator(NULL) michael@0: { michael@0: if (U_FAILURE(status)) michael@0: return; michael@0: michael@0: /* michael@0: Try to load, in order: michael@0: 1. The desired locale's collation. michael@0: 2. A fallback of the desired locale. michael@0: 3. The default locale's collation. michael@0: 4. A fallback of the default locale. michael@0: 5. The default collation rules, which contains en_US collation rules. michael@0: michael@0: To reiterate, we try: michael@0: Specific: michael@0: language+country+variant michael@0: language+country michael@0: language michael@0: Default: michael@0: language+country+variant michael@0: language+country michael@0: language michael@0: Root: (aka DEFAULTRULES) michael@0: steps 1-5 are handled by resource bundle fallback mechanism. michael@0: however, in a very unprobable situation that no resource bundle michael@0: data exists, step 5 is repeated with hardcoded default rules. michael@0: */ michael@0: michael@0: setUCollator(desiredLocale, status); michael@0: michael@0: if (U_FAILURE(status)) michael@0: { michael@0: status = U_ZERO_ERROR; michael@0: michael@0: setUCollator(kRootLocaleName, status); michael@0: if (status == U_ZERO_ERROR) { michael@0: status = U_USING_DEFAULT_WARNING; michael@0: } michael@0: } michael@0: michael@0: if (U_SUCCESS(status)) michael@0: { michael@0: setRuleStringFromCollator(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: RuleBasedCollator::setUCollator(const char *locale, michael@0: UErrorCode &status) michael@0: { michael@0: if (U_FAILURE(status)) { michael@0: return; michael@0: } michael@0: if (ucollator && dataIsOwned) michael@0: ucol_close(ucollator); michael@0: ucollator = ucol_open_internal(locale, &status); michael@0: dataIsOwned = TRUE; michael@0: isWriteThroughAlias = FALSE; michael@0: } michael@0: michael@0: michael@0: void michael@0: RuleBasedCollator::checkOwned() { michael@0: if (!(dataIsOwned || isWriteThroughAlias)) { michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: ucollator = ucol_safeClone(ucollator, NULL, NULL, &status); michael@0: setRuleStringFromCollator(); michael@0: dataIsOwned = TRUE; michael@0: isWriteThroughAlias = FALSE; michael@0: } michael@0: } michael@0: michael@0: michael@0: int32_t RuleBasedCollator::internalGetShortDefinitionString(const char *locale, michael@0: char *buffer, michael@0: int32_t capacity, michael@0: UErrorCode &status) const { michael@0: /* simply delegate */ michael@0: return ucol_getShortDefinitionString(ucollator, locale, buffer, capacity, &status); michael@0: } michael@0: michael@0: michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedCollator) michael@0: michael@0: U_NAMESPACE_END michael@0: michael@0: #endif /* #if !UCONFIG_NO_COLLATION */