michael@0: /* michael@0: ****************************************************************************** michael@0: * Copyright (C) 2001-2011, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: ****************************************************************************** michael@0: * michael@0: * File ucoleitr.cpp michael@0: * michael@0: * Modification History: michael@0: * michael@0: * Date Name Description michael@0: * 02/15/2001 synwee Modified all methods to process its own function michael@0: * instead of calling the equivalent c++ api (coleitr.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/ucoleitr.h" michael@0: #include "unicode/ustring.h" michael@0: #include "unicode/sortkey.h" michael@0: #include "unicode/uobject.h" michael@0: #include "ucol_imp.h" michael@0: #include "cmemory.h" michael@0: michael@0: U_NAMESPACE_USE michael@0: michael@0: #define BUFFER_LENGTH 100 michael@0: michael@0: #define DEFAULT_BUFFER_SIZE 16 michael@0: #define BUFFER_GROW 8 michael@0: michael@0: #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) michael@0: michael@0: #define ARRAY_COPY(dst, src, count) uprv_memcpy((void *) (dst), (void *) (src), (count) * sizeof (src)[0]) michael@0: michael@0: #define NEW_ARRAY(type, count) (type *) uprv_malloc((count) * sizeof(type)) michael@0: michael@0: #define GROW_ARRAY(array, newSize) uprv_realloc((void *) (array), (newSize) * sizeof (array)[0]) michael@0: michael@0: #define DELETE_ARRAY(array) uprv_free((void *) (array)) michael@0: michael@0: typedef struct icu::collIterate collIterator; michael@0: michael@0: struct RCEI michael@0: { michael@0: uint32_t ce; michael@0: int32_t low; michael@0: int32_t high; michael@0: }; michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: struct RCEBuffer michael@0: { michael@0: RCEI defaultBuffer[DEFAULT_BUFFER_SIZE]; michael@0: RCEI *buffer; michael@0: int32_t bufferIndex; michael@0: int32_t bufferSize; michael@0: michael@0: RCEBuffer(); michael@0: ~RCEBuffer(); michael@0: michael@0: UBool empty() const; michael@0: void put(uint32_t ce, int32_t ixLow, int32_t ixHigh); michael@0: const RCEI *get(); michael@0: }; michael@0: michael@0: RCEBuffer::RCEBuffer() michael@0: { michael@0: buffer = defaultBuffer; michael@0: bufferIndex = 0; michael@0: bufferSize = DEFAULT_BUFFER_SIZE; michael@0: } michael@0: michael@0: RCEBuffer::~RCEBuffer() michael@0: { michael@0: if (buffer != defaultBuffer) { michael@0: DELETE_ARRAY(buffer); michael@0: } michael@0: } michael@0: michael@0: UBool RCEBuffer::empty() const michael@0: { michael@0: return bufferIndex <= 0; michael@0: } michael@0: michael@0: void RCEBuffer::put(uint32_t ce, int32_t ixLow, int32_t ixHigh) michael@0: { michael@0: if (bufferIndex >= bufferSize) { michael@0: RCEI *newBuffer = NEW_ARRAY(RCEI, bufferSize + BUFFER_GROW); michael@0: michael@0: ARRAY_COPY(newBuffer, buffer, bufferSize); michael@0: michael@0: if (buffer != defaultBuffer) { michael@0: DELETE_ARRAY(buffer); michael@0: } michael@0: michael@0: buffer = newBuffer; michael@0: bufferSize += BUFFER_GROW; michael@0: } michael@0: michael@0: buffer[bufferIndex].ce = ce; michael@0: buffer[bufferIndex].low = ixLow; michael@0: buffer[bufferIndex].high = ixHigh; michael@0: michael@0: bufferIndex += 1; michael@0: } michael@0: michael@0: const RCEI *RCEBuffer::get() michael@0: { michael@0: if (bufferIndex > 0) { michael@0: return &buffer[--bufferIndex]; michael@0: } michael@0: michael@0: return NULL; michael@0: } michael@0: michael@0: struct PCEI michael@0: { michael@0: uint64_t ce; michael@0: int32_t low; michael@0: int32_t high; michael@0: }; michael@0: michael@0: struct PCEBuffer michael@0: { michael@0: PCEI defaultBuffer[DEFAULT_BUFFER_SIZE]; michael@0: PCEI *buffer; michael@0: int32_t bufferIndex; michael@0: int32_t bufferSize; michael@0: michael@0: PCEBuffer(); michael@0: ~PCEBuffer(); michael@0: michael@0: void reset(); michael@0: UBool empty() const; michael@0: void put(uint64_t ce, int32_t ixLow, int32_t ixHigh); michael@0: const PCEI *get(); michael@0: }; michael@0: michael@0: PCEBuffer::PCEBuffer() michael@0: { michael@0: buffer = defaultBuffer; michael@0: bufferIndex = 0; michael@0: bufferSize = DEFAULT_BUFFER_SIZE; michael@0: } michael@0: michael@0: PCEBuffer::~PCEBuffer() michael@0: { michael@0: if (buffer != defaultBuffer) { michael@0: DELETE_ARRAY(buffer); michael@0: } michael@0: } michael@0: michael@0: void PCEBuffer::reset() michael@0: { michael@0: bufferIndex = 0; michael@0: } michael@0: michael@0: UBool PCEBuffer::empty() const michael@0: { michael@0: return bufferIndex <= 0; michael@0: } michael@0: michael@0: void PCEBuffer::put(uint64_t ce, int32_t ixLow, int32_t ixHigh) michael@0: { michael@0: if (bufferIndex >= bufferSize) { michael@0: PCEI *newBuffer = NEW_ARRAY(PCEI, bufferSize + BUFFER_GROW); michael@0: michael@0: ARRAY_COPY(newBuffer, buffer, bufferSize); michael@0: michael@0: if (buffer != defaultBuffer) { michael@0: DELETE_ARRAY(buffer); michael@0: } michael@0: michael@0: buffer = newBuffer; michael@0: bufferSize += BUFFER_GROW; michael@0: } michael@0: michael@0: buffer[bufferIndex].ce = ce; michael@0: buffer[bufferIndex].low = ixLow; michael@0: buffer[bufferIndex].high = ixHigh; michael@0: michael@0: bufferIndex += 1; michael@0: } michael@0: michael@0: const PCEI *PCEBuffer::get() michael@0: { michael@0: if (bufferIndex > 0) { michael@0: return &buffer[--bufferIndex]; michael@0: } michael@0: michael@0: return NULL; michael@0: } michael@0: michael@0: /* michael@0: * This inherits from UObject so that michael@0: * it can be allocated by new and the michael@0: * constructor for PCEBuffer is called. michael@0: */ michael@0: struct UCollationPCE : public UObject michael@0: { michael@0: PCEBuffer pceBuffer; michael@0: UCollationStrength strength; michael@0: UBool toShift; michael@0: UBool isShifted; michael@0: uint32_t variableTop; michael@0: michael@0: UCollationPCE(UCollationElements *elems); michael@0: ~UCollationPCE(); michael@0: michael@0: void init(const UCollator *coll); michael@0: michael@0: virtual UClassID getDynamicClassID() const; michael@0: static UClassID getStaticClassID(); michael@0: }; michael@0: michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UCollationPCE) michael@0: michael@0: UCollationPCE::UCollationPCE(UCollationElements *elems) michael@0: { michael@0: init(elems->iteratordata_.coll); michael@0: } michael@0: michael@0: void UCollationPCE::init(const UCollator *coll) michael@0: { michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: michael@0: strength = ucol_getStrength(coll); michael@0: toShift = ucol_getAttribute(coll, UCOL_ALTERNATE_HANDLING, &status) == UCOL_SHIFTED; michael@0: isShifted = FALSE; michael@0: variableTop = coll->variableTopValue << 16; michael@0: } michael@0: michael@0: UCollationPCE::~UCollationPCE() michael@0: { michael@0: // nothing to do michael@0: } michael@0: michael@0: michael@0: U_NAMESPACE_END michael@0: michael@0: michael@0: inline uint64_t processCE(UCollationElements *elems, uint32_t ce) michael@0: { michael@0: uint64_t primary = 0, secondary = 0, tertiary = 0, quaternary = 0; michael@0: michael@0: // This is clean, but somewhat slow... michael@0: // We could apply the mask to ce and then michael@0: // just get all three orders... michael@0: switch(elems->pce->strength) { michael@0: default: michael@0: tertiary = ucol_tertiaryOrder(ce); michael@0: /* note fall-through */ michael@0: michael@0: case UCOL_SECONDARY: michael@0: secondary = ucol_secondaryOrder(ce); michael@0: /* note fall-through */ michael@0: michael@0: case UCOL_PRIMARY: michael@0: primary = ucol_primaryOrder(ce); michael@0: } michael@0: michael@0: // **** This should probably handle continuations too. **** michael@0: // **** That means that we need 24 bits for the primary **** michael@0: // **** instead of the 16 that we're currently using. **** michael@0: // **** So we can lay out the 64 bits as: 24.12.12.16. **** michael@0: // **** Another complication with continuations is that **** michael@0: // **** the *second* CE is marked as a continuation, so **** michael@0: // **** we always have to peek ahead to know how long **** michael@0: // **** the primary is... **** michael@0: if ((elems->pce->toShift && elems->pce->variableTop > ce && primary != 0) michael@0: || (elems->pce->isShifted && primary == 0)) { michael@0: michael@0: if (primary == 0) { michael@0: return UCOL_IGNORABLE; michael@0: } michael@0: michael@0: if (elems->pce->strength >= UCOL_QUATERNARY) { michael@0: quaternary = primary; michael@0: } michael@0: michael@0: primary = secondary = tertiary = 0; michael@0: elems->pce->isShifted = TRUE; michael@0: } else { michael@0: if (elems->pce->strength >= UCOL_QUATERNARY) { michael@0: quaternary = 0xFFFF; michael@0: } michael@0: michael@0: elems->pce->isShifted = FALSE; michael@0: } michael@0: michael@0: return primary << 48 | secondary << 32 | tertiary << 16 | quaternary; michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: uprv_init_pce(const UCollationElements *elems) michael@0: { michael@0: if (elems->pce != NULL) { michael@0: elems->pce->init(elems->iteratordata_.coll); michael@0: } michael@0: } michael@0: michael@0: michael@0: michael@0: /* public methods ---------------------------------------------------- */ michael@0: michael@0: U_CAPI UCollationElements* U_EXPORT2 michael@0: ucol_openElements(const UCollator *coll, michael@0: const UChar *text, michael@0: int32_t textLength, michael@0: UErrorCode *status) michael@0: { michael@0: if (U_FAILURE(*status)) { michael@0: return NULL; michael@0: } michael@0: michael@0: UCollationElements *result = new UCollationElements; michael@0: if (result == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: michael@0: result->reset_ = TRUE; michael@0: result->isWritable = FALSE; michael@0: result->pce = NULL; michael@0: michael@0: if (text == NULL) { michael@0: textLength = 0; michael@0: } michael@0: uprv_init_collIterate(coll, text, textLength, &result->iteratordata_, status); michael@0: michael@0: return result; michael@0: } michael@0: michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: ucol_closeElements(UCollationElements *elems) michael@0: { michael@0: if (elems != NULL) { michael@0: collIterate *ci = &elems->iteratordata_; michael@0: michael@0: if (ci->extendCEs) { michael@0: uprv_free(ci->extendCEs); michael@0: } michael@0: michael@0: if (ci->offsetBuffer) { michael@0: uprv_free(ci->offsetBuffer); michael@0: } michael@0: michael@0: if (elems->isWritable && elems->iteratordata_.string != NULL) michael@0: { michael@0: uprv_free((UChar *)elems->iteratordata_.string); michael@0: } michael@0: michael@0: if (elems->pce != NULL) { michael@0: delete elems->pce; michael@0: } michael@0: michael@0: delete elems; michael@0: } michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: ucol_reset(UCollationElements *elems) michael@0: { michael@0: collIterate *ci = &(elems->iteratordata_); michael@0: elems->reset_ = TRUE; michael@0: ci->pos = ci->string; michael@0: if ((ci->flags & UCOL_ITER_HASLEN) == 0 || ci->endp == NULL) { michael@0: ci->endp = ci->string + u_strlen(ci->string); michael@0: } michael@0: ci->CEpos = ci->toReturn = ci->CEs; michael@0: ci->flags = (ci->flags & UCOL_FORCE_HAN_IMPLICIT) | UCOL_ITER_HASLEN; michael@0: if (ci->coll->normalizationMode == UCOL_ON) { michael@0: ci->flags |= UCOL_ITER_NORM; michael@0: } michael@0: michael@0: ci->writableBuffer.remove(); michael@0: ci->fcdPosition = NULL; michael@0: michael@0: //ci->offsetReturn = ci->offsetStore = NULL; michael@0: ci->offsetRepeatCount = ci->offsetRepeatValue = 0; michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: ucol_forceHanImplicit(UCollationElements *elems, UErrorCode *status) michael@0: { michael@0: if (U_FAILURE(*status)) { michael@0: return; michael@0: } michael@0: michael@0: if (elems == NULL) { michael@0: *status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return; michael@0: } michael@0: michael@0: elems->iteratordata_.flags |= UCOL_FORCE_HAN_IMPLICIT; michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: ucol_next(UCollationElements *elems, michael@0: UErrorCode *status) michael@0: { michael@0: int32_t result; michael@0: if (U_FAILURE(*status)) { michael@0: return UCOL_NULLORDER; michael@0: } michael@0: michael@0: elems->reset_ = FALSE; michael@0: michael@0: result = (int32_t)ucol_getNextCE(elems->iteratordata_.coll, michael@0: &elems->iteratordata_, michael@0: status); michael@0: michael@0: if (result == UCOL_NO_MORE_CES) { michael@0: result = UCOL_NULLORDER; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: U_CAPI int64_t U_EXPORT2 michael@0: ucol_nextProcessed(UCollationElements *elems, michael@0: int32_t *ixLow, michael@0: int32_t *ixHigh, michael@0: UErrorCode *status) michael@0: { michael@0: const UCollator *coll = elems->iteratordata_.coll; michael@0: int64_t result = UCOL_IGNORABLE; michael@0: uint32_t low = 0, high = 0; michael@0: michael@0: if (U_FAILURE(*status)) { michael@0: return UCOL_PROCESSED_NULLORDER; michael@0: } michael@0: michael@0: if (elems->pce == NULL) { michael@0: elems->pce = new UCollationPCE(elems); michael@0: } else { michael@0: elems->pce->pceBuffer.reset(); michael@0: } michael@0: michael@0: elems->reset_ = FALSE; michael@0: michael@0: do { michael@0: low = ucol_getOffset(elems); michael@0: uint32_t ce = (uint32_t) ucol_getNextCE(coll, &elems->iteratordata_, status); michael@0: high = ucol_getOffset(elems); michael@0: michael@0: if (ce == UCOL_NO_MORE_CES) { michael@0: result = UCOL_PROCESSED_NULLORDER; michael@0: break; michael@0: } michael@0: michael@0: result = processCE(elems, ce); michael@0: } while (result == UCOL_IGNORABLE); michael@0: michael@0: if (ixLow != NULL) { michael@0: *ixLow = low; michael@0: } michael@0: michael@0: if (ixHigh != NULL) { michael@0: *ixHigh = high; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: ucol_previous(UCollationElements *elems, michael@0: UErrorCode *status) michael@0: { michael@0: if(U_FAILURE(*status)) { michael@0: return UCOL_NULLORDER; michael@0: } michael@0: else michael@0: { michael@0: int32_t result; michael@0: michael@0: if (elems->reset_ && (elems->iteratordata_.pos == elems->iteratordata_.string)) { michael@0: if (elems->iteratordata_.endp == NULL) { michael@0: elems->iteratordata_.endp = elems->iteratordata_.string + michael@0: u_strlen(elems->iteratordata_.string); michael@0: elems->iteratordata_.flags |= UCOL_ITER_HASLEN; michael@0: } michael@0: elems->iteratordata_.pos = elems->iteratordata_.endp; michael@0: elems->iteratordata_.fcdPosition = elems->iteratordata_.endp; michael@0: } michael@0: michael@0: elems->reset_ = FALSE; michael@0: michael@0: result = (int32_t)ucol_getPrevCE(elems->iteratordata_.coll, michael@0: &(elems->iteratordata_), michael@0: status); michael@0: michael@0: if (result == UCOL_NO_MORE_CES) { michael@0: result = UCOL_NULLORDER; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: } michael@0: michael@0: U_CAPI int64_t U_EXPORT2 michael@0: ucol_previousProcessed(UCollationElements *elems, michael@0: int32_t *ixLow, michael@0: int32_t *ixHigh, michael@0: UErrorCode *status) michael@0: { michael@0: const UCollator *coll = elems->iteratordata_.coll; michael@0: int64_t result = UCOL_IGNORABLE; michael@0: // int64_t primary = 0, secondary = 0, tertiary = 0, quaternary = 0; michael@0: // UCollationStrength strength = ucol_getStrength(coll); michael@0: // UBool toShift = ucol_getAttribute(coll, UCOL_ALTERNATE_HANDLING, status) == UCOL_SHIFTED; michael@0: // uint32_t variableTop = coll->variableTopValue; michael@0: int32_t low = 0, high = 0; michael@0: michael@0: if (U_FAILURE(*status)) { michael@0: return UCOL_PROCESSED_NULLORDER; michael@0: } michael@0: michael@0: if (elems->reset_ && michael@0: (elems->iteratordata_.pos == elems->iteratordata_.string)) { michael@0: if (elems->iteratordata_.endp == NULL) { michael@0: elems->iteratordata_.endp = elems->iteratordata_.string + michael@0: u_strlen(elems->iteratordata_.string); michael@0: elems->iteratordata_.flags |= UCOL_ITER_HASLEN; michael@0: } michael@0: michael@0: elems->iteratordata_.pos = elems->iteratordata_.endp; michael@0: elems->iteratordata_.fcdPosition = elems->iteratordata_.endp; michael@0: } michael@0: michael@0: if (elems->pce == NULL) { michael@0: elems->pce = new UCollationPCE(elems); michael@0: } else { michael@0: //elems->pce->pceBuffer.reset(); michael@0: } michael@0: michael@0: elems->reset_ = FALSE; michael@0: michael@0: while (elems->pce->pceBuffer.empty()) { michael@0: // buffer raw CEs up to non-ignorable primary michael@0: RCEBuffer rceb; michael@0: uint32_t ce; michael@0: michael@0: // **** do we need to reset rceb, or will it always be empty at this point **** michael@0: do { michael@0: high = ucol_getOffset(elems); michael@0: ce = ucol_getPrevCE(coll, &elems->iteratordata_, status); michael@0: low = ucol_getOffset(elems); michael@0: michael@0: if (ce == UCOL_NO_MORE_CES) { michael@0: if (! rceb.empty()) { michael@0: break; michael@0: } michael@0: michael@0: goto finish; michael@0: } michael@0: michael@0: rceb.put(ce, low, high); michael@0: } while ((ce & UCOL_PRIMARYMASK) == 0); michael@0: michael@0: // process the raw CEs michael@0: while (! rceb.empty()) { michael@0: const RCEI *rcei = rceb.get(); michael@0: michael@0: result = processCE(elems, rcei->ce); michael@0: michael@0: if (result != UCOL_IGNORABLE) { michael@0: elems->pce->pceBuffer.put(result, rcei->low, rcei->high); michael@0: } michael@0: } michael@0: } michael@0: michael@0: finish: michael@0: if (elems->pce->pceBuffer.empty()) { michael@0: // **** Is -1 the right value for ixLow, ixHigh? **** michael@0: if (ixLow != NULL) { michael@0: *ixLow = -1; michael@0: } michael@0: michael@0: if (ixHigh != NULL) { michael@0: *ixHigh = -1 michael@0: ; michael@0: } michael@0: return UCOL_PROCESSED_NULLORDER; michael@0: } michael@0: michael@0: const PCEI *pcei = elems->pce->pceBuffer.get(); michael@0: michael@0: if (ixLow != NULL) { michael@0: *ixLow = pcei->low; michael@0: } michael@0: michael@0: if (ixHigh != NULL) { michael@0: *ixHigh = pcei->high; michael@0: } michael@0: michael@0: return pcei->ce; michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: ucol_getMaxExpansion(const UCollationElements *elems, michael@0: int32_t order) michael@0: { michael@0: uint8_t result; michael@0: michael@0: #if 0 michael@0: UCOL_GETMAXEXPANSION(elems->iteratordata_.coll, (uint32_t)order, result); michael@0: #else michael@0: const UCollator *coll = elems->iteratordata_.coll; michael@0: const uint32_t *start; michael@0: const uint32_t *limit; michael@0: const uint32_t *mid; michael@0: uint32_t strengthMask = 0; michael@0: uint32_t mOrder = (uint32_t) order; michael@0: michael@0: switch (coll->strength) michael@0: { michael@0: default: michael@0: strengthMask |= UCOL_TERTIARYORDERMASK; michael@0: /* fall through */ michael@0: michael@0: case UCOL_SECONDARY: michael@0: strengthMask |= UCOL_SECONDARYORDERMASK; michael@0: /* fall through */ michael@0: michael@0: case UCOL_PRIMARY: michael@0: strengthMask |= UCOL_PRIMARYORDERMASK; michael@0: } michael@0: michael@0: mOrder &= strengthMask; michael@0: start = (coll)->endExpansionCE; michael@0: limit = (coll)->lastEndExpansionCE; michael@0: michael@0: while (start < limit - 1) { michael@0: mid = start + ((limit - start) >> 1); michael@0: if (mOrder <= (*mid & strengthMask)) { michael@0: limit = mid; michael@0: } else { michael@0: start = mid; michael@0: } michael@0: } michael@0: michael@0: // FIXME: with a masked search, there might be more than one hit, michael@0: // so we need to look forward and backward from the match to find all michael@0: // of the hits... michael@0: if ((*start & strengthMask) == mOrder) { michael@0: result = *((coll)->expansionCESize + (start - (coll)->endExpansionCE)); michael@0: } else if ((*limit & strengthMask) == mOrder) { michael@0: result = *(coll->expansionCESize + (limit - coll->endExpansionCE)); michael@0: } else if ((mOrder & 0xFFFF) == 0x00C0) { michael@0: result = 2; michael@0: } else { michael@0: result = 1; michael@0: } michael@0: #endif michael@0: michael@0: return result; michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: ucol_setText( UCollationElements *elems, michael@0: const UChar *text, michael@0: int32_t textLength, michael@0: UErrorCode *status) michael@0: { michael@0: if (U_FAILURE(*status)) { michael@0: return; michael@0: } michael@0: michael@0: if (elems->isWritable && elems->iteratordata_.string != NULL) michael@0: { michael@0: uprv_free((UChar *)elems->iteratordata_.string); michael@0: } michael@0: michael@0: if (text == NULL) { michael@0: textLength = 0; michael@0: } michael@0: michael@0: elems->isWritable = FALSE; michael@0: michael@0: /* free offset buffer to avoid memory leak before initializing. */ michael@0: ucol_freeOffsetBuffer(&(elems->iteratordata_)); michael@0: /* Ensure that previously allocated extendCEs is freed before setting to NULL. */ michael@0: if (elems->iteratordata_.extendCEs != NULL) { michael@0: uprv_free(elems->iteratordata_.extendCEs); michael@0: } michael@0: uprv_init_collIterate(elems->iteratordata_.coll, text, textLength, michael@0: &elems->iteratordata_, status); michael@0: michael@0: elems->reset_ = TRUE; michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: ucol_getOffset(const UCollationElements *elems) michael@0: { michael@0: const collIterate *ci = &(elems->iteratordata_); michael@0: michael@0: if (ci->offsetRepeatCount > 0 && ci->offsetRepeatValue != 0) { michael@0: return ci->offsetRepeatValue; michael@0: } michael@0: michael@0: if (ci->offsetReturn != NULL) { michael@0: return *ci->offsetReturn; michael@0: } michael@0: michael@0: // while processing characters in normalization buffer getOffset will michael@0: // return the next non-normalized character. michael@0: // should be inline with the old implementation since the old codes uses michael@0: // nextDecomp in normalizer which also decomposes the string till the michael@0: // first base character is found. michael@0: if (ci->flags & UCOL_ITER_INNORMBUF) { michael@0: if (ci->fcdPosition == NULL) { michael@0: return 0; michael@0: } michael@0: return (int32_t)(ci->fcdPosition - ci->string); michael@0: } michael@0: else { michael@0: return (int32_t)(ci->pos - ci->string); michael@0: } michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: ucol_setOffset(UCollationElements *elems, michael@0: int32_t offset, michael@0: UErrorCode *status) michael@0: { michael@0: if (U_FAILURE(*status)) { michael@0: return; michael@0: } michael@0: michael@0: // this methods will clean up any use of the writable buffer and points to michael@0: // the original string michael@0: collIterate *ci = &(elems->iteratordata_); michael@0: ci->pos = ci->string + offset; michael@0: ci->CEpos = ci->toReturn = ci->CEs; michael@0: if (ci->flags & UCOL_ITER_INNORMBUF) { michael@0: ci->flags = ci->origFlags; michael@0: } michael@0: if ((ci->flags & UCOL_ITER_HASLEN) == 0) { michael@0: ci->endp = ci->string + u_strlen(ci->string); michael@0: ci->flags |= UCOL_ITER_HASLEN; michael@0: } michael@0: ci->fcdPosition = NULL; michael@0: elems->reset_ = FALSE; michael@0: michael@0: ci->offsetReturn = NULL; michael@0: ci->offsetStore = ci->offsetBuffer; michael@0: ci->offsetRepeatCount = ci->offsetRepeatValue = 0; michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: ucol_primaryOrder (int32_t order) michael@0: { michael@0: order &= UCOL_PRIMARYMASK; michael@0: return (order >> UCOL_PRIMARYORDERSHIFT); michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: ucol_secondaryOrder (int32_t order) michael@0: { michael@0: order &= UCOL_SECONDARYMASK; michael@0: return (order >> UCOL_SECONDARYORDERSHIFT); michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: ucol_tertiaryOrder (int32_t order) michael@0: { michael@0: return (order & UCOL_TERTIARYMASK); michael@0: } michael@0: michael@0: michael@0: void ucol_freeOffsetBuffer(collIterate *s) { michael@0: if (s != NULL && s->offsetBuffer != NULL) { michael@0: uprv_free(s->offsetBuffer); michael@0: s->offsetBuffer = NULL; michael@0: s->offsetBufferSize = 0; michael@0: } michael@0: } michael@0: michael@0: #endif /* #if !UCONFIG_NO_COLLATION */