| /* |
| ******************************************************************************* |
| * Copyright (C) 1996-2011, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| */ |
| |
| /* |
| * File coleitr.cpp |
| * |
| * |
| * |
| * Created by: Helena Shih |
| * |
| * Modification History: |
| * |
| * Date Name Description |
| * |
| * 6/23/97 helena Adding comments to make code more readable. |
| * 08/03/98 erm Synched with 1.2 version of CollationElementIterator.java |
| * 12/10/99 aliu Ported Thai collation support from Java. |
| * 01/25/01 swquek Modified to a C++ wrapper calling C APIs (ucoliter.h) |
| * 02/19/01 swquek Removed CollationElementsIterator() since it is |
| * private constructor and no calls are made to it |
| */ |
| |
| #include "unicode/utypes.h" |
| |
| #if !UCONFIG_NO_COLLATION |
| |
| #include "unicode/coleitr.h" |
| #include "unicode/ustring.h" |
| #include "ucol_imp.h" |
| #include "uassert.h" |
| #include "cmemory.h" |
| |
| |
| /* Constants --------------------------------------------------------------- */ |
| |
| U_NAMESPACE_BEGIN |
| |
| UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationElementIterator) |
| |
| /* CollationElementIterator public constructor/destructor ------------------ */ |
| |
| CollationElementIterator::CollationElementIterator( |
| const CollationElementIterator& other) |
| : UObject(other), isDataOwned_(TRUE) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| m_data_ = ucol_openElements(other.m_data_->iteratordata_.coll, NULL, 0, |
| &status); |
| |
| *this = other; |
| } |
| |
| CollationElementIterator::~CollationElementIterator() |
| { |
| if (isDataOwned_) { |
| ucol_closeElements(m_data_); |
| } |
| } |
| |
| /* CollationElementIterator public methods --------------------------------- */ |
| |
| int32_t CollationElementIterator::getOffset() const |
| { |
| return ucol_getOffset(m_data_); |
| } |
| |
| /** |
| * Get the ordering priority of the next character in the string. |
| * @return the next character's ordering. Returns NULLORDER if an error has |
| * occured or if the end of string has been reached |
| */ |
| int32_t CollationElementIterator::next(UErrorCode& status) |
| { |
| return ucol_next(m_data_, &status); |
| } |
| |
| UBool CollationElementIterator::operator!=( |
| const CollationElementIterator& other) const |
| { |
| return !(*this == other); |
| } |
| |
| UBool CollationElementIterator::operator==( |
| const CollationElementIterator& that) const |
| { |
| if (this == &that || m_data_ == that.m_data_) { |
| return TRUE; |
| } |
| |
| // option comparison |
| if (m_data_->iteratordata_.coll != that.m_data_->iteratordata_.coll) |
| { |
| return FALSE; |
| } |
| |
| // the constructor and setText always sets a length |
| // and we only compare the string not the contents of the normalization |
| // buffer |
| int thislength = (int)(m_data_->iteratordata_.endp - m_data_->iteratordata_.string); |
| int thatlength = (int)(that.m_data_->iteratordata_.endp - that.m_data_->iteratordata_.string); |
| |
| if (thislength != thatlength) { |
| return FALSE; |
| } |
| |
| if (uprv_memcmp(m_data_->iteratordata_.string, |
| that.m_data_->iteratordata_.string, |
| thislength * U_SIZEOF_UCHAR) != 0) { |
| return FALSE; |
| } |
| if (getOffset() != that.getOffset()) { |
| return FALSE; |
| } |
| |
| // checking normalization buffer |
| if ((m_data_->iteratordata_.flags & UCOL_ITER_HASLEN) == 0) { |
| if ((that.m_data_->iteratordata_.flags & UCOL_ITER_HASLEN) != 0) { |
| return FALSE; |
| } |
| // both are in the normalization buffer |
| if (m_data_->iteratordata_.pos |
| - m_data_->iteratordata_.writableBuffer.getBuffer() |
| != that.m_data_->iteratordata_.pos |
| - that.m_data_->iteratordata_.writableBuffer.getBuffer()) { |
| // not in the same position in the normalization buffer |
| return FALSE; |
| } |
| } |
| else if ((that.m_data_->iteratordata_.flags & UCOL_ITER_HASLEN) == 0) { |
| return FALSE; |
| } |
| // checking ce position |
| return (m_data_->iteratordata_.CEpos - m_data_->iteratordata_.CEs) |
| == (that.m_data_->iteratordata_.CEpos |
| - that.m_data_->iteratordata_.CEs); |
| } |
| |
| /** |
| * Get the ordering priority of the previous collation element in the string. |
| * @param status the error code status. |
| * @return the previous element's ordering. Returns NULLORDER if an error has |
| * occured or if the start of string has been reached. |
| */ |
| int32_t CollationElementIterator::previous(UErrorCode& status) |
| { |
| return ucol_previous(m_data_, &status); |
| } |
| |
| /** |
| * Resets the cursor to the beginning of the string. |
| */ |
| void CollationElementIterator::reset() |
| { |
| ucol_reset(m_data_); |
| } |
| |
| void CollationElementIterator::setOffset(int32_t newOffset, |
| UErrorCode& status) |
| { |
| ucol_setOffset(m_data_, newOffset, &status); |
| } |
| |
| /** |
| * Sets the source to the new source string. |
| */ |
| void CollationElementIterator::setText(const UnicodeString& source, |
| UErrorCode& status) |
| { |
| if (U_FAILURE(status)) { |
| return; |
| } |
| |
| int32_t length = source.length(); |
| UChar *string = NULL; |
| if (m_data_->isWritable && m_data_->iteratordata_.string != NULL) { |
| uprv_free((UChar *)m_data_->iteratordata_.string); |
| } |
| m_data_->isWritable = TRUE; |
| if (length > 0) { |
| string = (UChar *)uprv_malloc(U_SIZEOF_UCHAR * length); |
| /* test for NULL */ |
| if (string == NULL) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| return; |
| } |
| u_memcpy(string, source.getBuffer(), length); |
| } |
| else { |
| string = (UChar *)uprv_malloc(U_SIZEOF_UCHAR); |
| /* test for NULL */ |
| if (string == NULL) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| return; |
| } |
| *string = 0; |
| } |
| /* Free offsetBuffer before initializing it. */ |
| ucol_freeOffsetBuffer(&(m_data_->iteratordata_)); |
| uprv_init_collIterate(m_data_->iteratordata_.coll, string, length, |
| &m_data_->iteratordata_, &status); |
| |
| m_data_->reset_ = TRUE; |
| } |
| |
| // Sets the source to the new character iterator. |
| void CollationElementIterator::setText(CharacterIterator& source, |
| UErrorCode& status) |
| { |
| if (U_FAILURE(status)) |
| return; |
| |
| int32_t length = source.getLength(); |
| UChar *buffer = NULL; |
| |
| if (length == 0) { |
| buffer = (UChar *)uprv_malloc(U_SIZEOF_UCHAR); |
| /* test for NULL */ |
| if (buffer == NULL) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| return; |
| } |
| *buffer = 0; |
| } |
| else { |
| buffer = (UChar *)uprv_malloc(U_SIZEOF_UCHAR * length); |
| /* test for NULL */ |
| if (buffer == NULL) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| return; |
| } |
| /* |
| Using this constructor will prevent buffer from being removed when |
| string gets removed |
| */ |
| UnicodeString string; |
| source.getText(string); |
| u_memcpy(buffer, string.getBuffer(), length); |
| } |
| |
| if (m_data_->isWritable && m_data_->iteratordata_.string != NULL) { |
| uprv_free((UChar *)m_data_->iteratordata_.string); |
| } |
| m_data_->isWritable = TRUE; |
| /* Free offsetBuffer before initializing it. */ |
| ucol_freeOffsetBuffer(&(m_data_->iteratordata_)); |
| uprv_init_collIterate(m_data_->iteratordata_.coll, buffer, length, |
| &m_data_->iteratordata_, &status); |
| m_data_->reset_ = TRUE; |
| } |
| |
| int32_t CollationElementIterator::strengthOrder(int32_t order) const |
| { |
| UCollationStrength s = ucol_getStrength(m_data_->iteratordata_.coll); |
| // Mask off the unwanted differences. |
| if (s == UCOL_PRIMARY) { |
| order &= RuleBasedCollator::PRIMARYDIFFERENCEONLY; |
| } |
| else if (s == UCOL_SECONDARY) { |
| order &= RuleBasedCollator::SECONDARYDIFFERENCEONLY; |
| } |
| |
| return order; |
| } |
| |
| /* CollationElementIterator private constructors/destructors --------------- */ |
| |
| /** |
| * This is the "real" constructor for this class; it constructs an iterator |
| * over the source text using the specified collator |
| */ |
| CollationElementIterator::CollationElementIterator( |
| const UnicodeString& sourceText, |
| const RuleBasedCollator* order, |
| UErrorCode& status) |
| : isDataOwned_(TRUE) |
| { |
| if (U_FAILURE(status)) { |
| return; |
| } |
| |
| int32_t length = sourceText.length(); |
| UChar *string = NULL; |
| |
| if (length > 0) { |
| string = (UChar *)uprv_malloc(U_SIZEOF_UCHAR * length); |
| /* test for NULL */ |
| if (string == NULL) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| return; |
| } |
| /* |
| Using this constructor will prevent buffer from being removed when |
| string gets removed |
| */ |
| u_memcpy(string, sourceText.getBuffer(), length); |
| } |
| else { |
| string = (UChar *)uprv_malloc(U_SIZEOF_UCHAR); |
| /* test for NULL */ |
| if (string == NULL) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| return; |
| } |
| *string = 0; |
| } |
| m_data_ = ucol_openElements(order->ucollator, string, length, &status); |
| |
| /* Test for buffer overflows */ |
| if (U_FAILURE(status)) { |
| return; |
| } |
| m_data_->isWritable = TRUE; |
| } |
| |
| /** |
| * This is the "real" constructor for this class; it constructs an iterator over |
| * the source text using the specified collator |
| */ |
| CollationElementIterator::CollationElementIterator( |
| const CharacterIterator& sourceText, |
| const RuleBasedCollator* order, |
| UErrorCode& status) |
| : isDataOwned_(TRUE) |
| { |
| if (U_FAILURE(status)) |
| return; |
| |
| // **** should I just drop this test? **** |
| /* |
| if ( sourceText.endIndex() != 0 ) |
| { |
| // A CollationElementIterator is really a two-layered beast. |
| // Internally it uses a Normalizer to munge the source text into a form |
| // where all "composed" Unicode characters (such as \u00FC) are split into a |
| // normal character and a combining accent character. |
| // Afterward, CollationElementIterator does its own processing to handle |
| // expanding and contracting collation sequences, ignorables, and so on. |
| |
| Normalizer::EMode decomp = order->getStrength() == Collator::IDENTICAL |
| ? Normalizer::NO_OP : order->getDecomposition(); |
| |
| text = new Normalizer(sourceText, decomp); |
| if (text == NULL) |
| status = U_MEMORY_ALLOCATION_ERROR; |
| } |
| */ |
| int32_t length = sourceText.getLength(); |
| UChar *buffer; |
| if (length > 0) { |
| buffer = (UChar *)uprv_malloc(U_SIZEOF_UCHAR * length); |
| /* test for NULL */ |
| if (buffer == NULL) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| return; |
| } |
| /* |
| Using this constructor will prevent buffer from being removed when |
| string gets removed |
| */ |
| UnicodeString string(buffer, length, length); |
| ((CharacterIterator &)sourceText).getText(string); |
| const UChar *temp = string.getBuffer(); |
| u_memcpy(buffer, temp, length); |
| } |
| else { |
| buffer = (UChar *)uprv_malloc(U_SIZEOF_UCHAR); |
| /* test for NULL */ |
| if (buffer == NULL) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| return; |
| } |
| *buffer = 0; |
| } |
| m_data_ = ucol_openElements(order->ucollator, buffer, length, &status); |
| |
| /* Test for buffer overflows */ |
| if (U_FAILURE(status)) { |
| return; |
| } |
| m_data_->isWritable = TRUE; |
| } |
| |
| /* CollationElementIterator protected methods ----------------------------- */ |
| |
| const CollationElementIterator& CollationElementIterator::operator=( |
| const CollationElementIterator& other) |
| { |
| if (this != &other) |
| { |
| UCollationElements *ucolelem = this->m_data_; |
| UCollationElements *otherucolelem = other.m_data_; |
| collIterate *coliter = &(ucolelem->iteratordata_); |
| collIterate *othercoliter = &(otherucolelem->iteratordata_); |
| int length = 0; |
| |
| // checking only UCOL_ITER_HASLEN is not enough here as we may be in |
| // the normalization buffer |
| length = (int)(othercoliter->endp - othercoliter->string); |
| |
| ucolelem->reset_ = otherucolelem->reset_; |
| ucolelem->isWritable = TRUE; |
| |
| /* create a duplicate of string */ |
| if (length > 0) { |
| coliter->string = (UChar *)uprv_malloc(length * U_SIZEOF_UCHAR); |
| if(coliter->string != NULL) { |
| uprv_memcpy((UChar *)coliter->string, othercoliter->string, |
| length * U_SIZEOF_UCHAR); |
| } else { // Error: couldn't allocate memory. No copying should be done |
| length = 0; |
| } |
| } |
| else { |
| coliter->string = NULL; |
| } |
| |
| /* start and end of string */ |
| coliter->endp = coliter->string == NULL ? NULL : coliter->string + length; |
| |
| /* handle writable buffer here */ |
| |
| if (othercoliter->flags & UCOL_ITER_INNORMBUF) { |
| coliter->writableBuffer = othercoliter->writableBuffer; |
| coliter->writableBuffer.getTerminatedBuffer(); |
| } |
| |
| /* current position */ |
| if (othercoliter->pos >= othercoliter->string && |
| othercoliter->pos <= othercoliter->endp) |
| { |
| U_ASSERT(coliter->string != NULL); |
| coliter->pos = coliter->string + |
| (othercoliter->pos - othercoliter->string); |
| } |
| else { |
| coliter->pos = coliter->writableBuffer.getTerminatedBuffer() + |
| (othercoliter->pos - othercoliter->writableBuffer.getBuffer()); |
| } |
| |
| /* CE buffer */ |
| int32_t CEsize; |
| if (coliter->extendCEs) { |
| uprv_memcpy(coliter->CEs, othercoliter->CEs, sizeof(uint32_t) * UCOL_EXPAND_CE_BUFFER_SIZE); |
| CEsize = sizeof(othercoliter->extendCEs); |
| if (CEsize > 0) { |
| othercoliter->extendCEs = (uint32_t *)uprv_malloc(CEsize); |
| uprv_memcpy(coliter->extendCEs, othercoliter->extendCEs, CEsize); |
| } |
| coliter->toReturn = coliter->extendCEs + |
| (othercoliter->toReturn - othercoliter->extendCEs); |
| coliter->CEpos = coliter->extendCEs + CEsize; |
| } else { |
| CEsize = (int32_t)(othercoliter->CEpos - othercoliter->CEs); |
| if (CEsize > 0) { |
| uprv_memcpy(coliter->CEs, othercoliter->CEs, CEsize); |
| } |
| coliter->toReturn = coliter->CEs + |
| (othercoliter->toReturn - othercoliter->CEs); |
| coliter->CEpos = coliter->CEs + CEsize; |
| } |
| |
| if (othercoliter->fcdPosition != NULL) { |
| U_ASSERT(coliter->string != NULL); |
| coliter->fcdPosition = coliter->string + |
| (othercoliter->fcdPosition |
| - othercoliter->string); |
| } |
| else { |
| coliter->fcdPosition = NULL; |
| } |
| coliter->flags = othercoliter->flags/*| UCOL_ITER_HASLEN*/; |
| coliter->origFlags = othercoliter->origFlags; |
| coliter->coll = othercoliter->coll; |
| this->isDataOwned_ = TRUE; |
| } |
| |
| return *this; |
| } |
| |
| U_NAMESPACE_END |
| |
| #endif /* #if !UCONFIG_NO_COLLATION */ |
| |
| /* eof */ |