|  | /* | 
|  | ******************************************************************************* | 
|  | * | 
|  | *   Copyright (C) 2002, International Business Machines | 
|  | *   Corporation and others.  All Rights Reserved. | 
|  | * | 
|  | ******************************************************************************* | 
|  | *   file name:  uiter.cpp | 
|  | *   encoding:   US-ASCII | 
|  | *   tab size:   8 (not used) | 
|  | *   indentation:4 | 
|  | * | 
|  | *   created on: 2002jan18 | 
|  | *   created by: Markus W. Scherer | 
|  | */ | 
|  |  | 
|  | #include "unicode/utypes.h" | 
|  | #include "unicode/ustring.h" | 
|  | #include "unicode/chariter.h" | 
|  | #include "unicode/rep.h" | 
|  | #include "unicode/uiter.h" | 
|  |  | 
|  | U_CDECL_BEGIN | 
|  |  | 
|  | /* No-Op UCharIterator implementation for illegal input --------------------- */ | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | noopGetIndex(UCharIterator * /*iter*/, UCharIteratorOrigin /*origin*/) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | noopMove(UCharIterator * /*iter*/, int32_t /*delta*/, UCharIteratorOrigin /*origin*/) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static UBool U_CALLCONV | 
|  | noopHasNext(UCharIterator * /*iter*/) { | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | noopCurrent(UCharIterator * /*iter*/) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static const UCharIterator noopIterator={ | 
|  | 0, 0, 0, 0, 0, 0, | 
|  | noopGetIndex, | 
|  | noopMove, | 
|  | noopHasNext, | 
|  | noopHasNext, | 
|  | noopCurrent, | 
|  | noopCurrent, | 
|  | noopCurrent, | 
|  | 0 | 
|  | }; | 
|  |  | 
|  | /* UCharIterator implementation for simple strings -------------------------- */ | 
|  |  | 
|  | /* | 
|  | * This is an implementation of a code unit (UChar) iterator | 
|  | * for UChar * strings. | 
|  | * | 
|  | * The UCharIterator.context field holds a pointer to the string. | 
|  | */ | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | stringIteratorGetIndex(UCharIterator *iter, UCharIteratorOrigin origin) { | 
|  | switch(origin) { | 
|  | case UITER_ZERO: | 
|  | return 0; | 
|  | case UITER_START: | 
|  | return iter->start; | 
|  | case UITER_CURRENT: | 
|  | return iter->index; | 
|  | case UITER_LIMIT: | 
|  | return iter->limit; | 
|  | case UITER_LENGTH: | 
|  | return iter->length; | 
|  | default: | 
|  | /* not a valid origin */ | 
|  | /* Should never get here! */ | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | stringIteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin) { | 
|  | int32_t pos; | 
|  |  | 
|  | switch(origin) { | 
|  | case UITER_ZERO: | 
|  | pos=delta; | 
|  | break; | 
|  | case UITER_START: | 
|  | pos=iter->start+delta; | 
|  | break; | 
|  | case UITER_CURRENT: | 
|  | pos=iter->index+delta; | 
|  | break; | 
|  | case UITER_LIMIT: | 
|  | pos=iter->limit+delta; | 
|  | break; | 
|  | case UITER_LENGTH: | 
|  | pos=iter->length+delta; | 
|  | break; | 
|  | default: | 
|  | /* not a valid origin, no move */ | 
|  | /* Should never get here! */ | 
|  | pos = iter->start; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if(pos<iter->start) { | 
|  | pos=iter->start; | 
|  | } else if(pos>iter->limit) { | 
|  | pos=iter->limit; | 
|  | } | 
|  |  | 
|  | return iter->index=pos; | 
|  | } | 
|  |  | 
|  | static UBool U_CALLCONV | 
|  | stringIteratorHasNext(UCharIterator *iter) { | 
|  | return iter->index<iter->limit; | 
|  | } | 
|  |  | 
|  | static UBool U_CALLCONV | 
|  | stringIteratorHasPrevious(UCharIterator *iter) { | 
|  | return iter->index>iter->start; | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | stringIteratorCurrent(UCharIterator *iter) { | 
|  | if(iter->index<iter->limit) { | 
|  | return ((const UChar *)(iter->context))[iter->index]; | 
|  | } else { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | stringIteratorNext(UCharIterator *iter) { | 
|  | if(iter->index<iter->limit) { | 
|  | return ((const UChar *)(iter->context))[iter->index++]; | 
|  | } else { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | stringIteratorPrevious(UCharIterator *iter) { | 
|  | if(iter->index>iter->start) { | 
|  | return ((const UChar *)(iter->context))[--iter->index]; | 
|  | } else { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static const UCharIterator stringIterator={ | 
|  | 0, 0, 0, 0, 0, 0, | 
|  | stringIteratorGetIndex, | 
|  | stringIteratorMove, | 
|  | stringIteratorHasNext, | 
|  | stringIteratorHasPrevious, | 
|  | stringIteratorCurrent, | 
|  | stringIteratorNext, | 
|  | stringIteratorPrevious, | 
|  | 0 | 
|  | }; | 
|  |  | 
|  | U_CAPI void U_EXPORT2 | 
|  | uiter_setString(UCharIterator *iter, const UChar *s, int32_t length) { | 
|  | if(iter!=0) { | 
|  | if(s!=0 && length>=-1) { | 
|  | *iter=stringIterator; | 
|  | iter->context=s; | 
|  | if(length>=0) { | 
|  | iter->length=length; | 
|  | } else { | 
|  | iter->length=u_strlen(s); | 
|  | } | 
|  | iter->limit=iter->length; | 
|  | } else { | 
|  | *iter=noopIterator; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* UCharIterator wrapper around CharacterIterator --------------------------- */ | 
|  |  | 
|  | /* | 
|  | * This is wrapper code around a C++ CharacterIterator to | 
|  | * look like a C UCharIterator. | 
|  | * | 
|  | * The UCharIterator.context field holds a pointer to the CharacterIterator. | 
|  | */ | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | characterIteratorGetIndex(UCharIterator *iter, UCharIteratorOrigin origin) { | 
|  | switch(origin) { | 
|  | case UITER_ZERO: | 
|  | return 0; | 
|  | case UITER_START: | 
|  | return ((CharacterIterator *)(iter->context))->startIndex(); | 
|  | case UITER_CURRENT: | 
|  | return ((CharacterIterator *)(iter->context))->getIndex(); | 
|  | case UITER_LIMIT: | 
|  | return ((CharacterIterator *)(iter->context))->endIndex(); | 
|  | case UITER_LENGTH: | 
|  | return ((CharacterIterator *)(iter->context))->getLength(); | 
|  | default: | 
|  | /* not a valid origin */ | 
|  | /* Should never get here! */ | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | characterIteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin) { | 
|  | switch(origin) { | 
|  | case UITER_ZERO: | 
|  | ((CharacterIterator *)(iter->context))->setIndex(delta); | 
|  | return ((CharacterIterator *)(iter->context))->getIndex(); | 
|  | case UITER_START: | 
|  | case UITER_CURRENT: | 
|  | case UITER_LIMIT: | 
|  | return ((CharacterIterator *)(iter->context))->move(delta, (CharacterIterator::EOrigin)origin); | 
|  | case UITER_LENGTH: | 
|  | ((CharacterIterator *)(iter->context))->setIndex(((CharacterIterator *)(iter->context))->getLength()+delta); | 
|  | return ((CharacterIterator *)(iter->context))->getIndex(); | 
|  | default: | 
|  | /* not a valid origin */ | 
|  | /* Should never get here! */ | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static UBool U_CALLCONV | 
|  | characterIteratorHasNext(UCharIterator *iter) { | 
|  | return ((CharacterIterator *)(iter->context))->hasNext(); | 
|  | } | 
|  |  | 
|  | static UBool U_CALLCONV | 
|  | characterIteratorHasPrevious(UCharIterator *iter) { | 
|  | return ((CharacterIterator *)(iter->context))->hasPrevious(); | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | characterIteratorCurrent(UCharIterator *iter) { | 
|  | int32_t c; | 
|  |  | 
|  | c=((CharacterIterator *)(iter->context))->current(); | 
|  | if(c!=0xffff || ((CharacterIterator *)(iter->context))->hasNext()) { | 
|  | return c; | 
|  | } else { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | characterIteratorNext(UCharIterator *iter) { | 
|  | if(((CharacterIterator *)(iter->context))->hasNext()) { | 
|  | return ((CharacterIterator *)(iter->context))->nextPostInc(); | 
|  | } else { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | characterIteratorPrevious(UCharIterator *iter) { | 
|  | if(((CharacterIterator *)(iter->context))->hasPrevious()) { | 
|  | return ((CharacterIterator *)(iter->context))->previous(); | 
|  | } else { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static const UCharIterator characterIteratorWrapper={ | 
|  | 0, 0, 0, 0, 0, 0, | 
|  | characterIteratorGetIndex, | 
|  | characterIteratorMove, | 
|  | characterIteratorHasNext, | 
|  | characterIteratorHasPrevious, | 
|  | characterIteratorCurrent, | 
|  | characterIteratorNext, | 
|  | characterIteratorPrevious, | 
|  | 0 | 
|  | }; | 
|  |  | 
|  | U_CAPI void U_EXPORT2 | 
|  | uiter_setCharacterIterator(UCharIterator *iter, CharacterIterator *charIter) { | 
|  | if(iter!=0) { | 
|  | if(charIter!=0) { | 
|  | *iter=characterIteratorWrapper; | 
|  | iter->context=charIter; | 
|  | } else { | 
|  | *iter=noopIterator; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* UCharIterator wrapper around Replaceable --------------------------------- */ | 
|  |  | 
|  | /* | 
|  | * This is an implementation of a code unit (UChar) iterator | 
|  | * based on a Replaceable object. | 
|  | * | 
|  | * The UCharIterator.context field holds a pointer to the Replaceable. | 
|  | * UCharIterator.length and UCharIterator.index hold Replaceable.length() | 
|  | * and the iteration index. | 
|  | */ | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | replaceableIteratorCurrent(UCharIterator *iter) { | 
|  | if(iter->index<iter->limit) { | 
|  | return ((Replaceable *)(iter->context))->charAt(iter->index); | 
|  | } else { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | replaceableIteratorNext(UCharIterator *iter) { | 
|  | if(iter->index<iter->limit) { | 
|  | return ((Replaceable *)(iter->context))->charAt(iter->index++); | 
|  | } else { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int32_t U_CALLCONV | 
|  | replaceableIteratorPrevious(UCharIterator *iter) { | 
|  | if(iter->index>iter->start) { | 
|  | return ((Replaceable *)(iter->context))->charAt(--iter->index); | 
|  | } else { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static const UCharIterator replaceableIterator={ | 
|  | 0, 0, 0, 0, 0, 0, | 
|  | stringIteratorGetIndex, | 
|  | stringIteratorMove, | 
|  | stringIteratorHasNext, | 
|  | stringIteratorHasPrevious, | 
|  | replaceableIteratorCurrent, | 
|  | replaceableIteratorNext, | 
|  | replaceableIteratorPrevious, | 
|  | 0 | 
|  | }; | 
|  |  | 
|  | U_CAPI void U_EXPORT2 | 
|  | uiter_setReplaceable(UCharIterator *iter, const Replaceable *rep) { | 
|  | if(iter!=0) { | 
|  | if(rep!=0) { | 
|  | *iter=replaceableIterator; | 
|  | iter->context=rep; | 
|  | iter->limit=iter->length=rep->length(); | 
|  | } else { | 
|  | *iter=noopIterator; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Helper functions --------------------------------------------------------- */ | 
|  |  | 
|  | U_CAPI int32_t U_EXPORT2 | 
|  | uiter_current32(UCharIterator *iter) { | 
|  | int32_t c, c2; | 
|  |  | 
|  | c=iter->current(iter); | 
|  | if(UTF_IS_SURROGATE(c)) { | 
|  | if(UTF_IS_SURROGATE_FIRST(c)) { | 
|  | /* | 
|  | * go to the next code unit | 
|  | * we know that we are not at the limit because c!=-1 | 
|  | */ | 
|  | iter->move(iter, 1, UITER_CURRENT); | 
|  | if(UTF_IS_SECOND_SURROGATE(c2=iter->current(iter))) { | 
|  | c=UTF16_GET_PAIR_VALUE(c, c2); | 
|  | } | 
|  |  | 
|  | /* undo index movement */ | 
|  | iter->move(iter, -1, UITER_CURRENT); | 
|  | } else { | 
|  | if(UTF_IS_FIRST_SURROGATE(c2=iter->previous(iter))) { | 
|  | c=UTF16_GET_PAIR_VALUE(c2, c); | 
|  | } | 
|  | if(c2>=0) { | 
|  | /* undo index movement */ | 
|  | iter->move(iter, 1, UITER_CURRENT); | 
|  | } | 
|  | } | 
|  | } | 
|  | return c; | 
|  | } | 
|  |  | 
|  | U_CAPI int32_t U_EXPORT2 | 
|  | uiter_next32(UCharIterator *iter) { | 
|  | int32_t c, c2; | 
|  |  | 
|  | c=iter->next(iter); | 
|  | if(UTF_IS_FIRST_SURROGATE(c)) { | 
|  | if(UTF_IS_SECOND_SURROGATE(c2=iter->next(iter))) { | 
|  | c=UTF16_GET_PAIR_VALUE(c, c2); | 
|  | } else if(c2>=0) { | 
|  | /* unmatched first surrogate, undo index movement */ | 
|  | iter->move(iter, -1, UITER_CURRENT); | 
|  | } | 
|  | } | 
|  | return c; | 
|  | } | 
|  |  | 
|  | U_CAPI int32_t U_EXPORT2 | 
|  | uiter_previous32(UCharIterator *iter) { | 
|  | int32_t c, c2; | 
|  |  | 
|  | c=iter->previous(iter); | 
|  | if(UTF_IS_SECOND_SURROGATE(c)) { | 
|  | if(UTF_IS_FIRST_SURROGATE(c2=iter->previous(iter))) { | 
|  | c=UTF16_GET_PAIR_VALUE(c2, c); | 
|  | } else if(c2>=0) { | 
|  | /* unmatched second surrogate, undo index movement */ | 
|  | iter->move(iter, 1, UITER_CURRENT); | 
|  | } | 
|  | } | 
|  | return c; | 
|  | } | 
|  |  | 
|  | U_CDECL_END |