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