628 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			628 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
| // © 2016 and later: Unicode, Inc. and others.
 | |
| // License & terms of use: http://www.unicode.org/copyright.html
 | |
| /*
 | |
| *******************************************************************************
 | |
| *   Copyright (C) 1996-2015, International Business Machines
 | |
| *   Corporation and others.  All Rights Reserved.
 | |
| *******************************************************************************
 | |
| *   file name:  ucol.cpp
 | |
| *   encoding:   UTF-8
 | |
| *   tab size:   8 (not used)
 | |
| *   indentation:4
 | |
| *
 | |
| * Modification history
 | |
| * Date        Name      Comments
 | |
| * 1996-1999   various members of ICU team maintained C API for collation framework
 | |
| * 02/16/2001  synwee    Added internal method getPrevSpecialCE
 | |
| * 03/01/2001  synwee    Added maxexpansion functionality.
 | |
| * 03/16/2001  weiv      Collation framework is rewritten in C and made UCA compliant
 | |
| * 2012-2014   markus    Rewritten in C++ again.
 | |
| */
 | |
| 
 | |
| #include "unicode/utypes.h"
 | |
| 
 | |
| #if !UCONFIG_NO_COLLATION
 | |
| 
 | |
| #include "unicode/coll.h"
 | |
| #include "unicode/tblcoll.h"
 | |
| #include "unicode/bytestream.h"
 | |
| #include "unicode/coleitr.h"
 | |
| #include "unicode/ucoleitr.h"
 | |
| #include "unicode/ustring.h"
 | |
| #include "cmemory.h"
 | |
| #include "collation.h"
 | |
| #include "cstring.h"
 | |
| #include "putilimp.h"
 | |
| #include "uassert.h"
 | |
| #include "utracimp.h"
 | |
| 
 | |
| U_NAMESPACE_USE
 | |
| 
 | |
| U_CAPI UCollator* U_EXPORT2
 | |
| ucol_openBinary(const uint8_t *bin, int32_t length,
 | |
|                 const UCollator *base,
 | |
|                 UErrorCode *status)
 | |
| {
 | |
|     if(U_FAILURE(*status)) { return NULL; }
 | |
|     RuleBasedCollator *coll = new RuleBasedCollator(
 | |
|             bin, length,
 | |
|             RuleBasedCollator::rbcFromUCollator(base),
 | |
|             *status);
 | |
|     if(coll == NULL) {
 | |
|         *status = U_MEMORY_ALLOCATION_ERROR;
 | |
|         return NULL;
 | |
|     }
 | |
|     if(U_FAILURE(*status)) {
 | |
|         delete coll;
 | |
|         return NULL;
 | |
|     }
 | |
|     return coll->toUCollator();
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| ucol_cloneBinary(const UCollator *coll,
 | |
|                  uint8_t *buffer, int32_t capacity,
 | |
|                  UErrorCode *status)
 | |
| {
 | |
|     if(U_FAILURE(*status)) {
 | |
|         return 0;
 | |
|     }
 | |
|     const RuleBasedCollator *rbc = RuleBasedCollator::rbcFromUCollator(coll);
 | |
|     if(rbc == NULL && coll != NULL) {
 | |
|         *status = U_UNSUPPORTED_ERROR;
 | |
|         return 0;
 | |
|     }
 | |
|     return rbc->cloneBinary(buffer, capacity, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI UCollator* U_EXPORT2
 | |
| ucol_safeClone(const UCollator *coll, void * /*stackBuffer*/, int32_t * pBufferSize, UErrorCode *status)
 | |
| {
 | |
|     if (status == NULL || U_FAILURE(*status)){
 | |
|         return NULL;
 | |
|     }
 | |
|     if (coll == NULL) {
 | |
|        *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return NULL;
 | |
|     }
 | |
|     if (pBufferSize != NULL) {
 | |
|         int32_t inputSize = *pBufferSize;
 | |
|         *pBufferSize = 1;
 | |
|         if (inputSize == 0) {
 | |
|             return NULL;  // preflighting for deprecated functionality
 | |
|         }
 | |
|     }
 | |
|     Collator *newColl = Collator::fromUCollator(coll)->clone();
 | |
|     if (newColl == NULL) {
 | |
|         *status = U_MEMORY_ALLOCATION_ERROR;
 | |
|         return nullptr;
 | |
|     } else if (pBufferSize != NULL) {
 | |
|         *status = U_SAFECLONE_ALLOCATED_WARNING;
 | |
|     }
 | |
|     return newColl->toUCollator();
 | |
| }
 | |
| 
 | |
| U_CAPI UCollator* U_EXPORT2
 | |
| ucol_clone(const UCollator *coll, UErrorCode *status)
 | |
| {
 | |
|     return ucol_safeClone(coll, nullptr, nullptr, status);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| ucol_close(UCollator *coll)
 | |
| {
 | |
|     UTRACE_ENTRY_OC(UTRACE_UCOL_CLOSE);
 | |
|     UTRACE_DATA1(UTRACE_INFO, "coll = %p", coll);
 | |
|     if(coll != NULL) {
 | |
|         delete Collator::fromUCollator(coll);
 | |
|     }
 | |
|     UTRACE_EXIT();
 | |
| }
 | |
| 
 | |
| 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) {
 | |
|     /* check arguments */
 | |
|     if( src1==NULL || src1Length<-1 || src1Length==0 || (src1Length>0 && src1[src1Length-1]!=0) ||
 | |
|         src2==NULL || src2Length<-1 || src2Length==0 || (src2Length>0 && src2[src2Length-1]!=0) ||
 | |
|         destCapacity<0 || (destCapacity>0 && dest==NULL)
 | |
|     ) {
 | |
|         /* error, attempt to write a zero byte and return 0 */
 | |
|         if(dest!=NULL && destCapacity>0) {
 | |
|             *dest=0;
 | |
|         }
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     /* check lengths and capacity */
 | |
|     if(src1Length<0) {
 | |
|         src1Length=(int32_t)uprv_strlen((const char *)src1)+1;
 | |
|     }
 | |
|     if(src2Length<0) {
 | |
|         src2Length=(int32_t)uprv_strlen((const char *)src2)+1;
 | |
|     }
 | |
| 
 | |
|     int32_t destLength=src1Length+src2Length;
 | |
|     if(destLength>destCapacity) {
 | |
|         /* the merged sort key does not fit into the destination */
 | |
|         return destLength;
 | |
|     }
 | |
| 
 | |
|     /* merge the sort keys with the same number of levels */
 | |
|     uint8_t *p=dest;
 | |
|     for(;;) {
 | |
|         /* copy level from src1 not including 00 or 01 */
 | |
|         uint8_t b;
 | |
|         while((b=*src1)>=2) {
 | |
|             ++src1;
 | |
|             *p++=b;
 | |
|         }
 | |
| 
 | |
|         /* add a 02 merge separator */
 | |
|         *p++=2;
 | |
| 
 | |
|         /* copy level from src2 not including 00 or 01 */
 | |
|         while((b=*src2)>=2) {
 | |
|             ++src2;
 | |
|             *p++=b;
 | |
|         }
 | |
| 
 | |
|         /* if both sort keys have another level, then add a 01 level separator and continue */
 | |
|         if(*src1==1 && *src2==1) {
 | |
|             ++src1;
 | |
|             ++src2;
 | |
|             *p++=1;
 | |
|         } else {
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * here, at least one sort key is finished now, but the other one
 | |
|      * might have some contents left from containing more levels;
 | |
|      * that contents is just appended to the result
 | |
|      */
 | |
|     if(*src1!=0) {
 | |
|         /* src1 is not finished, therefore *src2==0, and src1 is appended */
 | |
|         src2=src1;
 | |
|     }
 | |
|     /* append src2, "the other, unfinished sort key" */
 | |
|     while((*p++=*src2++)!=0) {}
 | |
| 
 | |
|     /* the actual length might be less than destLength if either sort key contained illegally embedded zero bytes */
 | |
|     return (int32_t)(p-dest);
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| ucol_getSortKey(const    UCollator    *coll,
 | |
|         const    UChar        *source,
 | |
|         int32_t        sourceLength,
 | |
|         uint8_t        *result,
 | |
|         int32_t        resultLength)
 | |
| {
 | |
|     UTRACE_ENTRY(UTRACE_UCOL_GET_SORTKEY);
 | |
|     if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
 | |
|         UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source string = %vh ", coll, source,
 | |
|             ((sourceLength==-1 && source!=NULL) ? u_strlen(source) : sourceLength));
 | |
|     }
 | |
| 
 | |
|     int32_t keySize = Collator::fromUCollator(coll)->
 | |
|             getSortKey(source, sourceLength, result, resultLength);
 | |
| 
 | |
|     UTRACE_DATA2(UTRACE_VERBOSE, "Sort Key = %vb", result, keySize);
 | |
|     UTRACE_EXIT_VALUE(keySize);
 | |
|     return keySize;
 | |
| }
 | |
| 
 | |
| 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)
 | |
| {
 | |
|     /* error checking */
 | |
|     if(status==NULL || U_FAILURE(*status)) {
 | |
|         return 0;
 | |
|     }
 | |
|     UTRACE_ENTRY(UTRACE_UCOL_NEXTSORTKEYPART);
 | |
|     UTRACE_DATA6(UTRACE_VERBOSE, "coll=%p, iter=%p, state=%d %d, dest=%p, count=%d",
 | |
|                   coll, iter, state[0], state[1], dest, count);
 | |
| 
 | |
|     int32_t i = Collator::fromUCollator(coll)->
 | |
|             internalNextSortKeyPart(iter, state, dest, count, *status);
 | |
| 
 | |
|     // Return number of meaningful sortkey bytes.
 | |
|     UTRACE_DATA4(UTRACE_VERBOSE, "dest = %vb, state=%d %d",
 | |
|                   dest,i, state[0], state[1]);
 | |
|     UTRACE_EXIT_VALUE_STATUS(i, *status);
 | |
|     return i;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Produce a bound for a given sortkey and a number of levels.
 | |
|  */
 | |
| 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)
 | |
| {
 | |
|     // consistency checks
 | |
|     if(status == NULL || U_FAILURE(*status)) {
 | |
|         return 0;
 | |
|     }
 | |
|     if(source == NULL) {
 | |
|         *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     int32_t sourceIndex = 0;
 | |
|     // Scan the string until we skip enough of the key OR reach the end of the key
 | |
|     do {
 | |
|         sourceIndex++;
 | |
|         if(source[sourceIndex] == Collation::LEVEL_SEPARATOR_BYTE) {
 | |
|             noOfLevels--;
 | |
|         }
 | |
|     } while (noOfLevels > 0
 | |
|         && (source[sourceIndex] != 0 || sourceIndex < sourceLength));
 | |
| 
 | |
|     if((source[sourceIndex] == 0 || sourceIndex == sourceLength)
 | |
|         && noOfLevels > 0) {
 | |
|             *status = U_SORT_KEY_TOO_SHORT_WARNING;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     // READ ME: this code assumes that the values for boundType
 | |
|     // enum will not changes. They are set so that the enum value
 | |
|     // corresponds to the number of extra bytes each bound type
 | |
|     // needs.
 | |
|     if(result != NULL && resultLength >= sourceIndex+boundType) {
 | |
|         uprv_memcpy(result, source, sourceIndex);
 | |
|         switch(boundType) {
 | |
|             // Lower bound just gets terminated. No extra bytes
 | |
|         case UCOL_BOUND_LOWER: // = 0
 | |
|             break;
 | |
|             // Upper bound needs one extra byte
 | |
|         case UCOL_BOUND_UPPER: // = 1
 | |
|             result[sourceIndex++] = 2;
 | |
|             break;
 | |
|             // Upper long bound needs two extra bytes
 | |
|         case UCOL_BOUND_UPPER_LONG: // = 2
 | |
|             result[sourceIndex++] = 0xFF;
 | |
|             result[sourceIndex++] = 0xFF;
 | |
|             break;
 | |
|         default:
 | |
|             *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|             return 0;
 | |
|         }
 | |
|         result[sourceIndex++] = 0;
 | |
| 
 | |
|         return sourceIndex;
 | |
|     } else {
 | |
|         return sourceIndex+boundType+1;
 | |
|     }
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| ucol_setMaxVariable(UCollator *coll, UColReorderCode group, UErrorCode *pErrorCode) {
 | |
|     if(U_FAILURE(*pErrorCode)) { return; }
 | |
|     Collator::fromUCollator(coll)->setMaxVariable(group, *pErrorCode);
 | |
| }
 | |
| 
 | |
| U_CAPI UColReorderCode U_EXPORT2
 | |
| ucol_getMaxVariable(const UCollator *coll) {
 | |
|     return Collator::fromUCollator(coll)->getMaxVariable();
 | |
| }
 | |
| 
 | |
| U_CAPI uint32_t  U_EXPORT2
 | |
| ucol_setVariableTop(UCollator *coll, const UChar *varTop, int32_t len, UErrorCode *status) {
 | |
|     if(U_FAILURE(*status) || coll == NULL) {
 | |
|         return 0;
 | |
|     }
 | |
|     return Collator::fromUCollator(coll)->setVariableTop(varTop, len, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI uint32_t U_EXPORT2 ucol_getVariableTop(const UCollator *coll, UErrorCode *status) {
 | |
|     if(U_FAILURE(*status) || coll == NULL) {
 | |
|         return 0;
 | |
|     }
 | |
|     return Collator::fromUCollator(coll)->getVariableTop(*status);
 | |
| }
 | |
| 
 | |
| U_CAPI void  U_EXPORT2
 | |
| ucol_restoreVariableTop(UCollator *coll, const uint32_t varTop, UErrorCode *status) {
 | |
|     if(U_FAILURE(*status) || coll == NULL) {
 | |
|         return;
 | |
|     }
 | |
|     Collator::fromUCollator(coll)->setVariableTop(varTop, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI void  U_EXPORT2
 | |
| ucol_setAttribute(UCollator *coll, UColAttribute attr, UColAttributeValue value, UErrorCode *status) {
 | |
|     if(U_FAILURE(*status) || coll == NULL) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     Collator::fromUCollator(coll)->setAttribute(attr, value, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI UColAttributeValue  U_EXPORT2
 | |
| ucol_getAttribute(const UCollator *coll, UColAttribute attr, UErrorCode *status) {
 | |
|     if(U_FAILURE(*status) || coll == NULL) {
 | |
|       return UCOL_DEFAULT;
 | |
|     }
 | |
| 
 | |
|     return Collator::fromUCollator(coll)->getAttribute(attr, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| ucol_setStrength(    UCollator                *coll,
 | |
|             UCollationStrength        strength)
 | |
| {
 | |
|     UErrorCode status = U_ZERO_ERROR;
 | |
|     ucol_setAttribute(coll, UCOL_STRENGTH, strength, &status);
 | |
| }
 | |
| 
 | |
| U_CAPI UCollationStrength U_EXPORT2
 | |
| ucol_getStrength(const UCollator *coll)
 | |
| {
 | |
|     UErrorCode status = U_ZERO_ERROR;
 | |
|     return ucol_getAttribute(coll, UCOL_STRENGTH, &status);
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2 
 | |
| ucol_getReorderCodes(const UCollator *coll,
 | |
|                     int32_t *dest,
 | |
|                     int32_t destCapacity,
 | |
|                     UErrorCode *status) {
 | |
|     if (U_FAILURE(*status)) {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     return Collator::fromUCollator(coll)->getReorderCodes(dest, destCapacity, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2 
 | |
| ucol_setReorderCodes(UCollator* coll,
 | |
|                     const int32_t* reorderCodes,
 | |
|                     int32_t reorderCodesLength,
 | |
|                     UErrorCode *status) {
 | |
|     if (U_FAILURE(*status)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     Collator::fromUCollator(coll)->setReorderCodes(reorderCodes, reorderCodesLength, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2 
 | |
| ucol_getEquivalentReorderCodes(int32_t reorderCode,
 | |
|                     int32_t* dest,
 | |
|                     int32_t destCapacity,
 | |
|                     UErrorCode *pErrorCode) {
 | |
|     return Collator::getEquivalentReorderCodes(reorderCode, dest, destCapacity, *pErrorCode);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| ucol_getVersion(const UCollator* coll,
 | |
|                 UVersionInfo versionInfo)
 | |
| {
 | |
|     Collator::fromUCollator(coll)->getVersion(versionInfo);
 | |
| }
 | |
| 
 | |
| U_CAPI UCollationResult U_EXPORT2
 | |
| ucol_strcollIter( const UCollator    *coll,
 | |
|                  UCharIterator *sIter,
 | |
|                  UCharIterator *tIter,
 | |
|                  UErrorCode         *status)
 | |
| {
 | |
|     if(!status || U_FAILURE(*status)) {
 | |
|         return UCOL_EQUAL;
 | |
|     }
 | |
| 
 | |
|     UTRACE_ENTRY(UTRACE_UCOL_STRCOLLITER);
 | |
|     UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, sIter=%p, tIter=%p", coll, sIter, tIter);
 | |
| 
 | |
|     if(sIter == NULL || tIter == NULL || coll == NULL) {
 | |
|         *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status);
 | |
|         return UCOL_EQUAL;
 | |
|     }
 | |
| 
 | |
|     UCollationResult result = Collator::fromUCollator(coll)->compare(*sIter, *tIter, *status);
 | |
| 
 | |
|     UTRACE_EXIT_VALUE_STATUS(result, *status);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*                                                                      */
 | |
| /* ucol_strcoll     Main public API string comparison function          */
 | |
| /*                                                                      */
 | |
| U_CAPI UCollationResult U_EXPORT2
 | |
| ucol_strcoll( const UCollator    *coll,
 | |
|               const UChar        *source,
 | |
|               int32_t            sourceLength,
 | |
|               const UChar        *target,
 | |
|               int32_t            targetLength)
 | |
| {
 | |
|     UTRACE_ENTRY(UTRACE_UCOL_STRCOLL);
 | |
|     if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
 | |
|         UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source=%p, target=%p", coll, source, target);
 | |
|         UTRACE_DATA2(UTRACE_VERBOSE, "source string = %vh ", source, sourceLength);
 | |
|         UTRACE_DATA2(UTRACE_VERBOSE, "target string = %vh ", target, targetLength);
 | |
|     }
 | |
| 
 | |
|     UErrorCode status = U_ZERO_ERROR;
 | |
|     UCollationResult returnVal = Collator::fromUCollator(coll)->
 | |
|             compare(source, sourceLength, target, targetLength, status);
 | |
|     UTRACE_EXIT_VALUE_STATUS(returnVal, status);
 | |
|     return returnVal;
 | |
| }
 | |
| 
 | |
| U_CAPI UCollationResult U_EXPORT2
 | |
| ucol_strcollUTF8(
 | |
|         const UCollator *coll,
 | |
|         const char      *source,
 | |
|         int32_t         sourceLength,
 | |
|         const char      *target,
 | |
|         int32_t         targetLength,
 | |
|         UErrorCode      *status)
 | |
| {
 | |
|     UTRACE_ENTRY(UTRACE_UCOL_STRCOLLUTF8);
 | |
|     if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
 | |
|         UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source=%p, target=%p", coll, source, target);
 | |
|         UTRACE_DATA2(UTRACE_VERBOSE, "source string = %vb ", source, sourceLength);
 | |
|         UTRACE_DATA2(UTRACE_VERBOSE, "target string = %vb ", target, targetLength);
 | |
|     }
 | |
| 
 | |
|     if (U_FAILURE(*status)) {
 | |
|         /* do nothing */
 | |
|         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status);
 | |
|         return UCOL_EQUAL;
 | |
|     }
 | |
| 
 | |
|     UCollationResult returnVal = Collator::fromUCollator(coll)->internalCompareUTF8(
 | |
|             source, sourceLength, target, targetLength, *status);
 | |
|     UTRACE_EXIT_VALUE_STATUS(returnVal, *status);
 | |
|     return returnVal;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* convenience function for comparing strings */
 | |
| U_CAPI UBool U_EXPORT2
 | |
| ucol_greater(    const    UCollator        *coll,
 | |
|         const    UChar            *source,
 | |
|         int32_t            sourceLength,
 | |
|         const    UChar            *target,
 | |
|         int32_t            targetLength)
 | |
| {
 | |
|     return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
 | |
|         == UCOL_GREATER);
 | |
| }
 | |
| 
 | |
| /* convenience function for comparing strings */
 | |
| U_CAPI UBool U_EXPORT2
 | |
| ucol_greaterOrEqual(    const    UCollator    *coll,
 | |
|             const    UChar        *source,
 | |
|             int32_t        sourceLength,
 | |
|             const    UChar        *target,
 | |
|             int32_t        targetLength)
 | |
| {
 | |
|     return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
 | |
|         != UCOL_LESS);
 | |
| }
 | |
| 
 | |
| /* convenience function for comparing strings */
 | |
| U_CAPI UBool U_EXPORT2
 | |
| ucol_equal(        const    UCollator        *coll,
 | |
|             const    UChar            *source,
 | |
|             int32_t            sourceLength,
 | |
|             const    UChar            *target,
 | |
|             int32_t            targetLength)
 | |
| {
 | |
|     return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
 | |
|         == UCOL_EQUAL);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| ucol_getUCAVersion(const UCollator* coll, UVersionInfo info) {
 | |
|     const Collator *c = Collator::fromUCollator(coll);
 | |
|     if(c != NULL) {
 | |
|         UVersionInfo v;
 | |
|         c->getVersion(v);
 | |
|         // Note: This is tied to how the current implementation encodes the UCA version
 | |
|         // in the overall getVersion().
 | |
|         // Alternatively, we could load the root collator and get at lower-level data from there.
 | |
|         // Either way, it will reflect the input collator's UCA version only
 | |
|         // if it is a known implementation.
 | |
|         // It would be cleaner to make this a virtual Collator method.
 | |
|         info[0] = v[1] >> 3;
 | |
|         info[1] = v[1] & 7;
 | |
|         info[2] = v[2] >> 6;
 | |
|         info[3] = 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| U_CAPI const UChar * U_EXPORT2
 | |
| ucol_getRules(const UCollator *coll, int32_t *length) {
 | |
|     const RuleBasedCollator *rbc = RuleBasedCollator::rbcFromUCollator(coll);
 | |
|     // OK to crash if coll==NULL: We do not want to check "this" pointers.
 | |
|     if(rbc != NULL || coll == NULL) {
 | |
|         const UnicodeString &rules = rbc->getRules();
 | |
|         U_ASSERT(rules.getBuffer()[rules.length()] == 0);
 | |
|         *length = rules.length();
 | |
|         return rules.getBuffer();
 | |
|     }
 | |
|     static const UChar _NUL = 0;
 | |
|     *length = 0;
 | |
|     return &_NUL;
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| ucol_getRulesEx(const UCollator *coll, UColRuleOption delta, UChar *buffer, int32_t bufferLen) {
 | |
|     UnicodeString rules;
 | |
|     const RuleBasedCollator *rbc = RuleBasedCollator::rbcFromUCollator(coll);
 | |
|     if(rbc != NULL || coll == NULL) {
 | |
|         rbc->getRules(delta, rules);
 | |
|     }
 | |
|     if(buffer != NULL && bufferLen > 0) {
 | |
|         UErrorCode errorCode = U_ZERO_ERROR;
 | |
|         return rules.extract(buffer, bufferLen, errorCode);
 | |
|     } else {
 | |
|         return rules.length();
 | |
|     }
 | |
| }
 | |
| 
 | |
| U_CAPI const char * U_EXPORT2
 | |
| ucol_getLocale(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status) {
 | |
|     return ucol_getLocaleByType(coll, type, status);
 | |
| }
 | |
| 
 | |
| U_CAPI const char * U_EXPORT2
 | |
| ucol_getLocaleByType(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status) {
 | |
|     if(U_FAILURE(*status)) {
 | |
|         return NULL;
 | |
|     }
 | |
|     UTRACE_ENTRY(UTRACE_UCOL_GETLOCALE);
 | |
|     UTRACE_DATA1(UTRACE_INFO, "coll=%p", coll);
 | |
| 
 | |
|     const char *result;
 | |
|     const RuleBasedCollator *rbc = RuleBasedCollator::rbcFromUCollator(coll);
 | |
|     if(rbc == NULL && coll != NULL) {
 | |
|         *status = U_UNSUPPORTED_ERROR;
 | |
|         result = NULL;
 | |
|     } else {
 | |
|         result = rbc->internalGetLocaleID(type, *status);
 | |
|     }
 | |
| 
 | |
|     UTRACE_DATA1(UTRACE_INFO, "result = %s", result);
 | |
|     UTRACE_EXIT_STATUS(*status);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| U_CAPI USet * U_EXPORT2
 | |
| ucol_getTailoredSet(const UCollator *coll, UErrorCode *status) {
 | |
|     if(U_FAILURE(*status)) {
 | |
|         return NULL;
 | |
|     }
 | |
|     UnicodeSet *set = Collator::fromUCollator(coll)->getTailoredSet(*status);
 | |
|     if(U_FAILURE(*status)) {
 | |
|         delete set;
 | |
|         return NULL;
 | |
|     }
 | |
|     return set->toUSet();
 | |
| }
 | |
| 
 | |
| U_CAPI UBool U_EXPORT2
 | |
| ucol_equals(const UCollator *source, const UCollator *target) {
 | |
|     return source == target ||
 | |
|         (*Collator::fromUCollator(source)) == (*Collator::fromUCollator(target));
 | |
| }
 | |
| 
 | |
| #endif /* #if !UCONFIG_NO_COLLATION */
 |