1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *   Copyright (C) 1996-2015, International Business Machines
6 *   Corporation and others.  All Rights Reserved.
7 *******************************************************************************
8 *   file name:  ucol.cpp
9 *   encoding:   UTF-8
10 *   tab size:   8 (not used)
11 *   indentation:4
12 *
13 * Modification history
14 * Date        Name      Comments
15 * 1996-1999   various members of ICU team maintained C API for collation framework
16 * 02/16/2001  synwee    Added internal method getPrevSpecialCE
17 * 03/01/2001  synwee    Added maxexpansion functionality.
18 * 03/16/2001  weiv      Collation framework is rewritten in C and made UCA compliant
19 * 2012-2014   markus    Rewritten in C++ again.
20 */
21 
22 #include "unicode/utypes.h"
23 
24 #if !UCONFIG_NO_COLLATION
25 
26 #include "unicode/coll.h"
27 #include "unicode/tblcoll.h"
28 #include "unicode/bytestream.h"
29 #include "unicode/coleitr.h"
30 #include "unicode/ucoleitr.h"
31 #include "unicode/ustring.h"
32 #include "cmemory.h"
33 #include "collation.h"
34 #include "cstring.h"
35 #include "putilimp.h"
36 #include "uassert.h"
37 #include "utracimp.h"
38 
39 U_NAMESPACE_USE
40 
41 U_CAPI UCollator* U_EXPORT2
ucol_openBinary(const uint8_t * bin,int32_t length,const UCollator * base,UErrorCode * status)42 ucol_openBinary(const uint8_t *bin, int32_t length,
43                 const UCollator *base,
44                 UErrorCode *status)
45 {
46     if(U_FAILURE(*status)) { return NULL; }
47     RuleBasedCollator *coll = new RuleBasedCollator(
48             bin, length,
49             RuleBasedCollator::rbcFromUCollator(base),
50             *status);
51     if(coll == NULL) {
52         *status = U_MEMORY_ALLOCATION_ERROR;
53         return NULL;
54     }
55     if(U_FAILURE(*status)) {
56         delete coll;
57         return NULL;
58     }
59     return coll->toUCollator();
60 }
61 
62 U_CAPI int32_t U_EXPORT2
ucol_cloneBinary(const UCollator * coll,uint8_t * buffer,int32_t capacity,UErrorCode * status)63 ucol_cloneBinary(const UCollator *coll,
64                  uint8_t *buffer, int32_t capacity,
65                  UErrorCode *status)
66 {
67     if(U_FAILURE(*status)) {
68         return 0;
69     }
70     const RuleBasedCollator *rbc = RuleBasedCollator::rbcFromUCollator(coll);
71     if(rbc == NULL && coll != NULL) {
72         *status = U_UNSUPPORTED_ERROR;
73         return 0;
74     }
75     return rbc->cloneBinary(buffer, capacity, *status);
76 }
77 
78 U_CAPI UCollator* U_EXPORT2
ucol_safeClone(const UCollator * coll,void *,int32_t * pBufferSize,UErrorCode * status)79 ucol_safeClone(const UCollator *coll, void * /*stackBuffer*/, int32_t * pBufferSize, UErrorCode *status)
80 {
81     if (status == NULL || U_FAILURE(*status)){
82         return NULL;
83     }
84     if (coll == NULL) {
85        *status = U_ILLEGAL_ARGUMENT_ERROR;
86         return NULL;
87     }
88     if (pBufferSize != NULL) {
89         int32_t inputSize = *pBufferSize;
90         *pBufferSize = 1;
91         if (inputSize == 0) {
92             return NULL;  // preflighting for deprecated functionality
93         }
94     }
95     Collator *newColl = Collator::fromUCollator(coll)->clone();
96     if (newColl == NULL) {
97         *status = U_MEMORY_ALLOCATION_ERROR;
98         return nullptr;
99     } else {
100         *status = U_SAFECLONE_ALLOCATED_WARNING;
101     }
102     return newColl->toUCollator();
103 }
104 
105 U_CAPI void U_EXPORT2
ucol_close(UCollator * coll)106 ucol_close(UCollator *coll)
107 {
108     UTRACE_ENTRY_OC(UTRACE_UCOL_CLOSE);
109     UTRACE_DATA1(UTRACE_INFO, "coll = %p", coll);
110     if(coll != NULL) {
111         delete Collator::fromUCollator(coll);
112     }
113     UTRACE_EXIT();
114 }
115 
116 U_CAPI int32_t U_EXPORT2
ucol_mergeSortkeys(const uint8_t * src1,int32_t src1Length,const uint8_t * src2,int32_t src2Length,uint8_t * dest,int32_t destCapacity)117 ucol_mergeSortkeys(const uint8_t *src1, int32_t src1Length,
118                    const uint8_t *src2, int32_t src2Length,
119                    uint8_t *dest, int32_t destCapacity) {
120     /* check arguments */
121     if( src1==NULL || src1Length<-1 || src1Length==0 || (src1Length>0 && src1[src1Length-1]!=0) ||
122         src2==NULL || src2Length<-1 || src2Length==0 || (src2Length>0 && src2[src2Length-1]!=0) ||
123         destCapacity<0 || (destCapacity>0 && dest==NULL)
124     ) {
125         /* error, attempt to write a zero byte and return 0 */
126         if(dest!=NULL && destCapacity>0) {
127             *dest=0;
128         }
129         return 0;
130     }
131 
132     /* check lengths and capacity */
133     if(src1Length<0) {
134         src1Length=(int32_t)uprv_strlen((const char *)src1)+1;
135     }
136     if(src2Length<0) {
137         src2Length=(int32_t)uprv_strlen((const char *)src2)+1;
138     }
139 
140     int32_t destLength=src1Length+src2Length;
141     if(destLength>destCapacity) {
142         /* the merged sort key does not fit into the destination */
143         return destLength;
144     }
145 
146     /* merge the sort keys with the same number of levels */
147     uint8_t *p=dest;
148     for(;;) {
149         /* copy level from src1 not including 00 or 01 */
150         uint8_t b;
151         while((b=*src1)>=2) {
152             ++src1;
153             *p++=b;
154         }
155 
156         /* add a 02 merge separator */
157         *p++=2;
158 
159         /* copy level from src2 not including 00 or 01 */
160         while((b=*src2)>=2) {
161             ++src2;
162             *p++=b;
163         }
164 
165         /* if both sort keys have another level, then add a 01 level separator and continue */
166         if(*src1==1 && *src2==1) {
167             ++src1;
168             ++src2;
169             *p++=1;
170         } else {
171             break;
172         }
173     }
174 
175     /*
176      * here, at least one sort key is finished now, but the other one
177      * might have some contents left from containing more levels;
178      * that contents is just appended to the result
179      */
180     if(*src1!=0) {
181         /* src1 is not finished, therefore *src2==0, and src1 is appended */
182         src2=src1;
183     }
184     /* append src2, "the other, unfinished sort key" */
185     while((*p++=*src2++)!=0) {}
186 
187     /* the actual length might be less than destLength if either sort key contained illegally embedded zero bytes */
188     return (int32_t)(p-dest);
189 }
190 
191 U_CAPI int32_t U_EXPORT2
ucol_getSortKey(const UCollator * coll,const UChar * source,int32_t sourceLength,uint8_t * result,int32_t resultLength)192 ucol_getSortKey(const    UCollator    *coll,
193         const    UChar        *source,
194         int32_t        sourceLength,
195         uint8_t        *result,
196         int32_t        resultLength)
197 {
198     UTRACE_ENTRY(UTRACE_UCOL_GET_SORTKEY);
199     if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
200         UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source string = %vh ", coll, source,
201             ((sourceLength==-1 && source!=NULL) ? u_strlen(source) : sourceLength));
202     }
203 
204     int32_t keySize = Collator::fromUCollator(coll)->
205             getSortKey(source, sourceLength, result, resultLength);
206 
207     UTRACE_DATA2(UTRACE_VERBOSE, "Sort Key = %vb", result, keySize);
208     UTRACE_EXIT_VALUE(keySize);
209     return keySize;
210 }
211 
212 U_CAPI int32_t U_EXPORT2
ucol_nextSortKeyPart(const UCollator * coll,UCharIterator * iter,uint32_t state[2],uint8_t * dest,int32_t count,UErrorCode * status)213 ucol_nextSortKeyPart(const UCollator *coll,
214                      UCharIterator *iter,
215                      uint32_t state[2],
216                      uint8_t *dest, int32_t count,
217                      UErrorCode *status)
218 {
219     /* error checking */
220     if(status==NULL || U_FAILURE(*status)) {
221         return 0;
222     }
223     UTRACE_ENTRY(UTRACE_UCOL_NEXTSORTKEYPART);
224     UTRACE_DATA6(UTRACE_VERBOSE, "coll=%p, iter=%p, state=%d %d, dest=%p, count=%d",
225                   coll, iter, state[0], state[1], dest, count);
226 
227     int32_t i = Collator::fromUCollator(coll)->
228             internalNextSortKeyPart(iter, state, dest, count, *status);
229 
230     // Return number of meaningful sortkey bytes.
231     UTRACE_DATA4(UTRACE_VERBOSE, "dest = %vb, state=%d %d",
232                   dest,i, state[0], state[1]);
233     UTRACE_EXIT_VALUE_STATUS(i, *status);
234     return i;
235 }
236 
237 /**
238  * Produce a bound for a given sortkey and a number of levels.
239  */
240 U_CAPI int32_t U_EXPORT2
ucol_getBound(const uint8_t * source,int32_t sourceLength,UColBoundMode boundType,uint32_t noOfLevels,uint8_t * result,int32_t resultLength,UErrorCode * status)241 ucol_getBound(const uint8_t       *source,
242         int32_t             sourceLength,
243         UColBoundMode       boundType,
244         uint32_t            noOfLevels,
245         uint8_t             *result,
246         int32_t             resultLength,
247         UErrorCode          *status)
248 {
249     // consistency checks
250     if(status == NULL || U_FAILURE(*status)) {
251         return 0;
252     }
253     if(source == NULL) {
254         *status = U_ILLEGAL_ARGUMENT_ERROR;
255         return 0;
256     }
257 
258     int32_t sourceIndex = 0;
259     // Scan the string until we skip enough of the key OR reach the end of the key
260     do {
261         sourceIndex++;
262         if(source[sourceIndex] == Collation::LEVEL_SEPARATOR_BYTE) {
263             noOfLevels--;
264         }
265     } while (noOfLevels > 0
266         && (source[sourceIndex] != 0 || sourceIndex < sourceLength));
267 
268     if((source[sourceIndex] == 0 || sourceIndex == sourceLength)
269         && noOfLevels > 0) {
270             *status = U_SORT_KEY_TOO_SHORT_WARNING;
271     }
272 
273 
274     // READ ME: this code assumes that the values for boundType
275     // enum will not changes. They are set so that the enum value
276     // corresponds to the number of extra bytes each bound type
277     // needs.
278     if(result != NULL && resultLength >= sourceIndex+boundType) {
279         uprv_memcpy(result, source, sourceIndex);
280         switch(boundType) {
281             // Lower bound just gets terminated. No extra bytes
282         case UCOL_BOUND_LOWER: // = 0
283             break;
284             // Upper bound needs one extra byte
285         case UCOL_BOUND_UPPER: // = 1
286             result[sourceIndex++] = 2;
287             break;
288             // Upper long bound needs two extra bytes
289         case UCOL_BOUND_UPPER_LONG: // = 2
290             result[sourceIndex++] = 0xFF;
291             result[sourceIndex++] = 0xFF;
292             break;
293         default:
294             *status = U_ILLEGAL_ARGUMENT_ERROR;
295             return 0;
296         }
297         result[sourceIndex++] = 0;
298 
299         return sourceIndex;
300     } else {
301         return sourceIndex+boundType+1;
302     }
303 }
304 
305 U_CAPI void U_EXPORT2
ucol_setMaxVariable(UCollator * coll,UColReorderCode group,UErrorCode * pErrorCode)306 ucol_setMaxVariable(UCollator *coll, UColReorderCode group, UErrorCode *pErrorCode) {
307     if(U_FAILURE(*pErrorCode)) { return; }
308     Collator::fromUCollator(coll)->setMaxVariable(group, *pErrorCode);
309 }
310 
311 U_CAPI UColReorderCode U_EXPORT2
ucol_getMaxVariable(const UCollator * coll)312 ucol_getMaxVariable(const UCollator *coll) {
313     return Collator::fromUCollator(coll)->getMaxVariable();
314 }
315 
316 U_CAPI uint32_t  U_EXPORT2
ucol_setVariableTop(UCollator * coll,const UChar * varTop,int32_t len,UErrorCode * status)317 ucol_setVariableTop(UCollator *coll, const UChar *varTop, int32_t len, UErrorCode *status) {
318     if(U_FAILURE(*status) || coll == NULL) {
319         return 0;
320     }
321     return Collator::fromUCollator(coll)->setVariableTop(varTop, len, *status);
322 }
323 
ucol_getVariableTop(const UCollator * coll,UErrorCode * status)324 U_CAPI uint32_t U_EXPORT2 ucol_getVariableTop(const UCollator *coll, UErrorCode *status) {
325     if(U_FAILURE(*status) || coll == NULL) {
326         return 0;
327     }
328     return Collator::fromUCollator(coll)->getVariableTop(*status);
329 }
330 
331 U_CAPI void  U_EXPORT2
ucol_restoreVariableTop(UCollator * coll,const uint32_t varTop,UErrorCode * status)332 ucol_restoreVariableTop(UCollator *coll, const uint32_t varTop, UErrorCode *status) {
333     if(U_FAILURE(*status) || coll == NULL) {
334         return;
335     }
336     Collator::fromUCollator(coll)->setVariableTop(varTop, *status);
337 }
338 
339 U_CAPI void  U_EXPORT2
ucol_setAttribute(UCollator * coll,UColAttribute attr,UColAttributeValue value,UErrorCode * status)340 ucol_setAttribute(UCollator *coll, UColAttribute attr, UColAttributeValue value, UErrorCode *status) {
341     if(U_FAILURE(*status) || coll == NULL) {
342       return;
343     }
344 
345     Collator::fromUCollator(coll)->setAttribute(attr, value, *status);
346 }
347 
348 U_CAPI UColAttributeValue  U_EXPORT2
ucol_getAttribute(const UCollator * coll,UColAttribute attr,UErrorCode * status)349 ucol_getAttribute(const UCollator *coll, UColAttribute attr, UErrorCode *status) {
350     if(U_FAILURE(*status) || coll == NULL) {
351       return UCOL_DEFAULT;
352     }
353 
354     return Collator::fromUCollator(coll)->getAttribute(attr, *status);
355 }
356 
357 U_CAPI void U_EXPORT2
ucol_setStrength(UCollator * coll,UCollationStrength strength)358 ucol_setStrength(    UCollator                *coll,
359             UCollationStrength        strength)
360 {
361     UErrorCode status = U_ZERO_ERROR;
362     ucol_setAttribute(coll, UCOL_STRENGTH, strength, &status);
363 }
364 
365 U_CAPI UCollationStrength U_EXPORT2
ucol_getStrength(const UCollator * coll)366 ucol_getStrength(const UCollator *coll)
367 {
368     UErrorCode status = U_ZERO_ERROR;
369     return ucol_getAttribute(coll, UCOL_STRENGTH, &status);
370 }
371 
372 U_CAPI int32_t U_EXPORT2
ucol_getReorderCodes(const UCollator * coll,int32_t * dest,int32_t destCapacity,UErrorCode * status)373 ucol_getReorderCodes(const UCollator *coll,
374                     int32_t *dest,
375                     int32_t destCapacity,
376                     UErrorCode *status) {
377     if (U_FAILURE(*status)) {
378         return 0;
379     }
380 
381     return Collator::fromUCollator(coll)->getReorderCodes(dest, destCapacity, *status);
382 }
383 
384 U_CAPI void U_EXPORT2
ucol_setReorderCodes(UCollator * coll,const int32_t * reorderCodes,int32_t reorderCodesLength,UErrorCode * status)385 ucol_setReorderCodes(UCollator* coll,
386                     const int32_t* reorderCodes,
387                     int32_t reorderCodesLength,
388                     UErrorCode *status) {
389     if (U_FAILURE(*status)) {
390         return;
391     }
392 
393     Collator::fromUCollator(coll)->setReorderCodes(reorderCodes, reorderCodesLength, *status);
394 }
395 
396 U_CAPI int32_t U_EXPORT2
ucol_getEquivalentReorderCodes(int32_t reorderCode,int32_t * dest,int32_t destCapacity,UErrorCode * pErrorCode)397 ucol_getEquivalentReorderCodes(int32_t reorderCode,
398                     int32_t* dest,
399                     int32_t destCapacity,
400                     UErrorCode *pErrorCode) {
401     return Collator::getEquivalentReorderCodes(reorderCode, dest, destCapacity, *pErrorCode);
402 }
403 
404 U_CAPI void U_EXPORT2
ucol_getVersion(const UCollator * coll,UVersionInfo versionInfo)405 ucol_getVersion(const UCollator* coll,
406                 UVersionInfo versionInfo)
407 {
408     Collator::fromUCollator(coll)->getVersion(versionInfo);
409 }
410 
411 U_CAPI UCollationResult U_EXPORT2
ucol_strcollIter(const UCollator * coll,UCharIterator * sIter,UCharIterator * tIter,UErrorCode * status)412 ucol_strcollIter( const UCollator    *coll,
413                  UCharIterator *sIter,
414                  UCharIterator *tIter,
415                  UErrorCode         *status)
416 {
417     if(!status || U_FAILURE(*status)) {
418         return UCOL_EQUAL;
419     }
420 
421     UTRACE_ENTRY(UTRACE_UCOL_STRCOLLITER);
422     UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, sIter=%p, tIter=%p", coll, sIter, tIter);
423 
424     if(sIter == NULL || tIter == NULL || coll == NULL) {
425         *status = U_ILLEGAL_ARGUMENT_ERROR;
426         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status);
427         return UCOL_EQUAL;
428     }
429 
430     UCollationResult result = Collator::fromUCollator(coll)->compare(*sIter, *tIter, *status);
431 
432     UTRACE_EXIT_VALUE_STATUS(result, *status);
433     return result;
434 }
435 
436 
437 /*                                                                      */
438 /* ucol_strcoll     Main public API string comparison function          */
439 /*                                                                      */
440 U_CAPI UCollationResult U_EXPORT2
ucol_strcoll(const UCollator * coll,const UChar * source,int32_t sourceLength,const UChar * target,int32_t targetLength)441 ucol_strcoll( const UCollator    *coll,
442               const UChar        *source,
443               int32_t            sourceLength,
444               const UChar        *target,
445               int32_t            targetLength)
446 {
447     UTRACE_ENTRY(UTRACE_UCOL_STRCOLL);
448     if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
449         UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source=%p, target=%p", coll, source, target);
450         UTRACE_DATA2(UTRACE_VERBOSE, "source string = %vh ", source, sourceLength);
451         UTRACE_DATA2(UTRACE_VERBOSE, "target string = %vh ", target, targetLength);
452     }
453 
454     UErrorCode status = U_ZERO_ERROR;
455     UCollationResult returnVal = Collator::fromUCollator(coll)->
456             compare(source, sourceLength, target, targetLength, status);
457     UTRACE_EXIT_VALUE_STATUS(returnVal, status);
458     return returnVal;
459 }
460 
461 U_CAPI UCollationResult U_EXPORT2
ucol_strcollUTF8(const UCollator * coll,const char * source,int32_t sourceLength,const char * target,int32_t targetLength,UErrorCode * status)462 ucol_strcollUTF8(
463         const UCollator *coll,
464         const char      *source,
465         int32_t         sourceLength,
466         const char      *target,
467         int32_t         targetLength,
468         UErrorCode      *status)
469 {
470     UTRACE_ENTRY(UTRACE_UCOL_STRCOLLUTF8);
471     if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
472         UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source=%p, target=%p", coll, source, target);
473         UTRACE_DATA2(UTRACE_VERBOSE, "source string = %vb ", source, sourceLength);
474         UTRACE_DATA2(UTRACE_VERBOSE, "target string = %vb ", target, targetLength);
475     }
476 
477     if (U_FAILURE(*status)) {
478         /* do nothing */
479         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status);
480         return UCOL_EQUAL;
481     }
482 
483     UCollationResult returnVal = Collator::fromUCollator(coll)->internalCompareUTF8(
484             source, sourceLength, target, targetLength, *status);
485     UTRACE_EXIT_VALUE_STATUS(returnVal, *status);
486     return returnVal;
487 }
488 
489 
490 /* convenience function for comparing strings */
491 U_CAPI UBool U_EXPORT2
ucol_greater(const UCollator * coll,const UChar * source,int32_t sourceLength,const UChar * target,int32_t targetLength)492 ucol_greater(    const    UCollator        *coll,
493         const    UChar            *source,
494         int32_t            sourceLength,
495         const    UChar            *target,
496         int32_t            targetLength)
497 {
498     return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
499         == UCOL_GREATER);
500 }
501 
502 /* convenience function for comparing strings */
503 U_CAPI UBool U_EXPORT2
ucol_greaterOrEqual(const UCollator * coll,const UChar * source,int32_t sourceLength,const UChar * target,int32_t targetLength)504 ucol_greaterOrEqual(    const    UCollator    *coll,
505             const    UChar        *source,
506             int32_t        sourceLength,
507             const    UChar        *target,
508             int32_t        targetLength)
509 {
510     return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
511         != UCOL_LESS);
512 }
513 
514 /* convenience function for comparing strings */
515 U_CAPI UBool U_EXPORT2
ucol_equal(const UCollator * coll,const UChar * source,int32_t sourceLength,const UChar * target,int32_t targetLength)516 ucol_equal(        const    UCollator        *coll,
517             const    UChar            *source,
518             int32_t            sourceLength,
519             const    UChar            *target,
520             int32_t            targetLength)
521 {
522     return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
523         == UCOL_EQUAL);
524 }
525 
526 U_CAPI void U_EXPORT2
ucol_getUCAVersion(const UCollator * coll,UVersionInfo info)527 ucol_getUCAVersion(const UCollator* coll, UVersionInfo info) {
528     const Collator *c = Collator::fromUCollator(coll);
529     if(c != NULL) {
530         UVersionInfo v;
531         c->getVersion(v);
532         // Note: This is tied to how the current implementation encodes the UCA version
533         // in the overall getVersion().
534         // Alternatively, we could load the root collator and get at lower-level data from there.
535         // Either way, it will reflect the input collator's UCA version only
536         // if it is a known implementation.
537         // It would be cleaner to make this a virtual Collator method.
538         info[0] = v[1] >> 3;
539         info[1] = v[1] & 7;
540         info[2] = v[2] >> 6;
541         info[3] = 0;
542     }
543 }
544 
545 U_CAPI const UChar * U_EXPORT2
ucol_getRules(const UCollator * coll,int32_t * length)546 ucol_getRules(const UCollator *coll, int32_t *length) {
547     const RuleBasedCollator *rbc = RuleBasedCollator::rbcFromUCollator(coll);
548     // OK to crash if coll==NULL: We do not want to check "this" pointers.
549     if(rbc != NULL || coll == NULL) {
550         const UnicodeString &rules = rbc->getRules();
551         U_ASSERT(rules.getBuffer()[rules.length()] == 0);
552         *length = rules.length();
553         return rules.getBuffer();
554     }
555     static const UChar _NUL = 0;
556     *length = 0;
557     return &_NUL;
558 }
559 
560 U_CAPI int32_t U_EXPORT2
ucol_getRulesEx(const UCollator * coll,UColRuleOption delta,UChar * buffer,int32_t bufferLen)561 ucol_getRulesEx(const UCollator *coll, UColRuleOption delta, UChar *buffer, int32_t bufferLen) {
562     UnicodeString rules;
563     const RuleBasedCollator *rbc = RuleBasedCollator::rbcFromUCollator(coll);
564     if(rbc != NULL || coll == NULL) {
565         rbc->getRules(delta, rules);
566     }
567     if(buffer != NULL && bufferLen > 0) {
568         UErrorCode errorCode = U_ZERO_ERROR;
569         return rules.extract(buffer, bufferLen, errorCode);
570     } else {
571         return rules.length();
572     }
573 }
574 
575 U_CAPI const char * U_EXPORT2
ucol_getLocale(const UCollator * coll,ULocDataLocaleType type,UErrorCode * status)576 ucol_getLocale(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status) {
577     return ucol_getLocaleByType(coll, type, status);
578 }
579 
580 U_CAPI const char * U_EXPORT2
ucol_getLocaleByType(const UCollator * coll,ULocDataLocaleType type,UErrorCode * status)581 ucol_getLocaleByType(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status) {
582     if(U_FAILURE(*status)) {
583         return NULL;
584     }
585     UTRACE_ENTRY(UTRACE_UCOL_GETLOCALE);
586     UTRACE_DATA1(UTRACE_INFO, "coll=%p", coll);
587 
588     const char *result;
589     const RuleBasedCollator *rbc = RuleBasedCollator::rbcFromUCollator(coll);
590     if(rbc == NULL && coll != NULL) {
591         *status = U_UNSUPPORTED_ERROR;
592         result = NULL;
593     } else {
594         result = rbc->internalGetLocaleID(type, *status);
595     }
596 
597     UTRACE_DATA1(UTRACE_INFO, "result = %s", result);
598     UTRACE_EXIT_STATUS(*status);
599     return result;
600 }
601 
602 U_CAPI USet * U_EXPORT2
ucol_getTailoredSet(const UCollator * coll,UErrorCode * status)603 ucol_getTailoredSet(const UCollator *coll, UErrorCode *status) {
604     if(U_FAILURE(*status)) {
605         return NULL;
606     }
607     UnicodeSet *set = Collator::fromUCollator(coll)->getTailoredSet(*status);
608     if(U_FAILURE(*status)) {
609         delete set;
610         return NULL;
611     }
612     return set->toUSet();
613 }
614 
615 U_CAPI UBool U_EXPORT2
ucol_equals(const UCollator * source,const UCollator * target)616 ucol_equals(const UCollator *source, const UCollator *target) {
617     return source == target ||
618         (*Collator::fromUCollator(source)) == (*Collator::fromUCollator(target));
619 }
620 
621 #endif /* #if !UCONFIG_NO_COLLATION */
622