Home | History | Annotate | Download | only in i18n
      1 /*
      2 *******************************************************************************
      3 *   Copyright (C) 1996-2012, International Business Machines
      4 *   Corporation and others.  All Rights Reserved.
      5 *******************************************************************************
      6 *   file name:  ucol.cpp
      7 *   encoding:   US-ASCII
      8 *   tab size:   8 (not used)
      9 *   indentation:4
     10 *
     11 * Modification history
     12 * Date        Name      Comments
     13 * 1996-1999   various members of ICU team maintained C API for collation framework
     14 * 02/16/2001  synwee    Added internal method getPrevSpecialCE
     15 * 03/01/2001  synwee    Added maxexpansion functionality.
     16 * 03/16/2001  weiv      Collation framework is rewritten in C and made UCA compliant
     17 */
     18 
     19 #include "unicode/utypes.h"
     20 
     21 #if !UCONFIG_NO_COLLATION
     22 
     23 #include "unicode/bytestream.h"
     24 #include "unicode/coleitr.h"
     25 #include "unicode/unorm.h"
     26 #include "unicode/udata.h"
     27 #include "unicode/ustring.h"
     28 #include "unicode/utf8.h"
     29 
     30 #include "ucol_imp.h"
     31 #include "bocsu.h"
     32 
     33 #include "normalizer2impl.h"
     34 #include "unorm_it.h"
     35 #include "umutex.h"
     36 #include "cmemory.h"
     37 #include "ucln_in.h"
     38 #include "cstring.h"
     39 #include "utracimp.h"
     40 #include "putilimp.h"
     41 #include "uassert.h"
     42 #include "unicode/coll.h"
     43 
     44 #ifdef UCOL_DEBUG
     45 #include <stdio.h>
     46 #endif
     47 
     48 U_NAMESPACE_USE
     49 
     50 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
     51 
     52 #define LAST_BYTE_MASK_           0xFF
     53 #define SECOND_LAST_BYTE_SHIFT_   8
     54 
     55 #define ZERO_CC_LIMIT_            0xC0
     56 
     57 // These are static pointers to the NFC/NFD implementation instance.
     58 // Each of them is always the same between calls to u_cleanup
     59 // and therefore writing to it is not synchronized.
     60 // They are cleaned in ucol_cleanup
     61 static const Normalizer2 *g_nfd = NULL;
     62 static const Normalizer2Impl *g_nfcImpl = NULL;
     63 
     64 // These are values from UCA required for
     65 // implicit generation and supressing sort key compression
     66 // they should regularly be in the UCA, but if one
     67 // is running without UCA, it could be a problem
     68 static const int32_t maxRegularPrimary  = 0x7A;
     69 static const int32_t minImplicitPrimary = 0xE0;
     70 static const int32_t maxImplicitPrimary = 0xE4;
     71 
     72 U_CDECL_BEGIN
     73 static UBool U_CALLCONV
     74 ucol_cleanup(void)
     75 {
     76     g_nfd = NULL;
     77     g_nfcImpl = NULL;
     78     return TRUE;
     79 }
     80 
     81 static int32_t U_CALLCONV
     82 _getFoldingOffset(uint32_t data) {
     83     return (int32_t)(data&0xFFFFFF);
     84 }
     85 
     86 U_CDECL_END
     87 
     88 static inline
     89 UBool initializeNFD(UErrorCode *status) {
     90     if (g_nfd != NULL) {
     91         return TRUE;
     92     } else {
     93         // The result is constant, until the library is reloaded.
     94         g_nfd = Normalizer2Factory::getNFDInstance(*status);
     95         ucln_i18n_registerCleanup(UCLN_I18N_UCOL, ucol_cleanup);
     96         return U_SUCCESS(*status);
     97     }
     98 }
     99 
    100 // init FCD data
    101 static inline
    102 UBool initializeFCD(UErrorCode *status) {
    103     if (g_nfcImpl != NULL) {
    104         return TRUE;
    105     } else {
    106         // The result is constant, until the library is reloaded.
    107         g_nfcImpl = Normalizer2Factory::getNFCImpl(*status);
    108         // Note: Alternatively, we could also store this pointer in each collIterate struct,
    109         // same as Normalizer2Factory::getImpl(collIterate->nfd).
    110         ucln_i18n_registerCleanup(UCLN_I18N_UCOL, ucol_cleanup);
    111         return U_SUCCESS(*status);
    112     }
    113 }
    114 
    115 static
    116 inline void IInit_collIterate(const UCollator *collator, const UChar *sourceString,
    117                               int32_t sourceLen, collIterate *s,
    118                               UErrorCode *status)
    119 {
    120     (s)->string = (s)->pos = sourceString;
    121     (s)->origFlags = 0;
    122     (s)->flags = 0;
    123     if (sourceLen >= 0) {
    124         s->flags |= UCOL_ITER_HASLEN;
    125         (s)->endp = (UChar *)sourceString+sourceLen;
    126     }
    127     else {
    128         /* change to enable easier checking for end of string for fcdpositon */
    129         (s)->endp = NULL;
    130     }
    131     (s)->extendCEs = NULL;
    132     (s)->extendCEsSize = 0;
    133     (s)->CEpos = (s)->toReturn = (s)->CEs;
    134     (s)->offsetBuffer = NULL;
    135     (s)->offsetBufferSize = 0;
    136     (s)->offsetReturn = (s)->offsetStore = NULL;
    137     (s)->offsetRepeatCount = (s)->offsetRepeatValue = 0;
    138     (s)->coll = (collator);
    139     if (initializeNFD(status)) {
    140         (s)->nfd = g_nfd;
    141     } else {
    142         return;
    143     }
    144     (s)->fcdPosition = 0;
    145     if(collator->normalizationMode == UCOL_ON) {
    146         (s)->flags |= UCOL_ITER_NORM;
    147     }
    148     if(collator->hiraganaQ == UCOL_ON && collator->strength >= UCOL_QUATERNARY) {
    149         (s)->flags |= UCOL_HIRAGANA_Q;
    150     }
    151     (s)->iterator = NULL;
    152     //(s)->iteratorIndex = 0;
    153 }
    154 
    155 U_CAPI void  U_EXPORT2
    156 uprv_init_collIterate(const UCollator *collator, const UChar *sourceString,
    157                              int32_t sourceLen, collIterate *s,
    158                              UErrorCode *status) {
    159     /* Out-of-line version for use from other files. */
    160     IInit_collIterate(collator, sourceString, sourceLen, s, status);
    161 }
    162 
    163 U_CAPI collIterate * U_EXPORT2
    164 uprv_new_collIterate(UErrorCode *status) {
    165     if(U_FAILURE(*status)) {
    166         return NULL;
    167     }
    168     collIterate *s = new collIterate;
    169     if(s == NULL) {
    170         *status = U_MEMORY_ALLOCATION_ERROR;
    171         return NULL;
    172     }
    173     return s;
    174 }
    175 
    176 U_CAPI void U_EXPORT2
    177 uprv_delete_collIterate(collIterate *s) {
    178     delete s;
    179 }
    180 
    181 U_CAPI UBool U_EXPORT2
    182 uprv_collIterateAtEnd(collIterate *s) {
    183     return s == NULL || s->pos == s->endp;
    184 }
    185 
    186 /**
    187 * Backup the state of the collIterate struct data
    188 * @param data collIterate to backup
    189 * @param backup storage
    190 */
    191 static
    192 inline void backupState(const collIterate *data, collIterateState *backup)
    193 {
    194     backup->fcdPosition = data->fcdPosition;
    195     backup->flags       = data->flags;
    196     backup->origFlags   = data->origFlags;
    197     backup->pos         = data->pos;
    198     backup->bufferaddress = data->writableBuffer.getBuffer();
    199     backup->buffersize    = data->writableBuffer.length();
    200     backup->iteratorMove = 0;
    201     backup->iteratorIndex = 0;
    202     if(data->iterator != NULL) {
    203         //backup->iteratorIndex = data->iterator->getIndex(data->iterator, UITER_CURRENT);
    204         backup->iteratorIndex = data->iterator->getState(data->iterator);
    205         // no we try to fixup if we're using a normalizing iterator and we get UITER_NO_STATE
    206         if(backup->iteratorIndex == UITER_NO_STATE) {
    207             while((backup->iteratorIndex = data->iterator->getState(data->iterator)) == UITER_NO_STATE) {
    208                 backup->iteratorMove++;
    209                 data->iterator->move(data->iterator, -1, UITER_CURRENT);
    210             }
    211             data->iterator->move(data->iterator, backup->iteratorMove, UITER_CURRENT);
    212         }
    213     }
    214 }
    215 
    216 /**
    217 * Loads the state into the collIterate struct data
    218 * @param data collIterate to backup
    219 * @param backup storage
    220 * @param forwards boolean to indicate if forwards iteration is used,
    221 *        false indicates backwards iteration
    222 */
    223 static
    224 inline void loadState(collIterate *data, const collIterateState *backup,
    225                       UBool        forwards)
    226 {
    227     UErrorCode status = U_ZERO_ERROR;
    228     data->flags       = backup->flags;
    229     data->origFlags   = backup->origFlags;
    230     if(data->iterator != NULL) {
    231         //data->iterator->move(data->iterator, backup->iteratorIndex, UITER_ZERO);
    232         data->iterator->setState(data->iterator, backup->iteratorIndex, &status);
    233         if(backup->iteratorMove != 0) {
    234             data->iterator->move(data->iterator, backup->iteratorMove, UITER_CURRENT);
    235         }
    236     }
    237     data->pos         = backup->pos;
    238 
    239     if ((data->flags & UCOL_ITER_INNORMBUF) &&
    240         data->writableBuffer.getBuffer() != backup->bufferaddress) {
    241         /*
    242         this is when a new buffer has been reallocated and we'll have to
    243         calculate the new position.
    244         note the new buffer has to contain the contents of the old buffer.
    245         */
    246         if (forwards) {
    247             data->pos = data->writableBuffer.getTerminatedBuffer() +
    248                                          (data->pos - backup->bufferaddress);
    249         }
    250         else {
    251             /* backwards direction */
    252             int32_t temp = backup->buffersize -
    253                                   (int32_t)(data->pos - backup->bufferaddress);
    254             data->pos = data->writableBuffer.getTerminatedBuffer() + (data->writableBuffer.length() - temp);
    255         }
    256     }
    257     if ((data->flags & UCOL_ITER_INNORMBUF) == 0) {
    258         /*
    259         this is alittle tricky.
    260         if we are initially not in the normalization buffer, even if we
    261         normalize in the later stage, the data in the buffer will be
    262         ignored, since we skip back up to the data string.
    263         however if we are already in the normalization buffer, any
    264         further normalization will pull data into the normalization
    265         buffer and modify the fcdPosition.
    266         since we are keeping the data in the buffer for use, the
    267         fcdPosition can not be reverted back.
    268         arrgghh....
    269         */
    270         data->fcdPosition = backup->fcdPosition;
    271     }
    272 }
    273 
    274 static UBool
    275 reallocCEs(collIterate *data, int32_t newCapacity) {
    276     uint32_t *oldCEs = data->extendCEs;
    277     if(oldCEs == NULL) {
    278         oldCEs = data->CEs;
    279     }
    280     int32_t length = data->CEpos - oldCEs;
    281     uint32_t *newCEs = (uint32_t *)uprv_malloc(newCapacity * 4);
    282     if(newCEs == NULL) {
    283         return FALSE;
    284     }
    285     uprv_memcpy(newCEs, oldCEs, length * 4);
    286     uprv_free(data->extendCEs);
    287     data->extendCEs = newCEs;
    288     data->extendCEsSize = newCapacity;
    289     data->CEpos = newCEs + length;
    290     return TRUE;
    291 }
    292 
    293 static UBool
    294 increaseCEsCapacity(collIterate *data) {
    295     int32_t oldCapacity;
    296     if(data->extendCEs != NULL) {
    297         oldCapacity = data->extendCEsSize;
    298     } else {
    299         oldCapacity = LENGTHOF(data->CEs);
    300     }
    301     return reallocCEs(data, 2 * oldCapacity);
    302 }
    303 
    304 static UBool
    305 ensureCEsCapacity(collIterate *data, int32_t minCapacity) {
    306     int32_t oldCapacity;
    307     if(data->extendCEs != NULL) {
    308         oldCapacity = data->extendCEsSize;
    309     } else {
    310         oldCapacity = LENGTHOF(data->CEs);
    311     }
    312     if(minCapacity <= oldCapacity) {
    313         return TRUE;
    314     }
    315     oldCapacity *= 2;
    316     return reallocCEs(data, minCapacity > oldCapacity ? minCapacity : oldCapacity);
    317 }
    318 
    319 void collIterate::appendOffset(int32_t offset, UErrorCode &errorCode) {
    320     if(U_FAILURE(errorCode)) {
    321         return;
    322     }
    323     int32_t length = offsetStore == NULL ? 0 : (int32_t)(offsetStore - offsetBuffer);
    324     U_ASSERT(length >= offsetBufferSize || offsetStore != NULL);
    325     if(length >= offsetBufferSize) {
    326         int32_t newCapacity = 2 * offsetBufferSize + UCOL_EXPAND_CE_BUFFER_SIZE;
    327         int32_t *newBuffer = static_cast<int32_t *>(uprv_malloc(newCapacity * 4));
    328         if(newBuffer == NULL) {
    329             errorCode = U_MEMORY_ALLOCATION_ERROR;
    330             return;
    331         }
    332         if(length > 0) {
    333             uprv_memcpy(newBuffer, offsetBuffer, length * 4);
    334         }
    335         uprv_free(offsetBuffer);
    336         offsetBuffer = newBuffer;
    337         offsetStore = offsetBuffer + length;
    338         offsetBufferSize = newCapacity;
    339     }
    340     *offsetStore++ = offset;
    341 }
    342 
    343 /*
    344 * collIter_eos()
    345 *     Checks for a collIterate being positioned at the end of
    346 *     its source string.
    347 *
    348 */
    349 static
    350 inline UBool collIter_eos(collIterate *s) {
    351     if(s->flags & UCOL_USE_ITERATOR) {
    352       return !(s->iterator->hasNext(s->iterator));
    353     }
    354     if ((s->flags & UCOL_ITER_HASLEN) == 0 && *s->pos != 0) {
    355         // Null terminated string, but not at null, so not at end.
    356         //   Whether in main or normalization buffer doesn't matter.
    357         return FALSE;
    358     }
    359 
    360     // String with length.  Can't be in normalization buffer, which is always
    361     //  null termintated.
    362     if (s->flags & UCOL_ITER_HASLEN) {
    363         return (s->pos == s->endp);
    364     }
    365 
    366     // We are at a null termination, could be either normalization buffer or main string.
    367     if ((s->flags & UCOL_ITER_INNORMBUF) == 0) {
    368         // At null at end of main string.
    369         return TRUE;
    370     }
    371 
    372     // At null at end of normalization buffer.  Need to check whether there there are
    373     //   any characters left in the main buffer.
    374     if(s->origFlags & UCOL_USE_ITERATOR) {
    375       return !(s->iterator->hasNext(s->iterator));
    376     } else if ((s->origFlags & UCOL_ITER_HASLEN) == 0) {
    377         // Null terminated main string.  fcdPosition is the 'return' position into main buf.
    378         return (*s->fcdPosition == 0);
    379     }
    380     else {
    381         // Main string with an end pointer.
    382         return s->fcdPosition == s->endp;
    383     }
    384 }
    385 
    386 /*
    387 * collIter_bos()
    388 *     Checks for a collIterate being positioned at the start of
    389 *     its source string.
    390 *
    391 */
    392 static
    393 inline UBool collIter_bos(collIterate *source) {
    394   // if we're going backwards, we need to know whether there is more in the
    395   // iterator, even if we are in the side buffer
    396   if(source->flags & UCOL_USE_ITERATOR || source->origFlags & UCOL_USE_ITERATOR) {
    397     return !source->iterator->hasPrevious(source->iterator);
    398   }
    399   if (source->pos <= source->string ||
    400       ((source->flags & UCOL_ITER_INNORMBUF) &&
    401       *(source->pos - 1) == 0 && source->fcdPosition == NULL)) {
    402     return TRUE;
    403   }
    404   return FALSE;
    405 }
    406 
    407 /*static
    408 inline UBool collIter_SimpleBos(collIterate *source) {
    409   // if we're going backwards, we need to know whether there is more in the
    410   // iterator, even if we are in the side buffer
    411   if(source->flags & UCOL_USE_ITERATOR || source->origFlags & UCOL_USE_ITERATOR) {
    412     return !source->iterator->hasPrevious(source->iterator);
    413   }
    414   if (source->pos == source->string) {
    415     return TRUE;
    416   }
    417   return FALSE;
    418 }*/
    419     //return (data->pos == data->string) ||
    420 
    421 
    422 /****************************************************************************/
    423 /* Following are the open/close functions                                   */
    424 /*                                                                          */
    425 /****************************************************************************/
    426 
    427 static UCollator*
    428 ucol_initFromBinary(const uint8_t *bin, int32_t length,
    429                 const UCollator *base,
    430                 UCollator *fillIn,
    431                 UErrorCode *status)
    432 {
    433     UCollator *result = fillIn;
    434     if(U_FAILURE(*status)) {
    435         return NULL;
    436     }
    437     /*
    438     if(base == NULL) {
    439         // we don't support null base yet
    440         *status = U_ILLEGAL_ARGUMENT_ERROR;
    441         return NULL;
    442     }
    443     */
    444     // We need these and we could be running without UCA
    445     uprv_uca_initImplicitConstants(status);
    446     UCATableHeader *colData = (UCATableHeader *)bin;
    447     // do we want version check here? We're trying to figure out whether collators are compatible
    448     if((base && (uprv_memcmp(colData->UCAVersion, base->image->UCAVersion, sizeof(UVersionInfo)) != 0 ||
    449         uprv_memcmp(colData->UCDVersion, base->image->UCDVersion, sizeof(UVersionInfo)) != 0)) ||
    450         colData->version[0] != UCOL_BUILDER_VERSION)
    451     {
    452         *status = U_COLLATOR_VERSION_MISMATCH;
    453         return NULL;
    454     }
    455     else {
    456         if((uint32_t)length > (paddedsize(sizeof(UCATableHeader)) + paddedsize(sizeof(UColOptionSet)))) {
    457             result = ucol_initCollator((const UCATableHeader *)bin, result, base, status);
    458             if(U_FAILURE(*status)){
    459                 return NULL;
    460             }
    461             result->hasRealData = TRUE;
    462         }
    463         else {
    464             if(base) {
    465                 result = ucol_initCollator(base->image, result, base, status);
    466                 ucol_setOptionsFromHeader(result, (UColOptionSet *)(bin+((const UCATableHeader *)bin)->options), status);
    467                 if(U_FAILURE(*status)){
    468                     return NULL;
    469                 }
    470                 result->hasRealData = FALSE;
    471             }
    472             else {
    473                 *status = U_USELESS_COLLATOR_ERROR;
    474                 return NULL;
    475             }
    476         }
    477         result->freeImageOnClose = FALSE;
    478     }
    479     result->actualLocale = NULL;
    480     result->validLocale = NULL;
    481     result->requestedLocale = NULL;
    482     result->rules = NULL;
    483     result->rulesLength = 0;
    484     result->freeRulesOnClose = FALSE;
    485     result->ucaRules = NULL;
    486     return result;
    487 }
    488 
    489 U_CAPI UCollator* U_EXPORT2
    490 ucol_openBinary(const uint8_t *bin, int32_t length,
    491                 const UCollator *base,
    492                 UErrorCode *status)
    493 {
    494     return ucol_initFromBinary(bin, length, base, NULL, status);
    495 }
    496 
    497 U_CAPI int32_t U_EXPORT2
    498 ucol_cloneBinary(const UCollator *coll,
    499                  uint8_t *buffer, int32_t capacity,
    500                  UErrorCode *status)
    501 {
    502     int32_t length = 0;
    503     if(U_FAILURE(*status)) {
    504         return length;
    505     }
    506     if(capacity < 0) {
    507         *status = U_ILLEGAL_ARGUMENT_ERROR;
    508         return length;
    509     }
    510     if(coll->hasRealData == TRUE) {
    511         length = coll->image->size;
    512         if(length <= capacity) {
    513             uprv_memcpy(buffer, coll->image, length);
    514         } else {
    515             *status = U_BUFFER_OVERFLOW_ERROR;
    516         }
    517     } else {
    518         length = (int32_t)(paddedsize(sizeof(UCATableHeader))+paddedsize(sizeof(UColOptionSet)));
    519         if(length <= capacity) {
    520             /* build the UCATableHeader with minimal entries */
    521             /* do not copy the header from the UCA file because its values are wrong! */
    522             /* uprv_memcpy(result, UCA->image, sizeof(UCATableHeader)); */
    523 
    524             /* reset everything */
    525             uprv_memset(buffer, 0, length);
    526 
    527             /* set the tailoring-specific values */
    528             UCATableHeader *myData = (UCATableHeader *)buffer;
    529             myData->size = length;
    530 
    531             /* offset for the options, the only part of the data that is present after the header */
    532             myData->options = sizeof(UCATableHeader);
    533 
    534             /* need to always set the expansion value for an upper bound of the options */
    535             myData->expansion = myData->options + sizeof(UColOptionSet);
    536 
    537             myData->magic = UCOL_HEADER_MAGIC;
    538             myData->isBigEndian = U_IS_BIG_ENDIAN;
    539             myData->charSetFamily = U_CHARSET_FAMILY;
    540 
    541             /* copy UCA's version; genrb will override all but the builder version with tailoring data */
    542             uprv_memcpy(myData->version, coll->image->version, sizeof(UVersionInfo));
    543 
    544             uprv_memcpy(myData->UCAVersion, coll->image->UCAVersion, sizeof(UVersionInfo));
    545             uprv_memcpy(myData->UCDVersion, coll->image->UCDVersion, sizeof(UVersionInfo));
    546             uprv_memcpy(myData->formatVersion, coll->image->formatVersion, sizeof(UVersionInfo));
    547             myData->jamoSpecial = coll->image->jamoSpecial;
    548 
    549             /* copy the collator options */
    550             uprv_memcpy(buffer+paddedsize(sizeof(UCATableHeader)), coll->options, sizeof(UColOptionSet));
    551         } else {
    552             *status = U_BUFFER_OVERFLOW_ERROR;
    553         }
    554     }
    555     return length;
    556 }
    557 
    558 U_CAPI UCollator* U_EXPORT2
    559 ucol_safeClone(const UCollator *coll, void *stackBuffer, int32_t * pBufferSize, UErrorCode *status)
    560 {
    561     UCollator * localCollator;
    562     int32_t bufferSizeNeeded = (int32_t)sizeof(UCollator);
    563     char *stackBufferChars = (char *)stackBuffer;
    564     int32_t imageSize = 0;
    565     int32_t rulesSize = 0;
    566     int32_t rulesPadding = 0;
    567     int32_t defaultReorderCodesSize = 0;
    568     int32_t reorderCodesSize = 0;
    569     uint8_t *image;
    570     UChar *rules;
    571     int32_t* defaultReorderCodes;
    572     int32_t* reorderCodes;
    573     uint8_t* leadBytePermutationTable;
    574     UBool colAllocated = FALSE;
    575     UBool imageAllocated = FALSE;
    576 
    577     if (status == NULL || U_FAILURE(*status)){
    578         return 0;
    579     }
    580     if ((stackBuffer && !pBufferSize) || !coll){
    581        *status = U_ILLEGAL_ARGUMENT_ERROR;
    582         return 0;
    583     }
    584 
    585     if (coll->rules && coll->freeRulesOnClose) {
    586         rulesSize = (int32_t)(coll->rulesLength + 1)*sizeof(UChar);
    587         rulesPadding = (int32_t)(bufferSizeNeeded % sizeof(UChar));
    588         bufferSizeNeeded += rulesSize + rulesPadding;
    589     }
    590     // no padding for alignment needed from here since the next two are 4 byte quantities
    591     if (coll->defaultReorderCodes) {
    592         defaultReorderCodesSize = coll->defaultReorderCodesLength * sizeof(int32_t);
    593         bufferSizeNeeded += defaultReorderCodesSize;
    594     }
    595     if (coll->reorderCodes) {
    596         reorderCodesSize = coll->reorderCodesLength * sizeof(int32_t);
    597         bufferSizeNeeded += reorderCodesSize;
    598     }
    599     if (coll->leadBytePermutationTable) {
    600         bufferSizeNeeded += 256 * sizeof(uint8_t);
    601     }
    602 
    603     if (stackBuffer && *pBufferSize <= 0) { /* 'preflighting' request - set needed size into *pBufferSize */
    604         *pBufferSize =  bufferSizeNeeded;
    605         return 0;
    606     }
    607 
    608     /* Pointers on 64-bit platforms need to be aligned
    609      * on a 64-bit boundry in memory.
    610      */
    611     if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) {
    612         int32_t offsetUp = (int32_t)U_ALIGNMENT_OFFSET_UP(stackBufferChars);
    613         if (*pBufferSize > offsetUp) {
    614             *pBufferSize -= offsetUp;
    615             stackBufferChars += offsetUp;
    616         }
    617         else {
    618             /* prevent using the stack buffer but keep the size > 0 so that we do not just preflight */
    619             *pBufferSize = 1;
    620         }
    621     }
    622     stackBuffer = (void *)stackBufferChars;
    623 
    624     if (stackBuffer == NULL || *pBufferSize < bufferSizeNeeded) {
    625         /* allocate one here...*/
    626         stackBufferChars = (char *)uprv_malloc(bufferSizeNeeded);
    627         // Null pointer check.
    628         if (stackBufferChars == NULL) {
    629             *status = U_MEMORY_ALLOCATION_ERROR;
    630             return NULL;
    631         }
    632         colAllocated = TRUE;
    633         if (U_SUCCESS(*status)) {
    634             *status = U_SAFECLONE_ALLOCATED_WARNING;
    635         }
    636     }
    637     localCollator = (UCollator *)stackBufferChars;
    638     rules = (UChar *)(stackBufferChars + sizeof(UCollator) + rulesPadding);
    639     defaultReorderCodes = (int32_t*)((uint8_t*)rules + rulesSize);
    640     reorderCodes = (int32_t*)((uint8_t*)defaultReorderCodes + defaultReorderCodesSize);
    641     leadBytePermutationTable = (uint8_t*)reorderCodes + reorderCodesSize;
    642 
    643     {
    644         UErrorCode tempStatus = U_ZERO_ERROR;
    645         imageSize = ucol_cloneBinary(coll, NULL, 0, &tempStatus);
    646     }
    647     if (coll->freeImageOnClose) {
    648         image = (uint8_t *)uprv_malloc(imageSize);
    649         // Null pointer check
    650         if (image == NULL) {
    651             *status = U_MEMORY_ALLOCATION_ERROR;
    652             return NULL;
    653         }
    654         ucol_cloneBinary(coll, image, imageSize, status);
    655         imageAllocated = TRUE;
    656     }
    657     else {
    658         image = (uint8_t *)coll->image;
    659     }
    660     localCollator = ucol_initFromBinary(image, imageSize, coll->UCA, localCollator, status);
    661     if (U_FAILURE(*status)) {
    662         return NULL;
    663     }
    664 
    665     if (coll->rules) {
    666         if (coll->freeRulesOnClose) {
    667             localCollator->rules = u_strcpy(rules, coll->rules);
    668             //bufferEnd += rulesSize;
    669         }
    670         else {
    671             localCollator->rules = coll->rules;
    672         }
    673         localCollator->freeRulesOnClose = FALSE;
    674         localCollator->rulesLength = coll->rulesLength;
    675     }
    676 
    677     // collator reordering
    678     if (coll->defaultReorderCodes) {
    679         localCollator->defaultReorderCodes =
    680             (int32_t*) uprv_memcpy(defaultReorderCodes, coll->defaultReorderCodes, coll->defaultReorderCodesLength * sizeof(int32_t));
    681         localCollator->defaultReorderCodesLength = coll->defaultReorderCodesLength;
    682         localCollator->freeDefaultReorderCodesOnClose = FALSE;
    683     }
    684     if (coll->reorderCodes) {
    685         localCollator->reorderCodes =
    686             (int32_t*)uprv_memcpy(reorderCodes, coll->reorderCodes, coll->reorderCodesLength * sizeof(int32_t));
    687         localCollator->reorderCodesLength = coll->reorderCodesLength;
    688         localCollator->freeReorderCodesOnClose = FALSE;
    689     }
    690     if (coll->leadBytePermutationTable) {
    691         localCollator->leadBytePermutationTable =
    692             (uint8_t*) uprv_memcpy(leadBytePermutationTable, coll->leadBytePermutationTable, 256);
    693         localCollator->freeLeadBytePermutationTableOnClose = FALSE;
    694     }
    695 
    696     int32_t i;
    697     for(i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) {
    698         ucol_setAttribute(localCollator, (UColAttribute)i, ucol_getAttribute(coll, (UColAttribute)i, status), status);
    699     }
    700     // zero copies of pointers
    701     localCollator->actualLocale = NULL;
    702     localCollator->validLocale = NULL;
    703     localCollator->requestedLocale = NULL;
    704     localCollator->ucaRules = coll->ucaRules; // There should only be one copy here.
    705     localCollator->freeOnClose = colAllocated;
    706     localCollator->freeImageOnClose = imageAllocated;
    707     return localCollator;
    708 }
    709 
    710 U_CAPI void U_EXPORT2
    711 ucol_close(UCollator *coll)
    712 {
    713     UTRACE_ENTRY_OC(UTRACE_UCOL_CLOSE);
    714     UTRACE_DATA1(UTRACE_INFO, "coll = %p", coll);
    715     if(coll != NULL) {
    716         // these are always owned by each UCollator struct,
    717         // so we always free them
    718         if(coll->validLocale != NULL) {
    719             uprv_free(coll->validLocale);
    720         }
    721         if(coll->actualLocale != NULL) {
    722             uprv_free(coll->actualLocale);
    723         }
    724         if(coll->requestedLocale != NULL) {
    725             uprv_free(coll->requestedLocale);
    726         }
    727         if(coll->latinOneCEs != NULL) {
    728             uprv_free(coll->latinOneCEs);
    729         }
    730         if(coll->options != NULL && coll->freeOptionsOnClose) {
    731             uprv_free(coll->options);
    732         }
    733         if(coll->rules != NULL && coll->freeRulesOnClose) {
    734             uprv_free((UChar *)coll->rules);
    735         }
    736         if(coll->image != NULL && coll->freeImageOnClose) {
    737             uprv_free((UCATableHeader *)coll->image);
    738         }
    739 
    740         if(coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
    741             uprv_free(coll->leadBytePermutationTable);
    742         }
    743         if(coll->defaultReorderCodes != NULL && coll->freeDefaultReorderCodesOnClose == TRUE) {
    744             uprv_free(coll->defaultReorderCodes);
    745         }
    746         if(coll->reorderCodes != NULL && coll->freeReorderCodesOnClose == TRUE) {
    747             uprv_free(coll->reorderCodes);
    748         }
    749 
    750         if(coll->delegate != NULL) {
    751           delete (Collator*)coll->delegate;
    752         }
    753 
    754         /* Here, it would be advisable to close: */
    755         /* - UData for UCA (unless we stuff it in the root resb */
    756         /* Again, do we need additional housekeeping... HMMM! */
    757         UTRACE_DATA1(UTRACE_INFO, "coll->freeOnClose: %d", coll->freeOnClose);
    758         if(coll->freeOnClose){
    759             /* for safeClone, if freeOnClose is FALSE,
    760             don't free the other instance data */
    761             uprv_free(coll);
    762         }
    763     }
    764     UTRACE_EXIT();
    765 }
    766 
    767 /* This one is currently used by genrb & tests. After constructing from rules (tailoring),*/
    768 /* you should be able to get the binary chunk to write out...  Doesn't look very full now */
    769 U_CFUNC uint8_t* U_EXPORT2
    770 ucol_cloneRuleData(const UCollator *coll, int32_t *length, UErrorCode *status)
    771 {
    772     uint8_t *result = NULL;
    773     if(U_FAILURE(*status)) {
    774         return NULL;
    775     }
    776     if(coll->hasRealData == TRUE) {
    777         *length = coll->image->size;
    778         result = (uint8_t *)uprv_malloc(*length);
    779         /* test for NULL */
    780         if (result == NULL) {
    781             *status = U_MEMORY_ALLOCATION_ERROR;
    782             return NULL;
    783         }
    784         uprv_memcpy(result, coll->image, *length);
    785     } else {
    786         *length = (int32_t)(paddedsize(sizeof(UCATableHeader))+paddedsize(sizeof(UColOptionSet)));
    787         result = (uint8_t *)uprv_malloc(*length);
    788         /* test for NULL */
    789         if (result == NULL) {
    790             *status = U_MEMORY_ALLOCATION_ERROR;
    791             return NULL;
    792         }
    793 
    794         /* build the UCATableHeader with minimal entries */
    795         /* do not copy the header from the UCA file because its values are wrong! */
    796         /* uprv_memcpy(result, UCA->image, sizeof(UCATableHeader)); */
    797 
    798         /* reset everything */
    799         uprv_memset(result, 0, *length);
    800 
    801         /* set the tailoring-specific values */
    802         UCATableHeader *myData = (UCATableHeader *)result;
    803         myData->size = *length;
    804 
    805         /* offset for the options, the only part of the data that is present after the header */
    806         myData->options = sizeof(UCATableHeader);
    807 
    808         /* need to always set the expansion value for an upper bound of the options */
    809         myData->expansion = myData->options + sizeof(UColOptionSet);
    810 
    811         myData->magic = UCOL_HEADER_MAGIC;
    812         myData->isBigEndian = U_IS_BIG_ENDIAN;
    813         myData->charSetFamily = U_CHARSET_FAMILY;
    814 
    815         /* copy UCA's version; genrb will override all but the builder version with tailoring data */
    816         uprv_memcpy(myData->version, coll->image->version, sizeof(UVersionInfo));
    817 
    818         uprv_memcpy(myData->UCAVersion, coll->image->UCAVersion, sizeof(UVersionInfo));
    819         uprv_memcpy(myData->UCDVersion, coll->image->UCDVersion, sizeof(UVersionInfo));
    820         uprv_memcpy(myData->formatVersion, coll->image->formatVersion, sizeof(UVersionInfo));
    821         myData->jamoSpecial = coll->image->jamoSpecial;
    822 
    823         /* copy the collator options */
    824         uprv_memcpy(result+paddedsize(sizeof(UCATableHeader)), coll->options, sizeof(UColOptionSet));
    825     }
    826     return result;
    827 }
    828 
    829 void ucol_setOptionsFromHeader(UCollator* result, UColOptionSet * opts, UErrorCode *status) {
    830     if(U_FAILURE(*status)) {
    831         return;
    832     }
    833     result->caseFirst = (UColAttributeValue)opts->caseFirst;
    834     result->caseLevel = (UColAttributeValue)opts->caseLevel;
    835     result->frenchCollation = (UColAttributeValue)opts->frenchCollation;
    836     result->normalizationMode = (UColAttributeValue)opts->normalizationMode;
    837     if(result->normalizationMode == UCOL_ON && !initializeFCD(status)) {
    838         return;
    839     }
    840     result->strength = (UColAttributeValue)opts->strength;
    841     result->variableTopValue = opts->variableTopValue;
    842     result->alternateHandling = (UColAttributeValue)opts->alternateHandling;
    843     result->hiraganaQ = (UColAttributeValue)opts->hiraganaQ;
    844     result->numericCollation = (UColAttributeValue)opts->numericCollation;
    845     result->caseFirstisDefault = TRUE;
    846     result->caseLevelisDefault = TRUE;
    847     result->frenchCollationisDefault = TRUE;
    848     result->normalizationModeisDefault = TRUE;
    849     result->strengthisDefault = TRUE;
    850     result->variableTopValueisDefault = TRUE;
    851     result->alternateHandlingisDefault = TRUE;
    852     result->hiraganaQisDefault = TRUE;
    853     result->numericCollationisDefault = TRUE;
    854 
    855     ucol_updateInternalState(result, status);
    856 
    857     result->options = opts;
    858 }
    859 
    860 
    861 /**
    862 * Approximate determination if a character is at a contraction end.
    863 * Guaranteed to be TRUE if a character is at the end of a contraction,
    864 * otherwise it is not deterministic.
    865 * @param c character to be determined
    866 * @param coll collator
    867 */
    868 static
    869 inline UBool ucol_contractionEndCP(UChar c, const UCollator *coll) {
    870     if (c < coll->minContrEndCP) {
    871         return FALSE;
    872     }
    873 
    874     int32_t  hash = c;
    875     uint8_t  htbyte;
    876     if (hash >= UCOL_UNSAFECP_TABLE_SIZE*8) {
    877         if (U16_IS_TRAIL(c)) {
    878             return TRUE;
    879         }
    880         hash = (hash & UCOL_UNSAFECP_TABLE_MASK) + 256;
    881     }
    882     htbyte = coll->contrEndCP[hash>>3];
    883     return (((htbyte >> (hash & 7)) & 1) == 1);
    884 }
    885 
    886 
    887 
    888 /*
    889 *   i_getCombiningClass()
    890 *        A fast, at least partly inline version of u_getCombiningClass()
    891 *        This is a candidate for further optimization.  Used heavily
    892 *        in contraction processing.
    893 */
    894 static
    895 inline uint8_t i_getCombiningClass(UChar32 c, const UCollator *coll) {
    896     uint8_t sCC = 0;
    897     if ((c >= 0x300 && ucol_unsafeCP(c, coll)) || c > 0xFFFF) {
    898         sCC = u_getCombiningClass(c);
    899     }
    900     return sCC;
    901 }
    902 
    903 UCollator* ucol_initCollator(const UCATableHeader *image, UCollator *fillIn, const UCollator *UCA, UErrorCode *status) {
    904     UChar c;
    905     UCollator *result = fillIn;
    906     if(U_FAILURE(*status) || image == NULL) {
    907         return NULL;
    908     }
    909 
    910     if(result == NULL) {
    911         result = (UCollator *)uprv_malloc(sizeof(UCollator));
    912         if(result == NULL) {
    913             *status = U_MEMORY_ALLOCATION_ERROR;
    914             return result;
    915         }
    916         result->freeOnClose = TRUE;
    917     } else {
    918         result->freeOnClose = FALSE;
    919     }
    920 
    921     result->delegate = NULL;
    922 
    923     result->image = image;
    924     result->mapping.getFoldingOffset = _getFoldingOffset;
    925     const uint8_t *mapping = (uint8_t*)result->image+result->image->mappingPosition;
    926     utrie_unserialize(&result->mapping, mapping, result->image->endExpansionCE - result->image->mappingPosition, status);
    927     if(U_FAILURE(*status)) {
    928         if(result->freeOnClose == TRUE) {
    929             uprv_free(result);
    930             result = NULL;
    931         }
    932         return result;
    933     }
    934 
    935     result->latinOneMapping = UTRIE_GET32_LATIN1(&result->mapping);
    936     result->contractionCEs = (uint32_t*)((uint8_t*)result->image+result->image->contractionCEs);
    937     result->contractionIndex = (UChar*)((uint8_t*)result->image+result->image->contractionIndex);
    938     result->expansion = (uint32_t*)((uint8_t*)result->image+result->image->expansion);
    939     result->rules = NULL;
    940     result->rulesLength = 0;
    941     result->freeRulesOnClose = FALSE;
    942     result->defaultReorderCodes = NULL;
    943     result->defaultReorderCodesLength = 0;
    944     result->freeDefaultReorderCodesOnClose = FALSE;
    945     result->reorderCodes = NULL;
    946     result->reorderCodesLength = 0;
    947     result->freeReorderCodesOnClose = FALSE;
    948     result->leadBytePermutationTable = NULL;
    949     result->freeLeadBytePermutationTableOnClose = FALSE;
    950 
    951     /* get the version info from UCATableHeader and populate the Collator struct*/
    952     result->dataVersion[0] = result->image->version[0]; /* UCA Builder version*/
    953     result->dataVersion[1] = result->image->version[1]; /* UCA Tailoring rules version*/
    954     result->dataVersion[2] = 0;
    955     result->dataVersion[3] = 0;
    956 
    957     result->unsafeCP = (uint8_t *)result->image + result->image->unsafeCP;
    958     result->minUnsafeCP = 0;
    959     for (c=0; c<0x300; c++) {  // Find the smallest unsafe char.
    960         if (ucol_unsafeCP(c, result)) break;
    961     }
    962     result->minUnsafeCP = c;
    963 
    964     result->contrEndCP = (uint8_t *)result->image + result->image->contrEndCP;
    965     result->minContrEndCP = 0;
    966     for (c=0; c<0x300; c++) {  // Find the Contraction-ending char.
    967         if (ucol_contractionEndCP(c, result)) break;
    968     }
    969     result->minContrEndCP = c;
    970 
    971     /* max expansion tables */
    972     result->endExpansionCE = (uint32_t*)((uint8_t*)result->image +
    973                                          result->image->endExpansionCE);
    974     result->lastEndExpansionCE = result->endExpansionCE +
    975                                  result->image->endExpansionCECount - 1;
    976     result->expansionCESize = (uint8_t*)result->image +
    977                                                result->image->expansionCESize;
    978 
    979 
    980     //result->errorCode = *status;
    981 
    982     result->latinOneCEs = NULL;
    983 
    984     result->latinOneRegenTable = FALSE;
    985     result->latinOneFailed = FALSE;
    986     result->UCA = UCA;
    987 
    988     /* Normally these will be set correctly later. This is the default if you use UCA or the default. */
    989     result->ucaRules = NULL;
    990     result->actualLocale = NULL;
    991     result->validLocale = NULL;
    992     result->requestedLocale = NULL;
    993     result->hasRealData = FALSE; // real data lives in .dat file...
    994     result->freeImageOnClose = FALSE;
    995 
    996     /* set attributes */
    997     ucol_setOptionsFromHeader(
    998         result,
    999         (UColOptionSet*)((uint8_t*)result->image+result->image->options),
   1000         status);
   1001     result->freeOptionsOnClose = FALSE;
   1002 
   1003     return result;
   1004 }
   1005 
   1006 /* new Mark's code */
   1007 
   1008 /**
   1009  * For generation of Implicit CEs
   1010  * @author Davis
   1011  *
   1012  * Cleaned up so that changes can be made more easily.
   1013  * Old values:
   1014 # First Implicit: E26A792D
   1015 # Last Implicit: E3DC70C0
   1016 # First CJK: E0030300
   1017 # Last CJK: E0A9DD00
   1018 # First CJK_A: E0A9DF00
   1019 # Last CJK_A: E0DE3100
   1020  */
   1021 /* Following is a port of Mark's code for new treatment of implicits.
   1022  * It is positioned here, since ucol_initUCA need to initialize the
   1023  * variables below according to the data in the fractional UCA.
   1024  */
   1025 
   1026 /**
   1027  * Function used to:
   1028  * a) collapse the 2 different Han ranges from UCA into one (in the right order), and
   1029  * b) bump any non-CJK characters by 10FFFF.
   1030  * The relevant blocks are:
   1031  * A:    4E00..9FFF; CJK Unified Ideographs
   1032  *       F900..FAFF; CJK Compatibility Ideographs
   1033  * B:    3400..4DBF; CJK Unified Ideographs Extension A
   1034  *       20000..XX;  CJK Unified Ideographs Extension B (and others later on)
   1035  * As long as
   1036  *   no new B characters are allocated between 4E00 and FAFF, and
   1037  *   no new A characters are outside of this range,
   1038  * (very high probability) this simple code will work.
   1039  * The reordered blocks are:
   1040  * Block1 is CJK
   1041  * Block2 is CJK_COMPAT_USED
   1042  * Block3 is CJK_A
   1043  * (all contiguous)
   1044  * Any other CJK gets its normal code point
   1045  * Any non-CJK gets +10FFFF
   1046  * When we reorder Block1, we make sure that it is at the very start,
   1047  * so that it will use a 3-byte form.
   1048  * Warning: the we only pick up the compatibility characters that are
   1049  * NOT decomposed, so that block is smaller!
   1050  */
   1051 
   1052 // CONSTANTS
   1053 static const UChar32
   1054     NON_CJK_OFFSET = 0x110000,
   1055     UCOL_MAX_INPUT = 0x220001; // 2 * Unicode range + 2
   1056 
   1057 /**
   1058  * Precomputed by initImplicitConstants()
   1059  */
   1060 static int32_t
   1061     final3Multiplier = 0,
   1062     final4Multiplier = 0,
   1063     final3Count = 0,
   1064     final4Count = 0,
   1065     medialCount = 0,
   1066     min3Primary = 0,
   1067     min4Primary = 0,
   1068     max4Primary = 0,
   1069     minTrail = 0,
   1070     maxTrail = 0,
   1071     max3Trail = 0,
   1072     max4Trail = 0,
   1073     min4Boundary = 0;
   1074 
   1075 static const UChar32
   1076     // 4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
   1077     // 9FCC;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;  (Unicode 6.1)
   1078     CJK_BASE = 0x4E00,
   1079     CJK_LIMIT = 0x9FCC+1,
   1080     // Unified CJK ideographs in the compatibility ideographs block.
   1081     CJK_COMPAT_USED_BASE = 0xFA0E,
   1082     CJK_COMPAT_USED_LIMIT = 0xFA2F+1,
   1083     // 3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
   1084     // 4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
   1085     CJK_A_BASE = 0x3400,
   1086     CJK_A_LIMIT = 0x4DB5+1,
   1087     // 20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;
   1088     // 2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
   1089     CJK_B_BASE = 0x20000,
   1090     CJK_B_LIMIT = 0x2A6D6+1,
   1091     // 2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;;
   1092     // 2B734;<CJK Ideograph Extension C, Last>;Lo;0;L;;;;;N;;;;;
   1093     CJK_C_BASE = 0x2A700,
   1094     CJK_C_LIMIT = 0x2B734+1,
   1095     // 2B740;<CJK Ideograph Extension D, First>;Lo;0;L;;;;;N;;;;;
   1096     // 2B81D;<CJK Ideograph Extension D, Last>;Lo;0;L;;;;;N;;;;;
   1097     CJK_D_BASE = 0x2B740,
   1098     CJK_D_LIMIT = 0x2B81D+1;
   1099     // when adding to this list, look for all occurrences (in project)
   1100     // of CJK_C_BASE and CJK_C_LIMIT, etc. to check for code that needs changing!!!!
   1101 
   1102 static UChar32 swapCJK(UChar32 i) {
   1103     if (i < CJK_A_BASE) {
   1104         // non-CJK
   1105     } else if (i < CJK_A_LIMIT) {
   1106         // Extension A has lower code points than the original Unihan+compat
   1107         // but sorts higher.
   1108         return i - CJK_A_BASE
   1109                 + (CJK_LIMIT - CJK_BASE)
   1110                 + (CJK_COMPAT_USED_LIMIT - CJK_COMPAT_USED_BASE);
   1111     } else if (i < CJK_BASE) {
   1112         // non-CJK
   1113     } else if (i < CJK_LIMIT) {
   1114         return i - CJK_BASE;
   1115     } else if (i < CJK_COMPAT_USED_BASE) {
   1116         // non-CJK
   1117     } else if (i < CJK_COMPAT_USED_LIMIT) {
   1118         return i - CJK_COMPAT_USED_BASE
   1119                 + (CJK_LIMIT - CJK_BASE);
   1120     } else if (i < CJK_B_BASE) {
   1121         // non-CJK
   1122     } else if (i < CJK_B_LIMIT) {
   1123         return i; // non-BMP-CJK
   1124     } else if (i < CJK_C_BASE) {
   1125         // non-CJK
   1126     } else if (i < CJK_C_LIMIT) {
   1127         return i; // non-BMP-CJK
   1128     } else if (i < CJK_D_BASE) {
   1129         // non-CJK
   1130     } else if (i < CJK_D_LIMIT) {
   1131         return i; // non-BMP-CJK
   1132     }
   1133     return i + NON_CJK_OFFSET; // non-CJK
   1134 }
   1135 
   1136 U_CAPI UChar32 U_EXPORT2
   1137 uprv_uca_getRawFromCodePoint(UChar32 i) {
   1138     return swapCJK(i)+1;
   1139 }
   1140 
   1141 U_CAPI UChar32 U_EXPORT2
   1142 uprv_uca_getCodePointFromRaw(UChar32 i) {
   1143     i--;
   1144     UChar32 result = 0;
   1145     if(i >= NON_CJK_OFFSET) {
   1146         result = i - NON_CJK_OFFSET;
   1147     } else if(i >= CJK_B_BASE) {
   1148         result = i;
   1149     } else if(i < CJK_A_LIMIT + (CJK_LIMIT - CJK_BASE) + (CJK_COMPAT_USED_LIMIT - CJK_COMPAT_USED_BASE)) { // rest of CJKs, compacted
   1150         if(i < CJK_LIMIT - CJK_BASE) {
   1151             result = i + CJK_BASE;
   1152         } else if(i < (CJK_LIMIT - CJK_BASE) + (CJK_COMPAT_USED_LIMIT - CJK_COMPAT_USED_BASE)) {
   1153             result = i + CJK_COMPAT_USED_BASE - (CJK_LIMIT - CJK_BASE);
   1154         } else {
   1155             result = i + CJK_A_BASE - (CJK_LIMIT - CJK_BASE) - (CJK_COMPAT_USED_LIMIT - CJK_COMPAT_USED_BASE);
   1156         }
   1157     } else {
   1158         result = -1;
   1159     }
   1160     return result;
   1161 }
   1162 
   1163 // GET IMPLICIT PRIMARY WEIGHTS
   1164 // Return value is left justified primary key
   1165 U_CAPI uint32_t U_EXPORT2
   1166 uprv_uca_getImplicitFromRaw(UChar32 cp) {
   1167     /*
   1168     if (cp < 0 || cp > UCOL_MAX_INPUT) {
   1169         throw new IllegalArgumentException("Code point out of range " + Utility.hex(cp));
   1170     }
   1171     */
   1172     int32_t last0 = cp - min4Boundary;
   1173     if (last0 < 0) {
   1174         int32_t last1 = cp / final3Count;
   1175         last0 = cp % final3Count;
   1176 
   1177         int32_t last2 = last1 / medialCount;
   1178         last1 %= medialCount;
   1179 
   1180         last0 = minTrail + last0*final3Multiplier; // spread out, leaving gap at start
   1181         last1 = minTrail + last1; // offset
   1182         last2 = min3Primary + last2; // offset
   1183         /*
   1184         if (last2 >= min4Primary) {
   1185             throw new IllegalArgumentException("4-byte out of range: " + Utility.hex(cp) + ", " + Utility.hex(last2));
   1186         }
   1187         */
   1188         return (last2 << 24) + (last1 << 16) + (last0 << 8);
   1189     } else {
   1190         int32_t last1 = last0 / final4Count;
   1191         last0 %= final4Count;
   1192 
   1193         int32_t last2 = last1 / medialCount;
   1194         last1 %= medialCount;
   1195 
   1196         int32_t last3 = last2 / medialCount;
   1197         last2 %= medialCount;
   1198 
   1199         last0 = minTrail + last0*final4Multiplier; // spread out, leaving gap at start
   1200         last1 = minTrail + last1; // offset
   1201         last2 = minTrail + last2; // offset
   1202         last3 = min4Primary + last3; // offset
   1203         /*
   1204         if (last3 > max4Primary) {
   1205             throw new IllegalArgumentException("4-byte out of range: " + Utility.hex(cp) + ", " + Utility.hex(last3));
   1206         }
   1207         */
   1208         return (last3 << 24) + (last2 << 16) + (last1 << 8) + last0;
   1209     }
   1210 }
   1211 
   1212 static uint32_t U_EXPORT2
   1213 uprv_uca_getImplicitPrimary(UChar32 cp) {
   1214    //fprintf(stdout, "Incoming: %04x\n", cp);
   1215     //if (DEBUG) System.out.println("Incoming: " + Utility.hex(cp));
   1216 
   1217     cp = swapCJK(cp);
   1218     cp++;
   1219     // we now have a range of numbers from 0 to 21FFFF.
   1220 
   1221     //if (DEBUG) System.out.println("CJK swapped: " + Utility.hex(cp));
   1222     //fprintf(stdout, "CJK swapped: %04x\n", cp);
   1223 
   1224     return uprv_uca_getImplicitFromRaw(cp);
   1225 }
   1226 
   1227 /**
   1228  * Converts implicit CE into raw integer ("code point")
   1229  * @param implicit
   1230  * @return -1 if illegal format
   1231  */
   1232 U_CAPI UChar32 U_EXPORT2
   1233 uprv_uca_getRawFromImplicit(uint32_t implicit) {
   1234     UChar32 result;
   1235     UChar32 b3 = implicit & 0xFF;
   1236     UChar32 b2 = (implicit >> 8) & 0xFF;
   1237     UChar32 b1 = (implicit >> 16) & 0xFF;
   1238     UChar32 b0 = (implicit >> 24) & 0xFF;
   1239 
   1240     // simple parameter checks
   1241     if (b0 < min3Primary || b0 > max4Primary
   1242         || b1 < minTrail || b1 > maxTrail)
   1243         return -1;
   1244     // normal offsets
   1245     b1 -= minTrail;
   1246 
   1247     // take care of the final values, and compose
   1248     if (b0 < min4Primary) {
   1249         if (b2 < minTrail || b2 > max3Trail || b3 != 0)
   1250             return -1;
   1251         b2 -= minTrail;
   1252         UChar32 remainder = b2 % final3Multiplier;
   1253         if (remainder != 0)
   1254             return -1;
   1255         b0 -= min3Primary;
   1256         b2 /= final3Multiplier;
   1257         result = ((b0 * medialCount) + b1) * final3Count + b2;
   1258     } else {
   1259         if (b2 < minTrail || b2 > maxTrail
   1260             || b3 < minTrail || b3 > max4Trail)
   1261             return -1;
   1262         b2 -= minTrail;
   1263         b3 -= minTrail;
   1264         UChar32 remainder = b3 % final4Multiplier;
   1265         if (remainder != 0)
   1266             return -1;
   1267         b3 /= final4Multiplier;
   1268         b0 -= min4Primary;
   1269         result = (((b0 * medialCount) + b1) * medialCount + b2) * final4Count + b3 + min4Boundary;
   1270     }
   1271     // final check
   1272     if (result < 0 || result > UCOL_MAX_INPUT)
   1273         return -1;
   1274     return result;
   1275 }
   1276 
   1277 
   1278 static inline int32_t divideAndRoundUp(int a, int b) {
   1279     return 1 + (a-1)/b;
   1280 }
   1281 
   1282 /* this function is either called from initUCA or from genUCA before
   1283  * doing canonical closure for the UCA.
   1284  */
   1285 
   1286 /**
   1287  * Set up to generate implicits.
   1288  * Maintenance Note:  this function may end up being called more than once, due
   1289  *                    to threading races during initialization.  Make sure that
   1290  *                    none of the Constants is ever transiently assigned an
   1291  *                    incorrect value.
   1292  * @param minPrimary
   1293  * @param maxPrimary
   1294  * @param minTrail final byte
   1295  * @param maxTrail final byte
   1296  * @param gap3 the gap we leave for tailoring for 3-byte forms
   1297  * @param gap4 the gap we leave for tailoring for 4-byte forms
   1298  */
   1299 static void initImplicitConstants(int minPrimary, int maxPrimary,
   1300                                     int minTrailIn, int maxTrailIn,
   1301                                     int gap3, int primaries3count,
   1302                                     UErrorCode *status) {
   1303     // some simple parameter checks
   1304     if ((minPrimary < 0 || minPrimary >= maxPrimary || maxPrimary > 0xFF)
   1305         || (minTrailIn < 0 || minTrailIn >= maxTrailIn || maxTrailIn > 0xFF)
   1306         || (primaries3count < 1))
   1307     {
   1308         *status = U_ILLEGAL_ARGUMENT_ERROR;
   1309         return;
   1310     };
   1311 
   1312     minTrail = minTrailIn;
   1313     maxTrail = maxTrailIn;
   1314 
   1315     min3Primary = minPrimary;
   1316     max4Primary = maxPrimary;
   1317     // compute constants for use later.
   1318     // number of values we can use in trailing bytes
   1319     // leave room for empty values between AND above, e.g. if gap = 2
   1320     // range 3..7 => +3 -4 -5 -6 -7: so 1 value
   1321     // range 3..8 => +3 -4 -5 +6 -7 -8: so 2 values
   1322     // range 3..9 => +3 -4 -5 +6 -7 -8 -9: so 2 values
   1323     final3Multiplier = gap3 + 1;
   1324     final3Count = (maxTrail - minTrail + 1) / final3Multiplier;
   1325     max3Trail = minTrail + (final3Count - 1) * final3Multiplier;
   1326 
   1327     // medials can use full range
   1328     medialCount = (maxTrail - minTrail + 1);
   1329     // find out how many values fit in each form
   1330     int32_t threeByteCount = medialCount * final3Count;
   1331     // now determine where the 3/4 boundary is.
   1332     // we use 3 bytes below the boundary, and 4 above
   1333     int32_t primariesAvailable = maxPrimary - minPrimary + 1;
   1334     int32_t primaries4count = primariesAvailable - primaries3count;
   1335 
   1336 
   1337     int32_t min3ByteCoverage = primaries3count * threeByteCount;
   1338     min4Primary = minPrimary + primaries3count;
   1339     min4Boundary = min3ByteCoverage;
   1340     // Now expand out the multiplier for the 4 bytes, and redo.
   1341 
   1342     int32_t totalNeeded = UCOL_MAX_INPUT - min4Boundary;
   1343     int32_t neededPerPrimaryByte = divideAndRoundUp(totalNeeded, primaries4count);
   1344     int32_t neededPerFinalByte = divideAndRoundUp(neededPerPrimaryByte, medialCount * medialCount);
   1345     int32_t gap4 = (maxTrail - minTrail - 1) / neededPerFinalByte;
   1346     if (gap4 < 1) {
   1347         *status = U_ILLEGAL_ARGUMENT_ERROR;
   1348         return;
   1349     }
   1350     final4Multiplier = gap4 + 1;
   1351     final4Count = neededPerFinalByte;
   1352     max4Trail = minTrail + (final4Count - 1) * final4Multiplier;
   1353 }
   1354 
   1355     /**
   1356      * Supply parameters for generating implicit CEs
   1357      */
   1358 U_CAPI void U_EXPORT2
   1359 uprv_uca_initImplicitConstants(UErrorCode *status) {
   1360     // 13 is the largest 4-byte gap we can use without getting 2 four-byte forms.
   1361     //initImplicitConstants(minPrimary, maxPrimary, 0x04, 0xFE, 1, 1, status);
   1362     initImplicitConstants(minImplicitPrimary, maxImplicitPrimary, 0x04, 0xFE, 1, 1, status);
   1363 }
   1364 
   1365 
   1366 /*    collIterNormalize     Incremental Normalization happens here.                       */
   1367 /*                          pick up the range of chars identifed by FCD,                  */
   1368 /*                          normalize it into the collIterate's writable buffer,          */
   1369 /*                          switch the collIterate's state to use the writable buffer.    */
   1370 /*                                                                                        */
   1371 static
   1372 void collIterNormalize(collIterate *collationSource)
   1373 {
   1374     UErrorCode  status = U_ZERO_ERROR;
   1375     const UChar *srcP = collationSource->pos - 1;      /*  Start of chars to normalize    */
   1376     const UChar *endP = collationSource->fcdPosition;  /* End of region to normalize+1    */
   1377 
   1378     collationSource->nfd->normalize(UnicodeString(FALSE, srcP, (int32_t)(endP - srcP)),
   1379                                     collationSource->writableBuffer,
   1380                                     status);
   1381     if (U_FAILURE(status)) {
   1382 #ifdef UCOL_DEBUG
   1383         fprintf(stderr, "collIterNormalize(), NFD failed, status = %s\n", u_errorName(status));
   1384 #endif
   1385         return;
   1386     }
   1387 
   1388     collationSource->pos        = collationSource->writableBuffer.getTerminatedBuffer();
   1389     collationSource->origFlags  = collationSource->flags;
   1390     collationSource->flags     |= UCOL_ITER_INNORMBUF;
   1391     collationSource->flags     &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN | UCOL_USE_ITERATOR);
   1392 }
   1393 
   1394 
   1395 // This function takes the iterator and extracts normalized stuff up to the next boundary
   1396 // It is similar in the end results to the collIterNormalize, but for the cases when we
   1397 // use an iterator
   1398 /*static
   1399 inline void normalizeIterator(collIterate *collationSource) {
   1400   UErrorCode status = U_ZERO_ERROR;
   1401   UBool wasNormalized = FALSE;
   1402   //int32_t iterIndex = collationSource->iterator->getIndex(collationSource->iterator, UITER_CURRENT);
   1403   uint32_t iterIndex = collationSource->iterator->getState(collationSource->iterator);
   1404   int32_t normLen = unorm_next(collationSource->iterator, collationSource->writableBuffer,
   1405     (int32_t)collationSource->writableBufSize, UNORM_FCD, 0, TRUE, &wasNormalized, &status);
   1406   if(status == U_BUFFER_OVERFLOW_ERROR || normLen == (int32_t)collationSource->writableBufSize) {
   1407     // reallocate and terminate
   1408     if(!u_growBufferFromStatic(collationSource->stackWritableBuffer,
   1409                                &collationSource->writableBuffer,
   1410                                (int32_t *)&collationSource->writableBufSize, normLen + 1,
   1411                                0)
   1412     ) {
   1413     #ifdef UCOL_DEBUG
   1414         fprintf(stderr, "normalizeIterator(), out of memory\n");
   1415     #endif
   1416         return;
   1417     }
   1418     status = U_ZERO_ERROR;
   1419     //collationSource->iterator->move(collationSource->iterator, iterIndex, UITER_ZERO);
   1420     collationSource->iterator->setState(collationSource->iterator, iterIndex, &status);
   1421     normLen = unorm_next(collationSource->iterator, collationSource->writableBuffer,
   1422     (int32_t)collationSource->writableBufSize, UNORM_FCD, 0, TRUE, &wasNormalized, &status);
   1423   }
   1424   // Terminate the buffer - we already checked that it is big enough
   1425   collationSource->writableBuffer[normLen] = 0;
   1426   if(collationSource->writableBuffer != collationSource->stackWritableBuffer) {
   1427       collationSource->flags |= UCOL_ITER_ALLOCATED;
   1428   }
   1429   collationSource->pos        = collationSource->writableBuffer;
   1430   collationSource->origFlags  = collationSource->flags;
   1431   collationSource->flags     |= UCOL_ITER_INNORMBUF;
   1432   collationSource->flags     &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN | UCOL_USE_ITERATOR);
   1433 }*/
   1434 
   1435 
   1436 /* Incremental FCD check and normalize                                                    */
   1437 /*   Called from getNextCE when normalization state is suspect.                           */
   1438 /*   When entering, the state is known to be this:                                        */
   1439 /*      o   We are working in the main buffer of the collIterate, not the side            */
   1440 /*          writable buffer.  When in the side buffer, normalization mode is always off,  */
   1441 /*          so we won't get here.                                                         */
   1442 /*      o   The leading combining class from the current character is 0 or                */
   1443 /*          the trailing combining class of the previous char was zero.                   */
   1444 /*          True because the previous call to this function will have always exited       */
   1445 /*          that way, and we get called for every char where cc might be non-zero.        */
   1446 static
   1447 inline UBool collIterFCD(collIterate *collationSource) {
   1448     const UChar *srcP, *endP;
   1449     uint8_t     leadingCC;
   1450     uint8_t     prevTrailingCC = 0;
   1451     uint16_t    fcd;
   1452     UBool       needNormalize = FALSE;
   1453 
   1454     srcP = collationSource->pos-1;
   1455 
   1456     if (collationSource->flags & UCOL_ITER_HASLEN) {
   1457         endP = collationSource->endp;
   1458     } else {
   1459         endP = NULL;
   1460     }
   1461 
   1462     // Get the trailing combining class of the current character. If it's zero, we are OK.
   1463     fcd = g_nfcImpl->nextFCD16(srcP, endP);
   1464     if (fcd != 0) {
   1465         prevTrailingCC = (uint8_t)(fcd & LAST_BYTE_MASK_);
   1466 
   1467         if (prevTrailingCC != 0) {
   1468             // The current char has a non-zero trailing CC.  Scan forward until we find
   1469             //   a char with a leading cc of zero.
   1470             while (endP == NULL || srcP != endP)
   1471             {
   1472                 const UChar *savedSrcP = srcP;
   1473 
   1474                 fcd = g_nfcImpl->nextFCD16(srcP, endP);
   1475                 leadingCC = (uint8_t)(fcd >> SECOND_LAST_BYTE_SHIFT_);
   1476                 if (leadingCC == 0) {
   1477                     srcP = savedSrcP;      // Hit char that is not part of combining sequence.
   1478                                            //   back up over it.  (Could be surrogate pair!)
   1479                     break;
   1480                 }
   1481 
   1482                 if (leadingCC < prevTrailingCC) {
   1483                     needNormalize = TRUE;
   1484                 }
   1485 
   1486                 prevTrailingCC = (uint8_t)(fcd & LAST_BYTE_MASK_);
   1487             }
   1488         }
   1489     }
   1490 
   1491     collationSource->fcdPosition = (UChar *)srcP;
   1492 
   1493     return needNormalize;
   1494 }
   1495 
   1496 /****************************************************************************/
   1497 /* Following are the CE retrieval functions                                 */
   1498 /*                                                                          */
   1499 /****************************************************************************/
   1500 
   1501 static uint32_t getImplicit(UChar32 cp, collIterate *collationSource);
   1502 static uint32_t getPrevImplicit(UChar32 cp, collIterate *collationSource);
   1503 
   1504 /* there should be a macro version of this function in the header file */
   1505 /* This is the first function that tries to fetch a collation element  */
   1506 /* If it's not succesfull or it encounters a more difficult situation  */
   1507 /* some more sofisticated and slower functions are invoked             */
   1508 static
   1509 inline uint32_t ucol_IGetNextCE(const UCollator *coll, collIterate *collationSource, UErrorCode *status) {
   1510     uint32_t order = 0;
   1511     if (collationSource->CEpos > collationSource->toReturn) {       /* Are there any CEs from previous expansions? */
   1512         order = *(collationSource->toReturn++);                         /* if so, return them */
   1513         if(collationSource->CEpos == collationSource->toReturn) {
   1514             collationSource->CEpos = collationSource->toReturn = collationSource->extendCEs ? collationSource->extendCEs : collationSource->CEs;
   1515         }
   1516         return order;
   1517     }
   1518 
   1519     UChar ch = 0;
   1520     collationSource->offsetReturn = NULL;
   1521 
   1522     do {
   1523         for (;;)                           /* Loop handles case when incremental normalize switches   */
   1524         {                                  /*   to or from the side buffer / original string, and we  */
   1525             /*   need to start again to get the next character.        */
   1526 
   1527             if ((collationSource->flags & (UCOL_ITER_HASLEN | UCOL_ITER_INNORMBUF | UCOL_ITER_NORM | UCOL_HIRAGANA_Q | UCOL_USE_ITERATOR)) == 0)
   1528             {
   1529                 // The source string is null terminated and we're not working from the side buffer,
   1530                 //   and we're not normalizing.  This is the fast path.
   1531                 //   (We can be in the side buffer for Thai pre-vowel reordering even when not normalizing.)
   1532                 ch = *collationSource->pos++;
   1533                 if (ch != 0) {
   1534                     break;
   1535                 }
   1536                 else {
   1537                     return UCOL_NO_MORE_CES;
   1538                 }
   1539             }
   1540 
   1541             if (collationSource->flags & UCOL_ITER_HASLEN) {
   1542                 // Normal path for strings when length is specified.
   1543                 //   (We can't be in side buffer because it is always null terminated.)
   1544                 if (collationSource->pos >= collationSource->endp) {
   1545                     // Ran off of the end of the main source string.  We're done.
   1546                     return UCOL_NO_MORE_CES;
   1547                 }
   1548                 ch = *collationSource->pos++;
   1549             }
   1550             else if(collationSource->flags & UCOL_USE_ITERATOR) {
   1551                 UChar32 iterCh = collationSource->iterator->next(collationSource->iterator);
   1552                 if(iterCh == U_SENTINEL) {
   1553                     return UCOL_NO_MORE_CES;
   1554                 }
   1555                 ch = (UChar)iterCh;
   1556             }
   1557             else
   1558             {
   1559                 // Null terminated string.
   1560                 ch = *collationSource->pos++;
   1561                 if (ch == 0) {
   1562                     // Ran off end of buffer.
   1563                     if ((collationSource->flags & UCOL_ITER_INNORMBUF) == 0) {
   1564                         // Ran off end of main string. backing up one character.
   1565                         collationSource->pos--;
   1566                         return UCOL_NO_MORE_CES;
   1567                     }
   1568                     else
   1569                     {
   1570                         // Hit null in the normalize side buffer.
   1571                         // Usually this means the end of the normalized data,
   1572                         // except for one odd case: a null followed by combining chars,
   1573                         //   which is the case if we are at the start of the buffer.
   1574                         if (collationSource->pos == collationSource->writableBuffer.getBuffer()+1) {
   1575                             break;
   1576                         }
   1577 
   1578                         //  Null marked end of side buffer.
   1579                         //   Revert to the main string and
   1580                         //   loop back to top to try again to get a character.
   1581                         collationSource->pos   = collationSource->fcdPosition;
   1582                         collationSource->flags = collationSource->origFlags;
   1583                         continue;
   1584                     }
   1585                 }
   1586             }
   1587 
   1588             if(collationSource->flags&UCOL_HIRAGANA_Q) {
   1589                 /* Codepoints \u3099-\u309C are both Hiragana and Katakana. Set the flag
   1590                  * based on whether the previous codepoint was Hiragana or Katakana.
   1591                  */
   1592                 if(((ch>=0x3040 && ch<=0x3096) || (ch >= 0x309d && ch <= 0x309f)) ||
   1593                         ((collationSource->flags & UCOL_WAS_HIRAGANA) && (ch >= 0x3099 && ch <= 0x309C))) {
   1594                     collationSource->flags |= UCOL_WAS_HIRAGANA;
   1595                 } else {
   1596                     collationSource->flags &= ~UCOL_WAS_HIRAGANA;
   1597                 }
   1598             }
   1599 
   1600             // We've got a character.  See if there's any fcd and/or normalization stuff to do.
   1601             //    Note that UCOL_ITER_NORM flag is always zero when we are in the side buffer.
   1602             if ((collationSource->flags & UCOL_ITER_NORM) == 0) {
   1603                 break;
   1604             }
   1605 
   1606             if (collationSource->fcdPosition >= collationSource->pos) {
   1607                 // An earlier FCD check has already covered the current character.
   1608                 // We can go ahead and process this char.
   1609                 break;
   1610             }
   1611 
   1612             if (ch < ZERO_CC_LIMIT_ ) {
   1613                 // Fast fcd safe path.  Trailing combining class == 0.  This char is OK.
   1614                 break;
   1615             }
   1616 
   1617             if (ch < NFC_ZERO_CC_BLOCK_LIMIT_) {
   1618                 // We need to peek at the next character in order to tell if we are FCD
   1619                 if ((collationSource->flags & UCOL_ITER_HASLEN) && collationSource->pos >= collationSource->endp) {
   1620                     // We are at the last char of source string.
   1621                     //  It is always OK for FCD check.
   1622                     break;
   1623                 }
   1624 
   1625                 // Not at last char of source string (or we'll check against terminating null).  Do the FCD fast test
   1626                 if (*collationSource->pos < NFC_ZERO_CC_BLOCK_LIMIT_) {
   1627                     break;
   1628                 }
   1629             }
   1630 
   1631 
   1632             // Need a more complete FCD check and possible normalization.
   1633             if (collIterFCD(collationSource)) {
   1634                 collIterNormalize(collationSource);
   1635             }
   1636             if ((collationSource->flags & UCOL_ITER_INNORMBUF) == 0) {
   1637                 //  No normalization was needed.  Go ahead and process the char we already had.
   1638                 break;
   1639             }
   1640 
   1641             // Some normalization happened.  Next loop iteration will pick up a char
   1642             //   from the normalization buffer.
   1643 
   1644         }   // end for (;;)
   1645 
   1646 
   1647         if (ch <= 0xFF) {
   1648             /*  For latin-1 characters we never need to fall back to the UCA table        */
   1649             /*    because all of the UCA data is replicated in the latinOneMapping array  */
   1650             order = coll->latinOneMapping[ch];
   1651             if (order > UCOL_NOT_FOUND) {
   1652                 order = ucol_prv_getSpecialCE(coll, ch, order, collationSource, status);
   1653             }
   1654         }
   1655         else
   1656         {
   1657             // Always use UCA for Han, Hangul
   1658             // (Han extension A is before main Han block)
   1659             // **** Han compatibility chars ?? ****
   1660             if ((collationSource->flags & UCOL_FORCE_HAN_IMPLICIT) != 0 &&
   1661                 (ch >= UCOL_FIRST_HAN_A && ch <= UCOL_LAST_HANGUL)) {
   1662                 if (ch > UCOL_LAST_HAN && ch < UCOL_FIRST_HANGUL) {
   1663                     // between the two target ranges; do normal lookup
   1664                     // **** this range is YI, Modifier tone letters, ****
   1665                     // **** Latin-D, Syloti Nagari, Phagas-pa.       ****
   1666                     // **** Latin-D might be tailored, so we need to ****
   1667                     // **** do the normal lookup for these guys.     ****
   1668                     order = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
   1669                 } else {
   1670                     // in one of the target ranges; use UCA
   1671                     order = UCOL_NOT_FOUND;
   1672                 }
   1673             } else {
   1674                 order = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
   1675             }
   1676 
   1677             if(order > UCOL_NOT_FOUND) {                                       /* if a CE is special                */
   1678                 order = ucol_prv_getSpecialCE(coll, ch, order, collationSource, status);    /* and try to get the special CE     */
   1679             }
   1680 
   1681             if(order == UCOL_NOT_FOUND && coll->UCA) {   /* We couldn't find a good CE in the tailoring */
   1682                 /* if we got here, the codepoint MUST be over 0xFF - so we look directly in the trie */
   1683                 order = UTRIE_GET32_FROM_LEAD(&coll->UCA->mapping, ch);
   1684 
   1685                 if(order > UCOL_NOT_FOUND) { /* UCA also gives us a special CE */
   1686                     order = ucol_prv_getSpecialCE(coll->UCA, ch, order, collationSource, status);
   1687                 }
   1688             }
   1689         }
   1690     } while ( order == UCOL_IGNORABLE && ch >= UCOL_FIRST_HANGUL && ch <= UCOL_LAST_HANGUL );
   1691 
   1692     if(order == UCOL_NOT_FOUND) {
   1693         order = getImplicit(ch, collationSource);
   1694     }
   1695     return order; /* return the CE */
   1696 }
   1697 
   1698 /* ucol_getNextCE, out-of-line version for use from other files.   */
   1699 U_CAPI uint32_t  U_EXPORT2
   1700 ucol_getNextCE(const UCollator *coll, collIterate *collationSource, UErrorCode *status) {
   1701     return ucol_IGetNextCE(coll, collationSource, status);
   1702 }
   1703 
   1704 
   1705 /**
   1706 * Incremental previous normalization happens here. Pick up the range of chars
   1707 * identifed by FCD, normalize it into the collIterate's writable buffer,
   1708 * switch the collIterate's state to use the writable buffer.
   1709 * @param data collation iterator data
   1710 */
   1711 static
   1712 void collPrevIterNormalize(collIterate *data)
   1713 {
   1714     UErrorCode status  = U_ZERO_ERROR;
   1715     const UChar *pEnd   = data->pos;  /* End normalize + 1 */
   1716     const UChar *pStart;
   1717 
   1718     /* Start normalize */
   1719     if (data->fcdPosition == NULL) {
   1720         pStart = data->string;
   1721     }
   1722     else {
   1723         pStart = data->fcdPosition + 1;
   1724     }
   1725 
   1726     int32_t normLen =
   1727         data->nfd->normalize(UnicodeString(FALSE, pStart, (int32_t)((pEnd - pStart) + 1)),
   1728                              data->writableBuffer,
   1729                              status).
   1730         length();
   1731     if(U_FAILURE(status)) {
   1732         return;
   1733     }
   1734     /*
   1735     this puts the null termination infront of the normalized string instead
   1736     of the end
   1737     */
   1738     data->writableBuffer.insert(0, (UChar)0);
   1739 
   1740     /*
   1741      * The usual case at this point is that we've got a base
   1742      * character followed by marks that were normalized. If
   1743      * fcdPosition is NULL, that means that we backed up to
   1744      * the beginning of the string and there's no base character.
   1745      *
   1746      * Forward processing will usually normalize when it sees
   1747      * the first mark, so that mark will get it's natural offset
   1748      * and the rest will get the offset of the character following
   1749      * the marks. The base character will also get its natural offset.
   1750      *
   1751      * We write the offset of the base character, if there is one,
   1752      * followed by the offset of the first mark and then the offsets
   1753      * of the rest of the marks.
   1754      */
   1755     int32_t firstMarkOffset = 0;
   1756     int32_t trailOffset     = (int32_t)(data->pos - data->string + 1);
   1757     int32_t trailCount      = normLen - 1;
   1758 
   1759     if (data->fcdPosition != NULL) {
   1760         int32_t baseOffset = (int32_t)(data->fcdPosition - data->string);
   1761         UChar   baseChar   = *data->fcdPosition;
   1762 
   1763         firstMarkOffset = baseOffset + 1;
   1764 
   1765         /*
   1766          * If the base character is the start of a contraction, forward processing
   1767          * will normalize the marks while checking for the contraction, which means
   1768          * that the offset of the first mark will the same as the other marks.
   1769          *
   1770          * **** THIS IS PROBABLY NOT A COMPLETE TEST ****
   1771          */
   1772         if (baseChar >= 0x100) {
   1773             uint32_t baseOrder = UTRIE_GET32_FROM_LEAD(&data->coll->mapping, baseChar);
   1774 
   1775             if (baseOrder == UCOL_NOT_FOUND && data->coll->UCA) {
   1776                 baseOrder = UTRIE_GET32_FROM_LEAD(&data->coll->UCA->mapping, baseChar);
   1777             }
   1778 
   1779             if (baseOrder > UCOL_NOT_FOUND && getCETag(baseOrder) == CONTRACTION_TAG) {
   1780                 firstMarkOffset = trailOffset;
   1781             }
   1782         }
   1783 
   1784         data->appendOffset(baseOffset, status);
   1785     }
   1786 
   1787     data->appendOffset(firstMarkOffset, status);
   1788 
   1789     for (int32_t i = 0; i < trailCount; i += 1) {
   1790         data->appendOffset(trailOffset, status);
   1791     }
   1792 
   1793     data->offsetRepeatValue = trailOffset;
   1794 
   1795     data->offsetReturn = data->offsetStore - 1;
   1796     if (data->offsetReturn == data->offsetBuffer) {
   1797         data->offsetStore = data->offsetBuffer;
   1798     }
   1799 
   1800     data->pos        = data->writableBuffer.getTerminatedBuffer() + 1 + normLen;
   1801     data->origFlags  = data->flags;
   1802     data->flags     |= UCOL_ITER_INNORMBUF;
   1803     data->flags     &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
   1804 }
   1805 
   1806 
   1807 /**
   1808 * Incremental FCD check for previous iteration and normalize. Called from
   1809 * getPrevCE when normalization state is suspect.
   1810 * When entering, the state is known to be this:
   1811 * o  We are working in the main buffer of the collIterate, not the side
   1812 *    writable buffer. When in the side buffer, normalization mode is always
   1813 *    off, so we won't get here.
   1814 * o  The leading combining class from the current character is 0 or the
   1815 *    trailing combining class of the previous char was zero.
   1816 *    True because the previous call to this function will have always exited
   1817 *    that way, and we get called for every char where cc might be non-zero.
   1818 * @param data collation iterate struct
   1819 * @return normalization status, TRUE for normalization to be done, FALSE
   1820 *         otherwise
   1821 */
   1822 static
   1823 inline UBool collPrevIterFCD(collIterate *data)
   1824 {
   1825     const UChar *src, *start;
   1826     uint8_t     leadingCC;
   1827     uint8_t     trailingCC = 0;
   1828     uint16_t    fcd;
   1829     UBool       result = FALSE;
   1830 
   1831     start = data->string;
   1832     src = data->pos + 1;
   1833 
   1834     /* Get the trailing combining class of the current character. */
   1835     fcd = g_nfcImpl->previousFCD16(start, src);
   1836 
   1837     leadingCC = (uint8_t)(fcd >> SECOND_LAST_BYTE_SHIFT_);
   1838 
   1839     if (leadingCC != 0) {
   1840         /*
   1841         The current char has a non-zero leading combining class.
   1842         Scan backward until we find a char with a trailing cc of zero.
   1843         */
   1844         for (;;)
   1845         {
   1846             if (start == src) {
   1847                 data->fcdPosition = NULL;
   1848                 return result;
   1849             }
   1850 
   1851             fcd = g_nfcImpl->previousFCD16(start, src);
   1852 
   1853             trailingCC = (uint8_t)(fcd & LAST_BYTE_MASK_);
   1854 
   1855             if (trailingCC == 0) {
   1856                 break;
   1857             }
   1858 
   1859             if (leadingCC < trailingCC) {
   1860                 result = TRUE;
   1861             }
   1862 
   1863             leadingCC = (uint8_t)(fcd >> SECOND_LAST_BYTE_SHIFT_);
   1864         }
   1865     }
   1866 
   1867     data->fcdPosition = (UChar *)src;
   1868 
   1869     return result;
   1870 }
   1871 
   1872 /** gets a code unit from the string at a given offset
   1873  *  Handles both normal and iterative cases.
   1874  *  No error checking - caller beware!
   1875  */
   1876 static inline
   1877 UChar peekCodeUnit(collIterate *source, int32_t offset) {
   1878     if(source->pos != NULL) {
   1879         return *(source->pos + offset);
   1880     } else if(source->iterator != NULL) {
   1881         UChar32 c;
   1882         if(offset != 0) {
   1883             source->iterator->move(source->iterator, offset, UITER_CURRENT);
   1884             c = source->iterator->next(source->iterator);
   1885             source->iterator->move(source->iterator, -offset-1, UITER_CURRENT);
   1886         } else {
   1887             c = source->iterator->current(source->iterator);
   1888         }
   1889         return c >= 0 ? (UChar)c : 0xfffd;  // If the caller works properly, we should never see c<0.
   1890     } else {
   1891         return 0xfffd;
   1892     }
   1893 }
   1894 
   1895 // Code point version. Treats the offset as a _code point_ delta.
   1896 // We cannot use U16_FWD_1_UNSAFE and similar because we might not have well-formed UTF-16.
   1897 // We cannot use U16_FWD_1 and similar because we do not know the start and limit of the buffer.
   1898 static inline
   1899 UChar32 peekCodePoint(collIterate *source, int32_t offset) {
   1900     UChar32 c;
   1901     if(source->pos != NULL) {
   1902         const UChar *p = source->pos;
   1903         if(offset >= 0) {
   1904             // Skip forward over (offset-1) code points.
   1905             while(--offset >= 0) {
   1906                 if(U16_IS_LEAD(*p++) && U16_IS_TRAIL(*p)) {
   1907                     ++p;
   1908                 }
   1909             }
   1910             // Read the code point there.
   1911             c = *p++;
   1912             UChar trail;
   1913             if(U16_IS_LEAD(c) && U16_IS_TRAIL(trail = *p)) {
   1914                 c = U16_GET_SUPPLEMENTARY(c, trail);
   1915             }
   1916         } else /* offset<0 */ {
   1917             // Skip backward over (offset-1) code points.
   1918             while(++offset < 0) {
   1919                 if(U16_IS_TRAIL(*--p) && U16_IS_LEAD(*(p - 1))) {
   1920                     --p;
   1921                 }
   1922             }
   1923             // Read the code point before that.
   1924             c = *--p;
   1925             UChar lead;
   1926             if(U16_IS_TRAIL(c) && U16_IS_LEAD(lead = *(p - 1))) {
   1927                 c = U16_GET_SUPPLEMENTARY(lead, c);
   1928             }
   1929         }
   1930     } else if(source->iterator != NULL) {
   1931         if(offset >= 0) {
   1932             // Skip forward over (offset-1) code points.
   1933             int32_t fwd = offset;
   1934             while(fwd-- > 0) {
   1935                 uiter_next32(source->iterator);
   1936             }
   1937             // Read the code point there.
   1938             c = uiter_current32(source->iterator);
   1939             // Return to the starting point, skipping backward over (offset-1) code points.
   1940             while(offset-- > 0) {
   1941                 uiter_previous32(source->iterator);
   1942             }
   1943         } else /* offset<0 */ {
   1944             // Read backward, reading offset code points, remember only the last-read one.
   1945             int32_t back = offset;
   1946             do {
   1947                 c = uiter_previous32(source->iterator);
   1948             } while(++back < 0);
   1949             // Return to the starting position, skipping forward over offset code points.
   1950             do {
   1951                 uiter_next32(source->iterator);
   1952             } while(++offset < 0);
   1953         }
   1954     } else {
   1955         c = U_SENTINEL;
   1956     }
   1957     return c;
   1958 }
   1959 
   1960 /**
   1961 * Determines if we are at the start of the data string in the backwards
   1962 * collation iterator
   1963 * @param data collation iterator
   1964 * @return TRUE if we are at the start
   1965 */
   1966 static
   1967 inline UBool isAtStartPrevIterate(collIterate *data) {
   1968     if(data->pos == NULL && data->iterator != NULL) {
   1969         return !data->iterator->hasPrevious(data->iterator);
   1970     }
   1971     //return (collIter_bos(data)) ||
   1972     return (data->pos == data->string) ||
   1973               ((data->flags & UCOL_ITER_INNORMBUF) && (data->pos != NULL) &&
   1974               *(data->pos - 1) == 0 && data->fcdPosition == NULL);
   1975 }
   1976 
   1977 static
   1978 inline void goBackOne(collIterate *data) {
   1979 # if 0
   1980     // somehow, it looks like we need to keep iterator synced up
   1981     // at all times, as above.
   1982     if(data->pos) {
   1983         data->pos--;
   1984     }
   1985     if(data->iterator) {
   1986         data->iterator->previous(data->iterator);
   1987     }
   1988 #endif
   1989     if(data->iterator && (data->flags & UCOL_USE_ITERATOR)) {
   1990         data->iterator->previous(data->iterator);
   1991     }
   1992     if(data->pos) {
   1993         data->pos --;
   1994     }
   1995 }
   1996 
   1997 /**
   1998 * Inline function that gets a simple CE.
   1999 * So what it does is that it will first check the expansion buffer. If the
   2000 * expansion buffer is not empty, ie the end pointer to the expansion buffer
   2001 * is different from the string pointer, we return the collation element at the
   2002 * return pointer and decrement it.
   2003 * For more complicated CEs it resorts to getComplicatedCE.
   2004 * @param coll collator data
   2005 * @param data collation iterator struct
   2006 * @param status error status
   2007 */
   2008 static
   2009 inline uint32_t ucol_IGetPrevCE(const UCollator *coll, collIterate *data,
   2010                                UErrorCode *status)
   2011 {
   2012     uint32_t result = (uint32_t)UCOL_NULLORDER;
   2013 
   2014     if (data->offsetReturn != NULL) {
   2015         if (data->offsetRepeatCount > 0) {
   2016                 data->offsetRepeatCount -= 1;
   2017         } else {
   2018             if (data->offsetReturn == data->offsetBuffer) {
   2019                 data->offsetReturn = NULL;
   2020                 data->offsetStore  = data->offsetBuffer;
   2021             } else {
   2022                 data->offsetReturn -= 1;
   2023             }
   2024         }
   2025     }
   2026 
   2027     if ((data->extendCEs && data->toReturn > data->extendCEs) ||
   2028             (!data->extendCEs && data->toReturn > data->CEs))
   2029     {
   2030         data->toReturn -= 1;
   2031         result = *(data->toReturn);
   2032         if (data->CEs == data->toReturn || data->extendCEs == data->toReturn) {
   2033             data->CEpos = data->toReturn;
   2034         }
   2035     }
   2036     else {
   2037         UChar ch = 0;
   2038 
   2039         do {
   2040             /*
   2041             Loop handles case when incremental normalize switches to or from the
   2042             side buffer / original string, and we need to start again to get the
   2043             next character.
   2044             */
   2045             for (;;) {
   2046                 if (data->flags & UCOL_ITER_HASLEN) {
   2047                     /*
   2048                     Normal path for strings when length is specified.
   2049                     Not in side buffer because it is always null terminated.
   2050                     */
   2051                     if (data->pos <= data->string) {
   2052                         /* End of the main source string */
   2053                         return UCOL_NO_MORE_CES;
   2054                     }
   2055                     data->pos --;
   2056                     ch = *data->pos;
   2057                 }
   2058                 // we are using an iterator to go back. Pray for us!
   2059                 else if (data->flags & UCOL_USE_ITERATOR) {
   2060                   UChar32 iterCh = data->iterator->previous(data->iterator);
   2061                   if(iterCh == U_SENTINEL) {
   2062                     return UCOL_NO_MORE_CES;
   2063                   } else {
   2064                     ch = (UChar)iterCh;
   2065                   }
   2066                 }
   2067                 else {
   2068                     data->pos --;
   2069                     ch = *data->pos;
   2070                     /* we are in the side buffer. */
   2071                     if (ch == 0) {
   2072                         /*
   2073                         At the start of the normalize side buffer.
   2074                         Go back to string.
   2075                         Because pointer points to the last accessed character,
   2076                         hence we have to increment it by one here.
   2077                         */
   2078                         data->flags = data->origFlags;
   2079                         data->offsetRepeatValue = 0;
   2080 
   2081                          if (data->fcdPosition == NULL) {
   2082                             data->pos = data->string;
   2083                             return UCOL_NO_MORE_CES;
   2084                         }
   2085                         else {
   2086                             data->pos   = data->fcdPosition + 1;
   2087                         }
   2088 
   2089                        continue;
   2090                     }
   2091                 }
   2092 
   2093                 if(data->flags&UCOL_HIRAGANA_Q) {
   2094                   if(ch>=0x3040 && ch<=0x309f) {
   2095                     data->flags |= UCOL_WAS_HIRAGANA;
   2096                   } else {
   2097                     data->flags &= ~UCOL_WAS_HIRAGANA;
   2098                   }
   2099                 }
   2100 
   2101                 /*
   2102                 * got a character to determine if there's fcd and/or normalization
   2103                 * stuff to do.
   2104                 * if the current character is not fcd.
   2105                 * if current character is at the start of the string
   2106                 * Trailing combining class == 0.
   2107                 * Note if pos is in the writablebuffer, norm is always 0
   2108                 */
   2109                 if (ch < ZERO_CC_LIMIT_ ||
   2110                   // this should propel us out of the loop in the iterator case
   2111                     (data->flags & UCOL_ITER_NORM) == 0 ||
   2112                     (data->fcdPosition != NULL && data->fcdPosition <= data->pos)
   2113                     || data->string == data->pos) {
   2114                     break;
   2115                 }
   2116 
   2117                 if (ch < NFC_ZERO_CC_BLOCK_LIMIT_) {
   2118                     /* if next character is FCD */
   2119                     if (data->pos == data->string) {
   2120                         /* First char of string is always OK for FCD check */
   2121                         break;
   2122                     }
   2123 
   2124                     /* Not first char of string, do the FCD fast test */
   2125                     if (*(data->pos - 1) < NFC_ZERO_CC_BLOCK_LIMIT_) {
   2126                         break;
   2127                     }
   2128                 }
   2129 
   2130                 /* Need a more complete FCD check and possible normalization. */
   2131                 if (collPrevIterFCD(data)) {
   2132                     collPrevIterNormalize(data);
   2133                 }
   2134 
   2135                 if ((data->flags & UCOL_ITER_INNORMBUF) == 0) {
   2136                     /*  No normalization. Go ahead and process the char. */
   2137                     break;
   2138                 }
   2139 
   2140                 /*
   2141                 Some normalization happened.
   2142                 Next loop picks up a char from the normalization buffer.
   2143                 */
   2144             }
   2145 
   2146             /* attempt to handle contractions, after removal of the backwards
   2147             contraction
   2148             */
   2149             if (ucol_contractionEndCP(ch, coll) && !isAtStartPrevIterate(data)) {
   2150                 result = ucol_prv_getSpecialPrevCE(coll, ch, UCOL_CONTRACTION, data, status);
   2151             } else {
   2152                 if (ch <= 0xFF) {
   2153                     result = coll->latinOneMapping[ch];
   2154                 }
   2155                 else {
   2156                     // Always use UCA for [3400..9FFF], [AC00..D7AF]
   2157                     // **** [FA0E..FA2F] ?? ****
   2158                     if ((data->flags & UCOL_FORCE_HAN_IMPLICIT) != 0 &&
   2159                         (ch >= 0x3400 && ch <= 0xD7AF)) {
   2160                         if (ch > 0x9FFF && ch < 0xAC00) {
   2161                             // between the two target ranges; do normal lookup
   2162                             // **** this range is YI, Modifier tone letters, ****
   2163                             // **** Latin-D, Syloti Nagari, Phagas-pa.       ****
   2164                             // **** Latin-D might be tailored, so we need to ****
   2165                             // **** do the normal lookup for these guys.     ****
   2166                              result = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
   2167                         } else {
   2168                             result = UCOL_NOT_FOUND;
   2169                         }
   2170                     } else {
   2171                         result = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
   2172                     }
   2173                 }
   2174                 if (result > UCOL_NOT_FOUND) {
   2175                     result = ucol_prv_getSpecialPrevCE(coll, ch, result, data, status);
   2176                 }
   2177                 if (result == UCOL_NOT_FOUND) { // Not found in master list
   2178                     if (!isAtStartPrevIterate(data) &&
   2179                         ucol_contractionEndCP(ch, data->coll))
   2180                     {
   2181                         result = UCOL_CONTRACTION;
   2182                     } else {
   2183                         if(coll->UCA) {
   2184                             result = UTRIE_GET32_FROM_LEAD(&coll->UCA->mapping, ch);
   2185                         }
   2186                     }
   2187 
   2188                     if (result > UCOL_NOT_FOUND) {
   2189                         if(coll->UCA) {
   2190                             result = ucol_prv_getSpecialPrevCE(coll->UCA, ch, result, data, status);
   2191                         }
   2192                     }
   2193                 }
   2194             }
   2195         } while ( result == UCOL_IGNORABLE && ch >= UCOL_FIRST_HANGUL && ch <= UCOL_LAST_HANGUL );
   2196 
   2197         if(result == UCOL_NOT_FOUND) {
   2198             result = getPrevImplicit(ch, data);
   2199         }
   2200     }
   2201 
   2202     return result;
   2203 }
   2204 
   2205 
   2206 /*   ucol_getPrevCE, out-of-line version for use from other files.  */
   2207 U_CFUNC uint32_t  U_EXPORT2
   2208 ucol_getPrevCE(const UCollator *coll, collIterate *data,
   2209                         UErrorCode *status) {
   2210     return ucol_IGetPrevCE(coll, data, status);
   2211 }
   2212 
   2213 
   2214 /* this should be connected to special Jamo handling */
   2215 U_CFUNC uint32_t  U_EXPORT2
   2216 ucol_getFirstCE(const UCollator *coll, UChar u, UErrorCode *status) {
   2217     collIterate colIt;
   2218     IInit_collIterate(coll, &u, 1, &colIt, status);
   2219     if(U_FAILURE(*status)) {
   2220         return 0;
   2221     }
   2222     return ucol_IGetNextCE(coll, &colIt, status);
   2223 }
   2224 
   2225 /**
   2226 * Inserts the argument character into the end of the buffer pushing back the
   2227 * null terminator.
   2228 * @param data collIterate struct data
   2229 * @param ch character to be appended
   2230 * @return the position of the new addition
   2231 */
   2232 static
   2233 inline const UChar * insertBufferEnd(collIterate *data, UChar ch)
   2234 {
   2235     int32_t oldLength = data->writableBuffer.length();
   2236     return data->writableBuffer.append(ch).getTerminatedBuffer() + oldLength;
   2237 }
   2238 
   2239 /**
   2240 * Inserts the argument string into the end of the buffer pushing back the
   2241 * null terminator.
   2242 * @param data collIterate struct data
   2243 * @param string to be appended
   2244 * @param length of the string to be appended
   2245 * @return the position of the new addition
   2246 */
   2247 static
   2248 inline const UChar * insertBufferEnd(collIterate *data, const UChar *str, int32_t length)
   2249 {
   2250     int32_t oldLength = data->writableBuffer.length();
   2251     return data->writableBuffer.append(str, length).getTerminatedBuffer() + oldLength;
   2252 }
   2253 
   2254 /**
   2255 * Special normalization function for contraction in the forwards iterator.
   2256 * This normalization sequence will place the current character at source->pos
   2257 * and its following normalized sequence into the buffer.
   2258 * The fcd position, pos will be changed.
   2259 * pos will now point to positions in the buffer.
   2260 * Flags will be changed accordingly.
   2261 * @param data collation iterator data
   2262 */
   2263 static
   2264 inline void normalizeNextContraction(collIterate *data)
   2265 {
   2266     int32_t     strsize;
   2267     UErrorCode  status     = U_ZERO_ERROR;
   2268     /* because the pointer points to the next character */
   2269     const UChar *pStart    = data->pos - 1;
   2270     const UChar *pEnd;
   2271 
   2272     if ((data->flags & UCOL_ITER_INNORMBUF) == 0) {
   2273         data->writableBuffer.setTo(*(pStart - 1));
   2274         strsize               = 1;
   2275     }
   2276     else {
   2277         strsize = data->writableBuffer.length();
   2278     }
   2279 
   2280     pEnd = data->fcdPosition;
   2281 
   2282     data->writableBuffer.append(
   2283         data->nfd->normalize(UnicodeString(FALSE, pStart, (int32_t)(pEnd - pStart)), status));
   2284     if(U_FAILURE(status)) {
   2285         return;
   2286     }
   2287 
   2288     data->pos        = data->writableBuffer.getTerminatedBuffer() + strsize;
   2289     data->origFlags  = data->flags;
   2290     data->flags     |= UCOL_ITER_INNORMBUF;
   2291     data->flags     &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
   2292 }
   2293 
   2294 /**
   2295 * Contraction character management function that returns the next character
   2296 * for the forwards iterator.
   2297 * Does nothing if the next character is in buffer and not the first character
   2298 * in it.
   2299 * Else it checks next character in data string to see if it is normalizable.
   2300 * If it is not, the character is simply copied into the buffer, else
   2301 * the whole normalized substring is copied into the buffer, including the
   2302 * current character.
   2303 * @param data collation element iterator data
   2304 * @return next character
   2305 */
   2306 static
   2307 inline UChar getNextNormalizedChar(collIterate *data)
   2308 {
   2309     UChar  nextch;
   2310     UChar  ch;
   2311     // Here we need to add the iterator code. One problem is the way
   2312     // end of string is handled. If we just return next char, it could
   2313     // be the sentinel. Most of the cases already check for this, but we
   2314     // need to be sure.
   2315     if ((data->flags & (UCOL_ITER_NORM | UCOL_ITER_INNORMBUF)) == 0 ) {
   2316          /* if no normalization and not in buffer. */
   2317       if(data->flags & UCOL_USE_ITERATOR) {
   2318          return (UChar)data->iterator->next(data->iterator);
   2319       } else {
   2320          return *(data->pos ++);
   2321       }
   2322     }
   2323 
   2324     //if (data->flags & UCOL_ITER_NORM && data->flags & UCOL_USE_ITERATOR) {
   2325       //normalizeIterator(data);
   2326     //}
   2327 
   2328     UBool  innormbuf = (UBool)(data->flags & UCOL_ITER_INNORMBUF);
   2329     if ((innormbuf && *data->pos != 0) ||
   2330         (data->fcdPosition != NULL && !innormbuf &&
   2331         data->pos < data->fcdPosition)) {
   2332         /*
   2333         if next character is in normalized buffer, no further normalization
   2334         is required
   2335         */
   2336         return *(data->pos ++);
   2337     }
   2338 
   2339     if (data->flags & UCOL_ITER_HASLEN) {
   2340         /* in data string */
   2341         if (data->pos + 1 == data->endp) {
   2342             return *(data->pos ++);
   2343         }
   2344     }
   2345     else {
   2346         if (innormbuf) {
   2347           // inside the normalization buffer, but at the end
   2348           // (since we encountered zero). This means, in the
   2349           // case we're using char iterator, that we need to
   2350           // do another round of normalization.
   2351           //if(data->origFlags & UCOL_USE_ITERATOR) {
   2352             // we need to restore original flags,
   2353             // otherwise, we'll lose them
   2354             //data->flags = data->origFlags;
   2355             //normalizeIterator(data);
   2356             //return *(data->pos++);
   2357           //} else {
   2358             /*
   2359             in writable buffer, at this point fcdPosition can not be
   2360             pointing to the end of the data string. see contracting tag.
   2361             */
   2362           if(data->fcdPosition) {
   2363             if (*(data->fcdPosition + 1) == 0 ||
   2364                 data->fcdPosition + 1 == data->endp) {
   2365                 /* at the end of the string, dump it into the normalizer */
   2366                 data->pos = insertBufferEnd(data, *(data->fcdPosition)) + 1;
   2367                 // Check if data->pos received a null pointer
   2368                 if (data->pos == NULL) {
   2369                     return (UChar)-1; // Return to indicate error.
   2370                 }
   2371                 return *(data->fcdPosition ++);
   2372             }
   2373             data->pos = data->fcdPosition;
   2374           } else if(data->origFlags & UCOL_USE_ITERATOR) {
   2375             // if we are here, we're using a normalizing iterator.
   2376             // we should just continue further.
   2377             data->flags = data->origFlags;
   2378             data->pos = NULL;
   2379             return (UChar)data->iterator->next(data->iterator);
   2380           }
   2381           //}
   2382         }
   2383         else {
   2384             if (*(data->pos + 1) == 0) {
   2385                 return *(data->pos ++);
   2386             }
   2387         }
   2388     }
   2389 
   2390     ch = *data->pos ++;
   2391     nextch = *data->pos;
   2392 
   2393     /*
   2394     * if the current character is not fcd.
   2395     * Trailing combining class == 0.
   2396     */
   2397     if ((data->fcdPosition == NULL || data->fcdPosition < data->pos) &&
   2398         (nextch >= NFC_ZERO_CC_BLOCK_LIMIT_ ||
   2399          ch >= NFC_ZERO_CC_BLOCK_LIMIT_)) {
   2400             /*
   2401             Need a more complete FCD check and possible normalization.
   2402             normalize substring will be appended to buffer
   2403             */
   2404         if (collIterFCD(data)) {
   2405             normalizeNextContraction(data);
   2406             return *(data->pos ++);
   2407         }
   2408         else if (innormbuf) {
   2409             /* fcdposition shifted even when there's no normalization, if we
   2410             don't input the rest into this, we'll get the wrong position when
   2411             we reach the end of the writableBuffer */
   2412             int32_t length = (int32_t)(data->fcdPosition - data->pos + 1);
   2413             data->pos = insertBufferEnd(data, data->pos - 1, length);
   2414             // Check if data->pos received a null pointer
   2415             if (data->pos == NULL) {
   2416                 return (UChar)-1; // Return to indicate error.
   2417             }
   2418             return *(data->pos ++);
   2419         }
   2420     }
   2421 
   2422     if (innormbuf) {
   2423         /*
   2424         no normalization is to be done hence only one character will be
   2425         appended to the buffer.
   2426         */
   2427         data->pos = insertBufferEnd(data, ch) + 1;
   2428         // Check if data->pos received a null pointer
   2429         if (data->pos == NULL) {
   2430             return (UChar)-1; // Return to indicate error.
   2431         }
   2432     }
   2433 
   2434     /* points back to the pos in string */
   2435     return ch;
   2436 }
   2437 
   2438 
   2439 
   2440 /**
   2441 * Function to copy the buffer into writableBuffer and sets the fcd position to
   2442 * the correct position
   2443 * @param source data string source
   2444 * @param buffer character buffer
   2445 */
   2446 static
   2447 inline void setDiscontiguosAttribute(collIterate *source, const UnicodeString &buffer)
   2448 {
   2449     /* okay confusing part here. to ensure that the skipped characters are
   2450     considered later, we need to place it in the appropriate position in the
   2451     normalization buffer and reassign the pos pointer. simple case if pos
   2452     reside in string, simply copy to normalization buffer and
   2453     fcdposition = pos, pos = start of normalization buffer. if pos in
   2454     normalization buffer, we'll insert the copy infront of pos and point pos
   2455     to the start of the normalization buffer. why am i doing these copies?
   2456     well, so that the whole chunk of codes in the getNextCE, ucol_prv_getSpecialCE does
   2457     not require any changes, which be really painful. */
   2458     if (source->flags & UCOL_ITER_INNORMBUF) {
   2459         int32_t replaceLength = source->pos - source->writableBuffer.getBuffer();
   2460         source->writableBuffer.replace(0, replaceLength, buffer);
   2461     }
   2462     else {
   2463         source->fcdPosition  = source->pos;
   2464         source->origFlags    = source->flags;
   2465         source->flags       |= UCOL_ITER_INNORMBUF;
   2466         source->flags       &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN | UCOL_USE_ITERATOR);
   2467         source->writableBuffer = buffer;
   2468     }
   2469 
   2470     source->pos = source->writableBuffer.getTerminatedBuffer();
   2471 }
   2472 
   2473 /**
   2474 * Function to get the discontiguos collation element within the source.
   2475 * Note this function will set the position to the appropriate places.
   2476 * @param coll current collator used
   2477 * @param source data string source
   2478 * @param constart index to the start character in the contraction table
   2479 * @return discontiguos collation element offset
   2480 */
   2481 static
   2482 uint32_t getDiscontiguous(const UCollator *coll, collIterate *source,
   2483                                 const UChar *constart)
   2484 {
   2485     /* source->pos currently points to the second combining character after
   2486        the start character */
   2487           const UChar *temppos      = source->pos;
   2488           UnicodeString buffer;
   2489     const UChar   *tempconstart = constart;
   2490           uint8_t  tempflags    = source->flags;
   2491           UBool    multicontraction = FALSE;
   2492           collIterateState discState;
   2493 
   2494           backupState(source, &discState);
   2495 
   2496     buffer.setTo(peekCodePoint(source, -1));
   2497     for (;;) {
   2498         UChar    *UCharOffset;
   2499         UChar     schar,
   2500                   tchar;
   2501         uint32_t  result;
   2502 
   2503         if (((source->flags & UCOL_ITER_HASLEN) && source->pos >= source->endp)
   2504             || (peekCodeUnit(source, 0) == 0  &&
   2505             //|| (*source->pos == 0  &&
   2506                 ((source->flags & UCOL_ITER_INNORMBUF) == 0 ||
   2507                  source->fcdPosition == NULL ||
   2508                  source->fcdPosition == source->endp ||
   2509                  *(source->fcdPosition) == 0 ||
   2510                  u_getCombiningClass(*(source->fcdPosition)) == 0)) ||
   2511                  /* end of string in null terminated string or stopped by a
   2512                  null character, note fcd does not always point to a base
   2513                  character after the discontiguos change */
   2514                  u_getCombiningClass(peekCodePoint(source, 0)) == 0) {
   2515                  //u_getCombiningClass(*(source->pos)) == 0) {
   2516             //constart = (UChar *)coll->image + getContractOffset(CE);
   2517             if (multicontraction) {
   2518                 source->pos    = temppos - 1;
   2519                 setDiscontiguosAttribute(source, buffer);
   2520                 return *(coll->contractionCEs +
   2521                                     (tempconstart - coll->contractionIndex));
   2522             }
   2523             constart = tempconstart;
   2524             break;
   2525         }
   2526 
   2527         UCharOffset = (UChar *)(tempconstart + 1); /* skip the backward offset*/
   2528         schar = getNextNormalizedChar(source);
   2529 
   2530         while (schar > (tchar = *UCharOffset)) {
   2531             UCharOffset++;
   2532         }
   2533 
   2534         if (schar != tchar) {
   2535             /* not the correct codepoint. we stuff the current codepoint into
   2536             the discontiguos buffer and try the next character */
   2537             buffer.append(schar);
   2538             continue;
   2539         }
   2540         else {
   2541             if (u_getCombiningClass(schar) ==
   2542                 u_getCombiningClass(peekCodePoint(source, -2))) {
   2543                 buffer.append(schar);
   2544                 continue;
   2545             }
   2546             result = *(coll->contractionCEs +
   2547                                       (UCharOffset - coll->contractionIndex));
   2548         }
   2549 
   2550         if (result == UCOL_NOT_FOUND) {
   2551           break;
   2552         } else if (isContraction(result)) {
   2553             /* this is a multi-contraction*/
   2554             tempconstart = (UChar *)coll->image + getContractOffset(result);
   2555             if (*(coll->contractionCEs + (constart - coll->contractionIndex))
   2556                 != UCOL_NOT_FOUND) {
   2557                 multicontraction = TRUE;
   2558                 temppos       = source->pos + 1;
   2559             }
   2560         } else {
   2561             setDiscontiguosAttribute(source, buffer);
   2562             return result;
   2563         }
   2564     }
   2565 
   2566     /* no problems simply reverting just like that,
   2567     if we are in string before getting into this function, points back to
   2568     string hence no problem.
   2569     if we are in normalization buffer before getting into this function,
   2570     since we'll never use another normalization within this function, we
   2571     know that fcdposition points to a base character. the normalization buffer
   2572     never change, hence this revert works. */
   2573     loadState(source, &discState, TRUE);
   2574     goBackOne(source);
   2575 
   2576     //source->pos   = temppos - 1;
   2577     source->flags = tempflags;
   2578     return *(coll->contractionCEs + (constart - coll->contractionIndex));
   2579 }
   2580 
   2581 /* now uses Mark's getImplicitPrimary code */
   2582 static
   2583 inline uint32_t getImplicit(UChar32 cp, collIterate *collationSource) {
   2584     uint32_t r = uprv_uca_getImplicitPrimary(cp);
   2585     *(collationSource->CEpos++) = ((r & 0x0000FFFF)<<16) | 0x000000C0;
   2586     collationSource->offsetRepeatCount += 1;
   2587     return (r & UCOL_PRIMARYMASK) | 0x00000505; // This was 'order'
   2588 }
   2589 
   2590 /**
   2591 * Inserts the argument character into the front of the buffer replacing the
   2592 * front null terminator.
   2593 * @param data collation element iterator data
   2594 * @param ch character to be appended
   2595 */
   2596 static
   2597 inline void insertBufferFront(collIterate *data, UChar ch)
   2598 {
   2599     data->pos = data->writableBuffer.setCharAt(0, ch).insert(0, (UChar)0).getTerminatedBuffer() + 2;
   2600 }
   2601 
   2602 /**
   2603 * Special normalization function for contraction in the previous iterator.
   2604 * This normalization sequence will place the current character at source->pos
   2605 * and its following normalized sequence into the buffer.
   2606 * The fcd position, pos will be changed.
   2607 * pos will now point to positions in the buffer.
   2608 * Flags will be changed accordingly.
   2609 * @param data collation iterator data
   2610 */
   2611 static
   2612 inline void normalizePrevContraction(collIterate *data, UErrorCode *status)
   2613 {
   2614     const UChar *pEnd = data->pos + 1;         /* End normalize + 1 */
   2615     const UChar *pStart;
   2616 
   2617     UnicodeString endOfBuffer;
   2618     if (data->flags & UCOL_ITER_HASLEN) {
   2619         /*
   2620         normalization buffer not used yet, we'll pull down the next
   2621         character into the end of the buffer
   2622         */
   2623         endOfBuffer.setTo(*pEnd);
   2624     }
   2625     else {
   2626         endOfBuffer.setTo(data->writableBuffer, 1);  // after the leading NUL
   2627     }
   2628 
   2629     if (data->fcdPosition == NULL) {
   2630         pStart = data->string;
   2631     }
   2632     else {
   2633         pStart = data->fcdPosition + 1;
   2634     }
   2635     int32_t normLen =
   2636         data->nfd->normalize(UnicodeString(FALSE, pStart, (int32_t)(pEnd - pStart)),
   2637                              data->writableBuffer,
   2638                              *status).
   2639         length();
   2640     if(U_FAILURE(*status)) {
   2641         return;
   2642     }
   2643     /*
   2644     this puts the null termination infront of the normalized string instead
   2645     of the end
   2646     */
   2647     data->pos =
   2648         data->writableBuffer.insert(0, (UChar)0).append(endOfBuffer).getTerminatedBuffer() +
   2649         1 + normLen;
   2650     data->origFlags  = data->flags;
   2651     data->flags     |= UCOL_ITER_INNORMBUF;
   2652     data->flags     &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
   2653 }
   2654 
   2655 /**
   2656 * Contraction character management function that returns the previous character
   2657 * for the backwards iterator.
   2658 * Does nothing if the previous character is in buffer and not the first
   2659 * character in it.
   2660 * Else it checks previous character in data string to see if it is
   2661 * normalizable.
   2662 * If it is not, the character is simply copied into the buffer, else
   2663 * the whole normalized substring is copied into the buffer, including the
   2664 * current character.
   2665 * @param data collation element iterator data
   2666 * @return previous character
   2667 */
   2668 static
   2669 inline UChar getPrevNormalizedChar(collIterate *data, UErrorCode *status)
   2670 {
   2671     UChar  prevch;
   2672     UChar  ch;
   2673     const UChar *start;
   2674     UBool  innormbuf = (UBool)(data->flags & UCOL_ITER_INNORMBUF);
   2675     if ((data->flags & (UCOL_ITER_NORM | UCOL_ITER_INNORMBUF)) == 0 ||
   2676         (innormbuf && *(data->pos - 1) != 0)) {
   2677         /*
   2678         if no normalization.
   2679         if previous character is in normalized buffer, no further normalization
   2680         is required
   2681         */
   2682       if(data->flags & UCOL_USE_ITERATOR) {
   2683         data->iterator->move(data->iterator, -1, UITER_CURRENT);
   2684         return (UChar)data->iterator->next(data->iterator);
   2685       } else {
   2686         return *(data->pos - 1);
   2687       }
   2688     }
   2689 
   2690     start = data->pos;
   2691     if ((data->fcdPosition==NULL)||(data->flags & UCOL_ITER_HASLEN)) {
   2692         /* in data string */
   2693         if ((start - 1) == data->string) {
   2694             return *(start - 1);
   2695         }
   2696         start --;
   2697         ch     = *start;
   2698         prevch = *(start - 1);
   2699     }
   2700     else {
   2701         /*
   2702         in writable buffer, at this point fcdPosition can not be NULL.
   2703         see contracting tag.
   2704         */
   2705         if (data->fcdPosition == data->string) {
   2706             /* at the start of the string, just dump it into the normalizer */
   2707             insertBufferFront(data, *(data->fcdPosition));
   2708             data->fcdPosition = NULL;
   2709             return *(data->pos - 1);
   2710         }
   2711         start  = data->fcdPosition;
   2712         ch     = *start;
   2713         prevch = *(start - 1);
   2714     }
   2715     /*
   2716     * if the current character is not fcd.
   2717     * Trailing combining class == 0.
   2718     */
   2719     if (data->fcdPosition > start &&
   2720        (ch >= NFC_ZERO_CC_BLOCK_LIMIT_ || prevch >= NFC_ZERO_CC_BLOCK_LIMIT_))
   2721     {
   2722         /*
   2723         Need a more complete FCD check and possible normalization.
   2724         normalize substring will be appended to buffer
   2725         */
   2726         const UChar *backuppos = data->pos;
   2727         data->pos = start;
   2728         if (collPrevIterFCD(data)) {
   2729             normalizePrevContraction(data, status);
   2730             return *(data->pos - 1);
   2731         }
   2732         data->pos = backuppos;
   2733         data->fcdPosition ++;
   2734     }
   2735 
   2736     if (innormbuf) {
   2737     /*
   2738     no normalization is to be done hence only one character will be
   2739     appended to the buffer.
   2740     */
   2741         insertBufferFront(data, ch);
   2742         data->fcdPosition --;
   2743     }
   2744 
   2745     return ch;
   2746 }
   2747 
   2748 /* This function handles the special CEs like contractions, expansions, surrogates, Thai */
   2749 /* It is called by getNextCE */
   2750 
   2751 /* The following should be even */
   2752 #define UCOL_MAX_DIGITS_FOR_NUMBER 254
   2753 
   2754 uint32_t ucol_prv_getSpecialCE(const UCollator *coll, UChar ch, uint32_t CE, collIterate *source, UErrorCode *status) {
   2755     collIterateState entryState;
   2756     backupState(source, &entryState);
   2757     UChar32 cp = ch;
   2758 
   2759     for (;;) {
   2760         // This loop will repeat only in the case of contractions, and only when a contraction
   2761         //   is found and the first CE resulting from that contraction is itself a special
   2762         //   (an expansion, for example.)  All other special CE types are fully handled the
   2763         //   first time through, and the loop exits.
   2764 
   2765         const uint32_t *CEOffset = NULL;
   2766         switch(getCETag(CE)) {
   2767         case NOT_FOUND_TAG:
   2768             /* This one is not found, and we'll let somebody else bother about it... no more games */
   2769             return CE;
   2770         case SPEC_PROC_TAG:
   2771             {
   2772                 // Special processing is getting a CE that is preceded by a certain prefix
   2773                 // Currently this is only needed for optimizing Japanese length and iteration marks.
   2774                 // When we encouter a special processing tag, we go backwards and try to see if
   2775                 // we have a match.
   2776                 // Contraction tables are used - so the whole process is not unlike contraction.
   2777                 // prefix data is stored backwards in the table.
   2778                 const UChar *UCharOffset;
   2779                 UChar schar, tchar;
   2780                 collIterateState prefixState;
   2781                 backupState(source, &prefixState);
   2782                 loadState(source, &entryState, TRUE);
   2783                 goBackOne(source); // We want to look at the point where we entered - actually one
   2784                 // before that...
   2785 
   2786                 for(;;) {
   2787                     // This loop will run once per source string character, for as long as we
   2788                     //  are matching a potential contraction sequence
   2789 
   2790                     // First we position ourselves at the begining of contraction sequence
   2791                     const UChar *ContractionStart = UCharOffset = (UChar *)coll->image+getContractOffset(CE);
   2792                     if (collIter_bos(source)) {
   2793                         CE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
   2794                         break;
   2795                     }
   2796                     schar = getPrevNormalizedChar(source, status);
   2797                     goBackOne(source);
   2798 
   2799                     while(schar > (tchar = *UCharOffset)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
   2800                         UCharOffset++;
   2801                     }
   2802 
   2803                     if (schar == tchar) {
   2804                         // Found the source string char in the table.
   2805                         //  Pick up the corresponding CE from the table.
   2806                         CE = *(coll->contractionCEs +
   2807                             (UCharOffset - coll->contractionIndex));
   2808                     }
   2809                     else
   2810                     {
   2811                         // Source string char was not in the table.
   2812                         //   We have not found the prefix.
   2813                         CE = *(coll->contractionCEs +
   2814                             (ContractionStart - coll->contractionIndex));
   2815                     }
   2816 
   2817                     if(!isPrefix(CE)) {
   2818                         // The source string char was in the contraction table, and the corresponding
   2819                         //   CE is not a prefix CE.  We found the prefix, break
   2820                         //   out of loop, this CE will end up being returned.  This is the normal
   2821                         //   way out of prefix handling when the source actually contained
   2822                         //   the prefix.
   2823                         break;
   2824                     }
   2825                 }
   2826                 if(CE != UCOL_NOT_FOUND) { // we found something and we can merilly continue
   2827                     loadState(source, &prefixState, TRUE);
   2828                     if(source->origFlags & UCOL_USE_ITERATOR) {
   2829                         source->flags = source->origFlags;
   2830                     }
   2831                 } else { // prefix search was a failure, we have to backup all the way to the start
   2832                     loadState(source, &entryState, TRUE);
   2833                 }
   2834                 break;
   2835             }
   2836         case CONTRACTION_TAG:
   2837             {
   2838                 /* This should handle contractions */
   2839                 collIterateState state;
   2840                 backupState(source, &state);
   2841                 uint32_t firstCE = *(coll->contractionCEs + ((UChar *)coll->image+getContractOffset(CE) - coll->contractionIndex)); //UCOL_NOT_FOUND;
   2842                 const UChar *UCharOffset;
   2843                 UChar schar, tchar;
   2844 
   2845                 for (;;) {
   2846                     /* This loop will run once per source string character, for as long as we     */
   2847                     /*  are matching a potential contraction sequence                  */
   2848 
   2849                     /* First we position ourselves at the begining of contraction sequence */
   2850                     const UChar *ContractionStart = UCharOffset = (UChar *)coll->image+getContractOffset(CE);
   2851 
   2852                     if (collIter_eos(source)) {
   2853                         // Ran off the end of the source string.
   2854                         CE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
   2855                         // So we'll pick whatever we have at the point...
   2856                         if (CE == UCOL_NOT_FOUND) {
   2857                             // back up the source over all the chars we scanned going into this contraction.
   2858                             CE = firstCE;
   2859                             loadState(source, &state, TRUE);
   2860                             if(source->origFlags & UCOL_USE_ITERATOR) {
   2861                                 source->flags = source->origFlags;
   2862                             }
   2863                         }
   2864                         break;
   2865                     }
   2866 
   2867                     uint8_t maxCC = (uint8_t)(*(UCharOffset)&0xFF); /*get the discontiguos stuff */ /* skip the backward offset, see above */
   2868                     uint8_t allSame = (uint8_t)(*(UCharOffset++)>>8);
   2869 
   2870                     schar = getNextNormalizedChar(source);
   2871                     while(schar > (tchar = *UCharOffset)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
   2872                         UCharOffset++;
   2873                     }
   2874 
   2875                     if (schar == tchar) {
   2876                         // Found the source string char in the contraction table.
   2877                         //  Pick up the corresponding CE from the table.
   2878                         CE = *(coll->contractionCEs +
   2879                             (UCharOffset - coll->contractionIndex));
   2880                     }
   2881                     else
   2882                     {
   2883                         // Source string char was not in contraction table.
   2884                         //   Unless we have a discontiguous contraction, we have finished
   2885                         //   with this contraction.
   2886                         // in order to do the proper detection, we
   2887                         // need to see if we're dealing with a supplementary
   2888                         /* We test whether the next two char are surrogate pairs.
   2889                         * This test is done if the iterator is not NULL.
   2890                         * If there is no surrogate pair, the iterator
   2891                         * goes back one if needed. */
   2892                         UChar32 miss = schar;
   2893                         if (source->iterator) {
   2894                             UChar32 surrNextChar; /* the next char in the iteration to test */
   2895                             int32_t prevPos; /* holds the previous position before move forward of the source iterator */
   2896                             if(U16_IS_LEAD(schar) && source->iterator->hasNext(source->iterator)) {
   2897                                 prevPos = source->iterator->index;
   2898                                 surrNextChar = getNextNormalizedChar(source);
   2899                                 if (U16_IS_TRAIL(surrNextChar)) {
   2900                                     miss = U16_GET_SUPPLEMENTARY(schar, surrNextChar);
   2901                                 } else if (prevPos < source->iterator->index){
   2902                                     goBackOne(source);
   2903                                 }
   2904                             }
   2905                         } else if (U16_IS_LEAD(schar)) {
   2906                             miss = U16_GET_SUPPLEMENTARY(schar, getNextNormalizedChar(source));
   2907                         }
   2908 
   2909                         uint8_t sCC;
   2910                         if (miss < 0x300 ||
   2911                             maxCC == 0 ||
   2912                             (sCC = i_getCombiningClass(miss, coll)) == 0 ||
   2913                             sCC>maxCC ||
   2914                             (allSame != 0 && sCC == maxCC) ||
   2915                             collIter_eos(source))
   2916                         {
   2917                             //  Contraction can not be discontiguous.
   2918                             goBackOne(source);  // back up the source string by one,
   2919                             //  because  the character we just looked at was
   2920                             //  not part of the contraction.   */
   2921                             if(U_IS_SUPPLEMENTARY(miss)) {
   2922                                 goBackOne(source);
   2923                             }
   2924                             CE = *(coll->contractionCEs +
   2925                                 (ContractionStart - coll->contractionIndex));
   2926                         } else {
   2927                             //
   2928                             // Contraction is possibly discontiguous.
   2929                             //   Scan more of source string looking for a match
   2930                             //
   2931                             UChar tempchar;
   2932                             /* find the next character if schar is not a base character
   2933                             and we are not yet at the end of the string */
   2934                             tempchar = getNextNormalizedChar(source);
   2935                             // probably need another supplementary thingie here
   2936                             goBackOne(source);
   2937                             if (i_getCombiningClass(tempchar, coll) == 0) {
   2938                                 goBackOne(source);
   2939                                 if(U_IS_SUPPLEMENTARY(miss)) {
   2940                                     goBackOne(source);
   2941                                 }
   2942                                 /* Spit out the last char of the string, wasn't tasty enough */
   2943                                 CE = *(coll->contractionCEs +
   2944                                     (ContractionStart - coll->contractionIndex));
   2945                             } else {
   2946                                 CE = getDiscontiguous(coll, source, ContractionStart);
   2947                             }
   2948                         }
   2949                     } // else after if(schar == tchar)
   2950 
   2951                     if(CE == UCOL_NOT_FOUND) {
   2952                         /* The Source string did not match the contraction that we were checking.  */
   2953                         /*  Back up the source position to undo the effects of having partially    */
   2954                         /*   scanned through what ultimately proved to not be a contraction.       */
   2955                         loadState(source, &state, TRUE);
   2956                         CE = firstCE;
   2957                         break;
   2958                     }
   2959 
   2960                     if(!isContraction(CE)) {
   2961                         // The source string char was in the contraction table, and the corresponding
   2962                         //   CE is not a contraction CE.  We completed the contraction, break
   2963                         //   out of loop, this CE will end up being returned.  This is the normal
   2964                         //   way out of contraction handling when the source actually contained
   2965                         //   the contraction.
   2966                         break;
   2967                     }
   2968 
   2969 
   2970                     // The source string char was in the contraction table, and the corresponding
   2971                     //   CE is IS  a contraction CE.  We will continue looping to check the source
   2972                     //   string for the remaining chars in the contraction.
   2973                     uint32_t tempCE = *(coll->contractionCEs + (ContractionStart - coll->contractionIndex));
   2974                     if(tempCE != UCOL_NOT_FOUND) {
   2975                         // We have scanned a a section of source string for which there is a
   2976                         //  CE from the contraction table.  Remember the CE and scan position, so
   2977                         //  that we can return to this point if further scanning fails to
   2978                         //  match a longer contraction sequence.
   2979                         firstCE = tempCE;
   2980 
   2981                         goBackOne(source);
   2982                         backupState(source, &state);
   2983                         getNextNormalizedChar(source);
   2984 
   2985                         // Another way to do this is:
   2986                         //collIterateState tempState;
   2987                         //backupState(source, &tempState);
   2988                         //goBackOne(source);
   2989                         //backupState(source, &state);
   2990                         //loadState(source, &tempState, TRUE);
   2991 
   2992                         // The problem is that for incomplete contractions we have to remember the previous
   2993                         // position. Before, the only thing I needed to do was state.pos--;
   2994                         // After iterator introduction and especially after introduction of normalizing
   2995                         // iterators, it became much more difficult to decrease the saved state.
   2996                         // I'm not yet sure which of the two methods above is faster.
   2997                     }
   2998                 } // for(;;)
   2999                 break;
   3000             } // case CONTRACTION_TAG:
   3001         case LONG_PRIMARY_TAG:
   3002             {
   3003                 *(source->CEpos++) = ((CE & 0xFF)<<24)|UCOL_CONTINUATION_MARKER;
   3004                 CE = ((CE & 0xFFFF00) << 8) | (UCOL_BYTE_COMMON << 8) | UCOL_BYTE_COMMON;
   3005                 source->offsetRepeatCount += 1;
   3006                 return CE;
   3007             }
   3008         case EXPANSION_TAG:
   3009             {
   3010                 /* This should handle expansion. */
   3011                 /* NOTE: we can encounter both continuations and expansions in an expansion! */
   3012                 /* I have to decide where continuations are going to be dealt with */
   3013                 uint32_t size;
   3014                 uint32_t i;    /* general counter */
   3015 
   3016                 CEOffset = (uint32_t *)coll->image+getExpansionOffset(CE); /* find the offset to expansion table */
   3017                 size = getExpansionCount(CE);
   3018                 CE = *CEOffset++;
   3019               //source->offsetRepeatCount = -1;
   3020 
   3021                 if(size != 0) { /* if there are less than 16 elements in expansion, we don't terminate */
   3022                     for(i = 1; i<size; i++) {
   3023                         *(source->CEpos++) = *CEOffset++;
   3024                         source->offsetRepeatCount += 1;
   3025                     }
   3026                 } else { /* else, we do */
   3027                     while(*CEOffset != 0) {
   3028                         *(source->CEpos++) = *CEOffset++;
   3029                         source->offsetRepeatCount += 1;
   3030                     }
   3031                 }
   3032 
   3033                 return CE;
   3034             }
   3035         case DIGIT_TAG:
   3036             {
   3037                 /*
   3038                 We do a check to see if we want to collate digits as numbers; if so we generate
   3039                 a custom collation key. Otherwise we pull out the value stored in the expansion table.
   3040                 */
   3041                 //uint32_t size;
   3042                 uint32_t i;    /* general counter */
   3043 
   3044                 if (source->coll->numericCollation == UCOL_ON){
   3045                     collIterateState digitState = {0,0,0,0,0,0,0,0,0};
   3046                     UChar32 char32 = 0;
   3047                     int32_t digVal = 0;
   3048 
   3049                     uint32_t digIndx = 0;
   3050                     uint32_t endIndex = 0;
   3051                     uint32_t trailingZeroIndex = 0;
   3052 
   3053                     uint8_t collateVal = 0;
   3054 
   3055                     UBool nonZeroValReached = FALSE;
   3056 
   3057                     uint8_t numTempBuf[UCOL_MAX_DIGITS_FOR_NUMBER/2 + 3]; // I just need a temporary place to store my generated CEs.
   3058                     /*
   3059                          We parse the source string until we hit a char that's NOT a digit.
   3060                         Use this u_charDigitValue. This might be slow because we have to
   3061                         handle surrogates...
   3062                     */
   3063             /*
   3064                     if (U16_IS_LEAD(ch)){
   3065                       if (!collIter_eos(source)) {
   3066                         backupState(source, &digitState);
   3067                         UChar trail = getNextNormalizedChar(source);
   3068                         if(U16_IS_TRAIL(trail)) {
   3069                           char32 = U16_GET_SUPPLEMENTARY(ch, trail);
   3070                         } else {
   3071                           loadState(source, &digitState, TRUE);
   3072                           char32 = ch;
   3073                         }
   3074                       } else {
   3075                         char32 = ch;
   3076                       }
   3077                     } else {
   3078                       char32 = ch;
   3079                     }
   3080                     digVal = u_charDigitValue(char32);
   3081             */
   3082                     digVal = u_charDigitValue(cp); // if we have arrived here, we have
   3083                     // already processed possible supplementaries that trigered the digit tag -
   3084                     // all supplementaries are marked in the UCA.
   3085                     /*
   3086                         We  pad a zero in front of the first element anyways. This takes
   3087                         care of the (probably) most common case where people are sorting things followed
   3088                         by a single digit
   3089                     */
   3090                     digIndx++;
   3091                     for(;;){
   3092                         // Make sure we have enough space. No longer needed;
   3093                         // at this point digIndx now has a max value of UCOL_MAX_DIGITS_FOR_NUMBER
   3094                         // (it has been pre-incremented) so we just ensure that numTempBuf is big enough
   3095                         // (UCOL_MAX_DIGITS_FOR_NUMBER/2 + 3).
   3096 
   3097                         // Skipping over leading zeroes.
   3098                         if (digVal != 0) {
   3099                             nonZeroValReached = TRUE;
   3100                         }
   3101                         if (nonZeroValReached) {
   3102                             /*
   3103                             We parse the digit string into base 100 numbers (this fits into a byte).
   3104                             We only add to the buffer in twos, thus if we are parsing an odd character,
   3105                             that serves as the 'tens' digit while the if we are parsing an even one, that
   3106                             is the 'ones' digit. We dumped the parsed base 100 value (collateVal) into
   3107                             a buffer. We multiply each collateVal by 2 (to give us room) and add 5 (to avoid
   3108                             overlapping magic CE byte values). The last byte we subtract 1 to ensure it is less
   3109                             than all the other bytes.
   3110                             */
   3111 
   3112                             if (digIndx % 2 == 1){
   3113                                 collateVal += (uint8_t)digVal;
   3114 
   3115                                 // We don't enter the low-order-digit case unless we've already seen
   3116                                 // the high order, or for the first digit, which is always non-zero.
   3117                                 if (collateVal != 0)
   3118                                     trailingZeroIndex = 0;
   3119 
   3120                                 numTempBuf[(digIndx/2) + 2] = collateVal*2 + 6;
   3121                                 collateVal = 0;
   3122                             }
   3123                             else{
   3124                                 // We drop the collation value into the buffer so if we need to do
   3125                                 // a "front patch" we don't have to check to see if we're hitting the
   3126                                 // last element.
   3127                                 collateVal = (uint8_t)(digVal * 10);
   3128 
   3129                                 // Check for trailing zeroes.
   3130                                 if (collateVal == 0)
   3131                                 {
   3132                                     if (!trailingZeroIndex)
   3133                                         trailingZeroIndex = (digIndx/2) + 2;
   3134                                 }
   3135                                 else
   3136                                     trailingZeroIndex = 0;
   3137 
   3138                                 numTempBuf[(digIndx/2) + 2] = collateVal*2 + 6;
   3139                             }
   3140                             digIndx++;
   3141                         }
   3142 
   3143                         // Get next character.
   3144                         if (!collIter_eos(source)){
   3145                             ch = getNextNormalizedChar(source);
   3146                             if (U16_IS_LEAD(ch)){
   3147                                 if (!collIter_eos(source)) {
   3148                                     backupState(source, &digitState);
   3149                                     UChar trail = getNextNormalizedChar(source);
   3150                                     if(U16_IS_TRAIL(trail)) {
   3151                                         char32 = U16_GET_SUPPLEMENTARY(ch, trail);
   3152                                     } else {
   3153                                         loadState(source, &digitState, TRUE);
   3154                                         char32 = ch;
   3155                                     }
   3156                                 }
   3157                             } else {
   3158                                 char32 = ch;
   3159                             }
   3160 
   3161                             if ((digVal = u_charDigitValue(char32)) == -1 || digIndx > UCOL_MAX_DIGITS_FOR_NUMBER){
   3162                                 // Resetting position to point to the next unprocessed char. We
   3163                                 // overshot it when doing our test/set for numbers.
   3164                                 if (char32 > 0xFFFF) { // For surrogates.
   3165                                     loadState(source, &digitState, TRUE);
   3166                                     //goBackOne(source);
   3167                                 }
   3168                                 goBackOne(source);
   3169                                 break;
   3170                             }
   3171                         } else {
   3172                             break;
   3173                         }
   3174                     }
   3175 
   3176                     if (nonZeroValReached == FALSE){
   3177                         digIndx = 2;
   3178                         numTempBuf[2] = 6;
   3179                     }
   3180 
   3181                     endIndex = trailingZeroIndex ? trailingZeroIndex : ((digIndx/2) + 2) ;
   3182                     if (digIndx % 2 != 0){
   3183                         /*
   3184                         We missed a value. Since digIndx isn't even, stuck too many values into the buffer (this is what
   3185                         we get for padding the first byte with a zero). "Front-patch" now by pushing all nybbles forward.
   3186                         Doing it this way ensures that at least 50% of the time (statistically speaking) we'll only be doing a
   3187                         single pass and optimizes for strings with single digits. I'm just assuming that's the more common case.
   3188                         */
   3189 
   3190                         for(i = 2; i < endIndex; i++){
   3191                             numTempBuf[i] =     (((((numTempBuf[i] - 6)/2) % 10) * 10) +
   3192                                 (((numTempBuf[i+1])-6)/2) / 10) * 2 + 6;
   3193                         }
   3194                         --digIndx;
   3195                     }
   3196 
   3197                     // Subtract one off of the last byte.
   3198                     numTempBuf[endIndex-1] -= 1;
   3199 
   3200                     /*
   3201                     We want to skip over the first two slots in the buffer. The first slot
   3202                     is reserved for the header byte UCOL_CODAN_PLACEHOLDER. The second slot is for the
   3203                     sign/exponent byte: 0x80 + (decimalPos/2) & 7f.
   3204                     */
   3205                     numTempBuf[0] = UCOL_CODAN_PLACEHOLDER;
   3206                     numTempBuf[1] = (uint8_t)(0x80 + ((digIndx/2) & 0x7F));
   3207 
   3208                     // Now transfer the collation key to our collIterate struct.
   3209                     // The total size for our collation key is endIndx bumped up to the next largest even value divided by two.
   3210                     //size = ((endIndex+1) & ~1)/2;
   3211                     CE = (((numTempBuf[0] << 8) | numTempBuf[1]) << UCOL_PRIMARYORDERSHIFT) | //Primary weight
   3212                         (UCOL_BYTE_COMMON << UCOL_SECONDARYORDERSHIFT) | // Secondary weight
   3213                         UCOL_BYTE_COMMON; // Tertiary weight.
   3214                     i = 2; // Reset the index into the buffer.
   3215                     while(i < endIndex)
   3216                     {
   3217                         uint32_t primWeight = numTempBuf[i++] << 8;
   3218                         if ( i < endIndex)
   3219                             primWeight |= numTempBuf[i++];
   3220                         *(source->CEpos++) = (primWeight << UCOL_PRIMARYORDERSHIFT) | UCOL_CONTINUATION_MARKER;
   3221                     }
   3222 
   3223                 } else {
   3224                     // no numeric mode, we'll just switch to whatever we stashed and continue
   3225                     CEOffset = (uint32_t *)coll->image+getExpansionOffset(CE); /* find the offset to expansion table */
   3226                     CE = *CEOffset++;
   3227                     break;
   3228                 }
   3229                 return CE;
   3230             }
   3231             /* various implicits optimization */
   3232         case IMPLICIT_TAG:        /* everything that is not defined otherwise */
   3233             /* UCA is filled with these. Tailorings are NOT_FOUND */
   3234             return getImplicit(cp, source);
   3235         case CJK_IMPLICIT_TAG:    /* 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D*/
   3236             // TODO: remove CJK_IMPLICIT_TAG completely - handled by the getImplicit
   3237             return getImplicit(cp, source);
   3238         case HANGUL_SYLLABLE_TAG: /* AC00-D7AF*/
   3239             {
   3240                 static const uint32_t
   3241                     SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7;
   3242                 //const uint32_t LCount = 19;
   3243                 static const uint32_t VCount = 21;
   3244                 static const uint32_t TCount = 28;
   3245                 //const uint32_t NCount = VCount * TCount;   // 588
   3246                 //const uint32_t SCount = LCount * NCount;   // 11172
   3247                 uint32_t L = ch - SBase;
   3248 
   3249                 // divide into pieces
   3250 
   3251                 uint32_t T = L % TCount; // we do it in this order since some compilers can do % and / in one operation
   3252                 L /= TCount;
   3253                 uint32_t V = L % VCount;
   3254                 L /= VCount;
   3255 
   3256                 // offset them
   3257 
   3258                 L += LBase;
   3259                 V += VBase;
   3260                 T += TBase;
   3261 
   3262                 // return the first CE, but first put the rest into the expansion buffer
   3263                 if (!source->coll->image->jamoSpecial) { // FAST PATH
   3264 
   3265                     *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, V);
   3266                     if (T != TBase) {
   3267                         *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, T);
   3268                     }
   3269 
   3270                     return UTRIE_GET32_FROM_LEAD(&coll->mapping, L);
   3271 
   3272                 } else { // Jamo is Special
   3273                     // Since Hanguls pass the FCD check, it is
   3274                     // guaranteed that we won't be in
   3275                     // the normalization buffer if something like this happens
   3276 
   3277                     // However, if we are using a uchar iterator and normalization
   3278                     // is ON, the Hangul that lead us here is going to be in that
   3279                     // normalization buffer. Here we want to restore the uchar
   3280                     // iterator state and pull out of the normalization buffer
   3281                     if(source->iterator != NULL && source->flags & UCOL_ITER_INNORMBUF) {
   3282                         source->flags = source->origFlags; // restore the iterator
   3283                         source->pos = NULL;
   3284                     }
   3285 
   3286                     // Move Jamos into normalization buffer
   3287                     UChar *buffer = source->writableBuffer.getBuffer(4);
   3288                     int32_t bufferLength;
   3289                     buffer[0] = (UChar)L;
   3290                     buffer[1] = (UChar)V;
   3291                     if (T != TBase) {
   3292                         buffer[2] = (UChar)T;
   3293                         bufferLength = 3;
   3294                     } else {
   3295                         bufferLength = 2;
   3296                     }
   3297                     source->writableBuffer.releaseBuffer(bufferLength);
   3298 
   3299                     // Indicate where to continue in main input string after exhausting the writableBuffer
   3300                     source->fcdPosition       = source->pos;
   3301 
   3302                     source->pos   = source->writableBuffer.getTerminatedBuffer();
   3303                     source->origFlags   = source->flags;
   3304                     source->flags       |= UCOL_ITER_INNORMBUF;
   3305                     source->flags       &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
   3306 
   3307                     return(UCOL_IGNORABLE);
   3308                 }
   3309             }
   3310         case SURROGATE_TAG:
   3311             /* we encountered a leading surrogate. We shall get the CE by using the following code unit */
   3312             /* two things can happen here: next code point can be a trailing surrogate - we will use it */
   3313             /* to retrieve the CE, or it is not a trailing surrogate (or the string is done). In that case */
   3314             /* we treat it like an unassigned code point. */
   3315             {
   3316                 UChar trail;
   3317                 collIterateState state;
   3318                 backupState(source, &state);
   3319                 if (collIter_eos(source) || !(U16_IS_TRAIL((trail = getNextNormalizedChar(source))))) {
   3320                     // we chould have stepped one char forward and it might have turned that it
   3321                     // was not a trail surrogate. In that case, we have to backup.
   3322                     loadState(source, &state, TRUE);
   3323                     return UCOL_NOT_FOUND;
   3324                 } else {
   3325                     /* TODO: CE contain the data from the previous CE + the mask. It should at least be unmasked */
   3326                     CE = UTRIE_GET32_FROM_OFFSET_TRAIL(&coll->mapping, CE&0xFFFFFF, trail);
   3327                     if(CE == UCOL_NOT_FOUND) { // there are tailored surrogates in this block, but not this one.
   3328                         // We need to backup
   3329                         loadState(source, &state, TRUE);
   3330                         return CE;
   3331                     }
   3332                     // calculate the supplementary code point value, if surrogate was not tailored
   3333                     cp = ((((uint32_t)ch)<<10UL)+(trail)-(((uint32_t)0xd800<<10UL)+0xdc00-0x10000));
   3334                 }
   3335             }
   3336             break;
   3337         case LEAD_SURROGATE_TAG:  /* D800-DBFF*/
   3338             UChar nextChar;
   3339             if( source->flags & UCOL_USE_ITERATOR) {
   3340                 if(U_IS_TRAIL(nextChar = (UChar)source->iterator->current(source->iterator))) {
   3341                     cp = U16_GET_SUPPLEMENTARY(ch, nextChar);
   3342                     source->iterator->next(source->iterator);
   3343                     return getImplicit(cp, source);
   3344                 }
   3345             } else if((((source->flags & UCOL_ITER_HASLEN) == 0 ) || (source->pos<source->endp)) &&
   3346                       U_IS_TRAIL((nextChar=*source->pos))) {
   3347                 cp = U16_GET_SUPPLEMENTARY(ch, nextChar);
   3348                 source->pos++;
   3349                 return getImplicit(cp, source);
   3350             }
   3351             return UCOL_NOT_FOUND;
   3352         case TRAIL_SURROGATE_TAG: /* DC00-DFFF*/
   3353             return UCOL_NOT_FOUND; /* broken surrogate sequence */
   3354         case CHARSET_TAG:
   3355             /* not yet implemented */
   3356             /* probably after 1.8 */
   3357             return UCOL_NOT_FOUND;
   3358         default:
   3359             *status = U_INTERNAL_PROGRAM_ERROR;
   3360             CE=0;
   3361             break;
   3362     }
   3363     if (CE <= UCOL_NOT_FOUND) break;
   3364   }
   3365   return CE;
   3366 }
   3367 
   3368 
   3369 /* now uses Mark's getImplicitPrimary code */
   3370 static
   3371 inline uint32_t getPrevImplicit(UChar32 cp, collIterate *collationSource) {
   3372     uint32_t r = uprv_uca_getImplicitPrimary(cp);
   3373 
   3374     *(collationSource->CEpos++) = (r & UCOL_PRIMARYMASK) | 0x00000505;
   3375     collationSource->toReturn = collationSource->CEpos;
   3376 
   3377     // **** doesn't work if using iterator ****
   3378     if (collationSource->flags & UCOL_ITER_INNORMBUF) {
   3379         collationSource->offsetRepeatCount = 1;
   3380     } else {
   3381         int32_t firstOffset = (int32_t)(collationSource->pos - collationSource->string);
   3382 
   3383         UErrorCode errorCode = U_ZERO_ERROR;
   3384         collationSource->appendOffset(firstOffset, errorCode);
   3385         collationSource->appendOffset(firstOffset + 1, errorCode);
   3386 
   3387         collationSource->offsetReturn = collationSource->offsetStore - 1;
   3388         *(collationSource->offsetBuffer) = firstOffset;
   3389         if (collationSource->offsetReturn == collationSource->offsetBuffer) {
   3390             collationSource->offsetStore = collationSource->offsetBuffer;
   3391         }
   3392     }
   3393 
   3394     return ((r & 0x0000FFFF)<<16) | 0x000000C0;
   3395 }
   3396 
   3397 /**
   3398  * This function handles the special CEs like contractions, expansions,
   3399  * surrogates, Thai.
   3400  * It is called by both getPrevCE
   3401  */
   3402 uint32_t ucol_prv_getSpecialPrevCE(const UCollator *coll, UChar ch, uint32_t CE,
   3403                           collIterate *source,
   3404                           UErrorCode *status)
   3405 {
   3406     const uint32_t *CEOffset    = NULL;
   3407           UChar    *UCharOffset = NULL;
   3408           UChar    schar;
   3409     const UChar    *constart    = NULL;
   3410           uint32_t size;
   3411           UChar    buffer[UCOL_MAX_BUFFER];
   3412           uint32_t *endCEBuffer;
   3413           UChar   *strbuffer;
   3414           int32_t noChars = 0;
   3415           int32_t CECount = 0;
   3416 
   3417     for(;;)
   3418     {
   3419         /* the only ces that loops are thai and contractions */
   3420         switch (getCETag(CE))
   3421         {
   3422         case NOT_FOUND_TAG:  /* this tag always returns */
   3423             return CE;
   3424 
   3425         case SPEC_PROC_TAG:
   3426             {
   3427                 // Special processing is getting a CE that is preceded by a certain prefix
   3428                 // Currently this is only needed for optimizing Japanese length and iteration marks.
   3429                 // When we encouter a special processing tag, we go backwards and try to see if
   3430                 // we have a match.
   3431                 // Contraction tables are used - so the whole process is not unlike contraction.
   3432                 // prefix data is stored backwards in the table.
   3433                 const UChar *UCharOffset;
   3434                 UChar schar, tchar;
   3435                 collIterateState prefixState;
   3436                 backupState(source, &prefixState);
   3437                 for(;;) {
   3438                     // This loop will run once per source string character, for as long as we
   3439                     //  are matching a potential contraction sequence
   3440 
   3441                     // First we position ourselves at the begining of contraction sequence
   3442                     const UChar *ContractionStart = UCharOffset = (UChar *)coll->image+getContractOffset(CE);
   3443 
   3444                     if (collIter_bos(source)) {
   3445                         CE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
   3446                         break;
   3447                     }
   3448                     schar = getPrevNormalizedChar(source, status);
   3449                     goBackOne(source);
   3450 
   3451                     while(schar > (tchar = *UCharOffset)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
   3452                         UCharOffset++;
   3453                     }
   3454 
   3455                     if (schar == tchar) {
   3456                         // Found the source string char in the table.
   3457                         //  Pick up the corresponding CE from the table.
   3458                         CE = *(coll->contractionCEs +
   3459                             (UCharOffset - coll->contractionIndex));
   3460                     }
   3461                     else
   3462                     {
   3463                         // if there is a completely ignorable code point in the middle of
   3464                         // a prefix, we need to act as if it's not there
   3465                         // assumption: 'real' noncharacters (*fffe, *ffff, fdd0-fdef are set to zero)
   3466                         // lone surrogates cannot be set to zero as it would break other processing
   3467                         uint32_t isZeroCE = UTRIE_GET32_FROM_LEAD(&coll->mapping, schar);
   3468                         // it's easy for BMP code points
   3469                         if(isZeroCE == 0) {
   3470                             continue;
   3471                         } else if(U16_IS_SURROGATE(schar)) {
   3472                             // for supplementary code points, we have to check the next one
   3473                             // situations where we are going to ignore
   3474                             // 1. beginning of the string: schar is a lone surrogate
   3475                             // 2. schar is a lone surrogate
   3476                             // 3. schar is a trail surrogate in a valid surrogate sequence
   3477                             //    that is explicitly set to zero.
   3478                             if (!collIter_bos(source)) {
   3479                                 UChar lead;
   3480                                 if(!U16_IS_SURROGATE_LEAD(schar) && U16_IS_LEAD(lead = getPrevNormalizedChar(source, status))) {
   3481                                     isZeroCE = UTRIE_GET32_FROM_LEAD(&coll->mapping, lead);
   3482                                     if(isSpecial(isZeroCE) && getCETag(isZeroCE) == SURROGATE_TAG) {
   3483                                         uint32_t finalCE = UTRIE_GET32_FROM_OFFSET_TRAIL(&coll->mapping, isZeroCE&0xFFFFFF, schar);
   3484                                         if(finalCE == 0) {
   3485                                             // this is a real, assigned completely ignorable code point
   3486                                             goBackOne(source);
   3487                                             continue;
   3488                                         }
   3489                                     }
   3490                                 } else {
   3491                                     // lone surrogate, treat like unassigned
   3492                                     return UCOL_NOT_FOUND;
   3493                                 }
   3494                             } else {
   3495                                 // lone surrogate at the beggining, treat like unassigned
   3496                                 return UCOL_NOT_FOUND;
   3497                             }
   3498                         }
   3499                         // Source string char was not in the table.
   3500                         //   We have not found the prefix.
   3501                         CE = *(coll->contractionCEs +
   3502                             (ContractionStart - coll->contractionIndex));
   3503                     }
   3504 
   3505                     if(!isPrefix(CE)) {
   3506                         // The source string char was in the contraction table, and the corresponding
   3507                         //   CE is not a prefix CE.  We found the prefix, break
   3508                         //   out of loop, this CE will end up being returned.  This is the normal
   3509                         //   way out of prefix handling when the source actually contained
   3510                         //   the prefix.
   3511                         break;
   3512                     }
   3513                 }
   3514                 loadState(source, &prefixState, TRUE);
   3515                 break;
   3516             }
   3517 
   3518         case CONTRACTION_TAG: {
   3519             /* to ensure that the backwards and forwards iteration matches, we
   3520             take the current region of most possible match and pass it through
   3521             the forward iteration. this will ensure that the obstinate problem of
   3522             overlapping contractions will not occur.
   3523             */
   3524             schar = peekCodeUnit(source, 0);
   3525             constart = (UChar *)coll->image + getContractOffset(CE);
   3526             if (isAtStartPrevIterate(source)
   3527                 /* commented away contraction end checks after adding the checks
   3528                 in getPrevCE  */) {
   3529                     /* start of string or this is not the end of any contraction */
   3530                     CE = *(coll->contractionCEs +
   3531                         (constart - coll->contractionIndex));
   3532                     break;
   3533             }
   3534             strbuffer = buffer;
   3535             UCharOffset = strbuffer + (UCOL_MAX_BUFFER - 1);
   3536             *(UCharOffset --) = 0;
   3537             noChars = 0;
   3538             // have to swap thai characters
   3539             while (ucol_unsafeCP(schar, coll)) {
   3540                 *(UCharOffset) = schar;
   3541                 noChars++;
   3542                 UCharOffset --;
   3543                 schar = getPrevNormalizedChar(source, status);
   3544                 goBackOne(source);
   3545                 // TODO: when we exhaust the contraction buffer,
   3546                 // it needs to get reallocated. The problem is
   3547                 // that the size depends on the string which is
   3548                 // not iterated over. However, since we're travelling
   3549                 // backwards, we already had to set the iterator at
   3550                 // the end - so we might as well know where we are?
   3551                 if (UCharOffset + 1 == buffer) {
   3552                     /* we have exhausted the buffer */
   3553                     int32_t newsize = 0;
   3554                     if(source->pos) { // actually dealing with a position
   3555                         newsize = (int32_t)(source->pos - source->string + 1);
   3556                     } else { // iterator
   3557                         newsize = 4 * UCOL_MAX_BUFFER;
   3558                     }
   3559                     strbuffer = (UChar *)uprv_malloc(sizeof(UChar) *
   3560                         (newsize + UCOL_MAX_BUFFER));
   3561                     /* test for NULL */
   3562                     if (strbuffer == NULL) {
   3563                         *status = U_MEMORY_ALLOCATION_ERROR;
   3564                         return UCOL_NO_MORE_CES;
   3565                     }
   3566                     UCharOffset = strbuffer + newsize;
   3567                     uprv_memcpy(UCharOffset, buffer,
   3568                         UCOL_MAX_BUFFER * sizeof(UChar));
   3569                     UCharOffset --;
   3570                 }
   3571                 if ((source->pos && (source->pos == source->string ||
   3572                     ((source->flags & UCOL_ITER_INNORMBUF) &&
   3573                     *(source->pos - 1) == 0 && source->fcdPosition == NULL)))
   3574                     || (source->iterator && !source->iterator->hasPrevious(source->iterator))) {
   3575                         break;
   3576                 }
   3577             }
   3578             /* adds the initial base character to the string */
   3579             *(UCharOffset) = schar;
   3580             noChars++;
   3581 
   3582             int32_t offsetBias;
   3583 
   3584             // **** doesn't work if using iterator ****
   3585             if (source->flags & UCOL_ITER_INNORMBUF) {
   3586                 offsetBias = -1;
   3587             } else {
   3588                 offsetBias = (int32_t)(source->pos - source->string);
   3589             }
   3590 
   3591             /* a new collIterate is used to simplify things, since using the current
   3592             collIterate will mean that the forward and backwards iteration will
   3593             share and change the same buffers. we don't want to get into that. */
   3594             collIterate temp;
   3595             int32_t rawOffset;
   3596 
   3597             IInit_collIterate(coll, UCharOffset, noChars, &temp, status);
   3598             if(U_FAILURE(*status)) {
   3599                 return (uint32_t)UCOL_NULLORDER;
   3600             }
   3601             temp.flags &= ~UCOL_ITER_NORM;
   3602             temp.flags |= source->flags & UCOL_FORCE_HAN_IMPLICIT;
   3603 
   3604             rawOffset = (int32_t)(temp.pos - temp.string); // should always be zero?
   3605             CE = ucol_IGetNextCE(coll, &temp, status);
   3606 
   3607             if (source->extendCEs) {
   3608                 endCEBuffer = source->extendCEs + source->extendCEsSize;
   3609                 CECount = (int32_t)((source->CEpos - source->extendCEs)/sizeof(uint32_t));
   3610             } else {
   3611                 endCEBuffer = source->CEs + UCOL_EXPAND_CE_BUFFER_SIZE;
   3612                 CECount = (int32_t)((source->CEpos - source->CEs)/sizeof(uint32_t));
   3613             }
   3614 
   3615             while (CE != UCOL_NO_MORE_CES) {
   3616                 *(source->CEpos ++) = CE;
   3617 
   3618                 if (offsetBias >= 0) {
   3619                     source->appendOffset(rawOffset + offsetBias, *status);
   3620                 }
   3621 
   3622                 CECount++;
   3623                 if (source->CEpos == endCEBuffer) {
   3624                     /* ran out of CE space, reallocate to new buffer.
   3625                     If reallocation fails, reset pointers and bail out,
   3626                     there's no guarantee of the right character position after
   3627                     this bail*/
   3628                     if (!increaseCEsCapacity(source)) {
   3629                         *status = U_MEMORY_ALLOCATION_ERROR;
   3630                         break;
   3631                     }
   3632 
   3633                     endCEBuffer = source->extendCEs + source->extendCEsSize;
   3634                 }
   3635 
   3636                 if ((temp.flags & UCOL_ITER_INNORMBUF) != 0) {
   3637                     rawOffset = (int32_t)(temp.fcdPosition - temp.string);
   3638                 } else {
   3639                     rawOffset = (int32_t)(temp.pos - temp.string);
   3640                 }
   3641 
   3642                 CE = ucol_IGetNextCE(coll, &temp, status);
   3643             }
   3644 
   3645             if (strbuffer != buffer) {
   3646                 uprv_free(strbuffer);
   3647             }
   3648             if (U_FAILURE(*status)) {
   3649                 return (uint32_t)UCOL_NULLORDER;
   3650             }
   3651 
   3652             if (source->offsetRepeatValue != 0) {
   3653                 if (CECount > noChars) {
   3654                     source->offsetRepeatCount += temp.offsetRepeatCount;
   3655                 } else {
   3656                     // **** does this really skip the right offsets? ****
   3657                     source->offsetReturn -= (noChars - CECount);
   3658                 }
   3659             }
   3660 
   3661             if (offsetBias >= 0) {
   3662                 source->offsetReturn = source->offsetStore - 1;
   3663                 if (source->offsetReturn == source->offsetBuffer) {
   3664                     source->offsetStore = source->offsetBuffer;
   3665                 }
   3666             }
   3667 
   3668             source->toReturn = source->CEpos - 1;
   3669             if (source->toReturn == source->CEs) {
   3670                 source->CEpos = source->CEs;
   3671             }
   3672 
   3673             return *(source->toReturn);
   3674         }
   3675         case LONG_PRIMARY_TAG:
   3676             {
   3677                 *(source->CEpos++) = ((CE & 0xFFFF00) << 8) | (UCOL_BYTE_COMMON << 8) | UCOL_BYTE_COMMON;
   3678                 *(source->CEpos++) = ((CE & 0xFF)<<24)|UCOL_CONTINUATION_MARKER;
   3679                 source->toReturn = source->CEpos - 1;
   3680 
   3681                 if (source->flags & UCOL_ITER_INNORMBUF) {
   3682                     source->offsetRepeatCount = 1;
   3683                 } else {
   3684                     int32_t firstOffset = (int32_t)(source->pos - source->string);
   3685 
   3686                     source->appendOffset(firstOffset, *status);
   3687                     source->appendOffset(firstOffset + 1, *status);
   3688 
   3689                     source->offsetReturn = source->offsetStore - 1;
   3690                     *(source->offsetBuffer) = firstOffset;
   3691                     if (source->offsetReturn == source->offsetBuffer) {
   3692                         source->offsetStore = source->offsetBuffer;
   3693                     }
   3694                 }
   3695 
   3696 
   3697                 return *(source->toReturn);
   3698             }
   3699 
   3700         case EXPANSION_TAG: /* this tag always returns */
   3701             {
   3702             /*
   3703             This should handle expansion.
   3704             NOTE: we can encounter both continuations and expansions in an expansion!
   3705             I have to decide where continuations are going to be dealt with
   3706             */
   3707             int32_t firstOffset = (int32_t)(source->pos - source->string);
   3708 
   3709             // **** doesn't work if using iterator ****
   3710             if (source->offsetReturn != NULL) {
   3711                 if (! (source->flags & UCOL_ITER_INNORMBUF) && source->offsetReturn == source->offsetBuffer) {
   3712                     source->offsetStore = source->offsetBuffer;
   3713                 }else {
   3714                   firstOffset = -1;
   3715                 }
   3716             }
   3717 
   3718             /* find the offset to expansion table */
   3719             CEOffset = (uint32_t *)coll->image + getExpansionOffset(CE);
   3720             size     = getExpansionCount(CE);
   3721             if (size != 0) {
   3722                 /*
   3723                 if there are less than 16 elements in expansion, we don't terminate
   3724                 */
   3725                 uint32_t count;
   3726 
   3727                 for (count = 0; count < size; count++) {
   3728                     *(source->CEpos ++) = *CEOffset++;
   3729 
   3730                     if (firstOffset >= 0) {
   3731                         source->appendOffset(firstOffset + 1, *status);
   3732                     }
   3733                 }
   3734             } else {
   3735                 /* else, we do */
   3736                 while (*CEOffset != 0) {
   3737                     *(source->CEpos ++) = *CEOffset ++;
   3738 
   3739                     if (firstOffset >= 0) {
   3740                         source->appendOffset(firstOffset + 1, *status);
   3741                     }
   3742                 }
   3743             }
   3744 
   3745             if (firstOffset >= 0) {
   3746                 source->offsetReturn = source->offsetStore - 1;
   3747                 *(source->offsetBuffer) = firstOffset;
   3748                 if (source->offsetReturn == source->offsetBuffer) {
   3749                     source->offsetStore = source->offsetBuffer;
   3750                 }
   3751             } else {
   3752                 source->offsetRepeatCount += size - 1;
   3753             }
   3754 
   3755             source->toReturn = source->CEpos - 1;
   3756             // in case of one element expansion, we
   3757             // want to immediately return CEpos
   3758             if(source->toReturn == source->CEs) {
   3759                 source->CEpos = source->CEs;
   3760             }
   3761 
   3762             return *(source->toReturn);
   3763             }
   3764 
   3765         case DIGIT_TAG:
   3766             {
   3767                 /*
   3768                 We do a check to see if we want to collate digits as numbers; if so we generate
   3769                 a custom collation key. Otherwise we pull out the value stored in the expansion table.
   3770                 */
   3771                 uint32_t i;    /* general counter */
   3772 
   3773                 if (source->coll->numericCollation == UCOL_ON){
   3774                     uint32_t digIndx = 0;
   3775                     uint32_t endIndex = 0;
   3776                     uint32_t leadingZeroIndex = 0;
   3777                     uint32_t trailingZeroCount = 0;
   3778 
   3779                     uint8_t collateVal = 0;
   3780 
   3781                     UBool nonZeroValReached = FALSE;
   3782 
   3783                     uint8_t numTempBuf[UCOL_MAX_DIGITS_FOR_NUMBER/2 + 2]; // I just need a temporary place to store my generated CEs.
   3784                     /*
   3785                     We parse the source string until we hit a char that's NOT a digit.
   3786                     Use this u_charDigitValue. This might be slow because we have to
   3787                     handle surrogates...
   3788                     */
   3789                     /*
   3790                     We need to break up the digit string into collection elements of UCOL_MAX_DIGITS_FOR_NUMBER or less,
   3791                     with any chunks smaller than that being on the right end of the digit string - i.e. the first collation
   3792                     element we process when going backward. To determine how long that chunk might be, we may need to make
   3793                     two passes through the loop that collects digits - one to see how long the string is (and how much is
   3794                     leading zeros) to determine the length of that right-hand chunk, and a second (if the whole string has
   3795                     more than UCOL_MAX_DIGITS_FOR_NUMBER non-leading-zero digits) to actually process that collation
   3796                     element chunk after resetting the state to the initialState at the right side of the digit string.
   3797                     */
   3798                     uint32_t ceLimit = 0;
   3799                     UChar initial_ch = ch;
   3800                     collIterateState initialState = {0,0,0,0,0,0,0,0,0};
   3801                     backupState(source, &initialState);
   3802 
   3803                     for(;;) {
   3804                         collIterateState state = {0,0,0,0,0,0,0,0,0};
   3805                         UChar32 char32 = 0;
   3806                         int32_t digVal = 0;
   3807 
   3808                         if (U16_IS_TRAIL (ch)) {
   3809                             if (!collIter_bos(source)){
   3810                                 UChar lead = getPrevNormalizedChar(source, status);
   3811                                 if(U16_IS_LEAD(lead)) {
   3812                                     char32 = U16_GET_SUPPLEMENTARY(lead,ch);
   3813                                     goBackOne(source);
   3814                                 } else {
   3815                                     char32 = ch;
   3816                                 }
   3817                             } else {
   3818                                 char32 = ch;
   3819                             }
   3820                         } else {
   3821                             char32 = ch;
   3822                         }
   3823                         digVal = u_charDigitValue(char32);
   3824 
   3825                         for(;;) {
   3826                             // Make sure we have enough space. No longer needed;
   3827                             // at this point the largest value of digIndx when we need to save data in numTempBuf
   3828                             // is UCOL_MAX_DIGITS_FOR_NUMBER-1 (digIndx is post-incremented) so we just ensure
   3829                             // that numTempBuf is big enough (UCOL_MAX_DIGITS_FOR_NUMBER/2 + 2).
   3830 
   3831                             // Skip over trailing zeroes, and keep a count of them.
   3832                             if (digVal != 0)
   3833                                 nonZeroValReached = TRUE;
   3834 
   3835                             if (nonZeroValReached) {
   3836                                 /*
   3837                                 We parse the digit string into base 100 numbers (this fits into a byte).
   3838                                 We only add to the buffer in twos, thus if we are parsing an odd character,
   3839                                 that serves as the 'tens' digit while the if we are parsing an even one, that
   3840                                 is the 'ones' digit. We dumped the parsed base 100 value (collateVal) into
   3841                                 a buffer. We multiply each collateVal by 2 (to give us room) and add 5 (to avoid
   3842                                 overlapping magic CE byte values). The last byte we subtract 1 to ensure it is less
   3843                                 than all the other bytes.
   3844 
   3845                                 Since we're doing in this reverse we want to put the first digit encountered into the
   3846                                 ones place and the second digit encountered into the tens place.
   3847                                 */
   3848 
   3849                                 if ((digIndx + trailingZeroCount) % 2 == 1) {
   3850                                     // High-order digit case (tens place)
   3851                                     collateVal += (uint8_t)(digVal * 10);
   3852 
   3853                                     // We cannot set leadingZeroIndex unless it has been set for the
   3854                                     // low-order digit. Therefore, all we can do for the high-order
   3855                                     // digit is turn it off, never on.
   3856                                     // The only time we will have a high digit without a low is for
   3857                                     // the very first non-zero digit, so no zero check is necessary.
   3858                                     if (collateVal != 0)
   3859                                         leadingZeroIndex = 0;
   3860 
   3861                                     // The first pass through, digIndx may exceed the limit, but in that case
   3862                                     // we no longer care about numTempBuf contents since they will be discarded
   3863                                     if ( digIndx < UCOL_MAX_DIGITS_FOR_NUMBER ) {
   3864                                         numTempBuf[(digIndx/2) + 2] = collateVal*2 + 6;
   3865                                     }
   3866                                     collateVal = 0;
   3867                                 } else {
   3868                                     // Low-order digit case (ones place)
   3869                                     collateVal = (uint8_t)digVal;
   3870 
   3871                                     // Check for leading zeroes.
   3872                                     if (collateVal == 0) {
   3873                                         if (!leadingZeroIndex)
   3874                                             leadingZeroIndex = (digIndx/2) + 2;
   3875                                     } else
   3876                                         leadingZeroIndex = 0;
   3877 
   3878                                     // No need to write to buffer; the case of a last odd digit
   3879                                     // is handled below.
   3880                                 }
   3881                                 ++digIndx;
   3882                             } else
   3883                                 ++trailingZeroCount;
   3884 
   3885                             if (!collIter_bos(source)) {
   3886                                 ch = getPrevNormalizedChar(source, status);
   3887                                 //goBackOne(source);
   3888                                 if (U16_IS_TRAIL(ch)) {
   3889                                     backupState(source, &state);
   3890                                     if (!collIter_bos(source)) {
   3891                                         goBackOne(source);
   3892                                         UChar lead = getPrevNormalizedChar(source, status);
   3893 
   3894                                         if(U16_IS_LEAD(lead)) {
   3895                                             char32 = U16_GET_SUPPLEMENTARY(lead,ch);
   3896                                         } else {
   3897                                             loadState(source, &state, FALSE);
   3898                                             char32 = ch;
   3899                                         }
   3900                                     }
   3901                                 } else
   3902                                     char32 = ch;
   3903 
   3904                                 if ((digVal = u_charDigitValue(char32)) == -1 || (ceLimit > 0 && (digIndx + trailingZeroCount) >= ceLimit)) {
   3905                                     if (char32 > 0xFFFF) {// For surrogates.
   3906                                         loadState(source, &state, FALSE);
   3907                                     }
   3908                                     // Don't need to "reverse" the goBackOne call,
   3909                                     // as this points to the next position to process..
   3910                                     //if (char32 > 0xFFFF) // For surrogates.
   3911                                     //getNextNormalizedChar(source);
   3912                                     break;
   3913                                 }
   3914 
   3915                                 goBackOne(source);
   3916                             }else
   3917                                 break;
   3918                         }
   3919 
   3920                         if (digIndx + trailingZeroCount <= UCOL_MAX_DIGITS_FOR_NUMBER) {
   3921                             // our collation element is not too big, go ahead and finish with it
   3922                             break;
   3923                         }
   3924                         // our digit string is too long for a collation element;
   3925                         // set the limit for it, reset the state and begin again
   3926                         ceLimit = (digIndx + trailingZeroCount) % UCOL_MAX_DIGITS_FOR_NUMBER;
   3927                         if ( ceLimit == 0 ) {
   3928                             ceLimit = UCOL_MAX_DIGITS_FOR_NUMBER;
   3929                         }
   3930                         ch = initial_ch;
   3931                         loadState(source, &initialState, FALSE);
   3932                         digIndx = endIndex = leadingZeroIndex = trailingZeroCount = 0;
   3933                         collateVal = 0;
   3934                         nonZeroValReached = FALSE;
   3935                     }
   3936 
   3937                     if (! nonZeroValReached) {
   3938                         digIndx = 2;
   3939                         trailingZeroCount = 0;
   3940                         numTempBuf[2] = 6;
   3941                     }
   3942 
   3943                     if ((digIndx + trailingZeroCount) % 2 != 0) {
   3944                         numTempBuf[((digIndx)/2) + 2] = collateVal*2 + 6;
   3945                         digIndx += 1;       // The implicit leading zero
   3946                     }
   3947                     if (trailingZeroCount % 2 != 0) {
   3948                         // We had to consume one trailing zero for the low digit
   3949                         // of the least significant byte
   3950                         digIndx += 1;       // The trailing zero not in the exponent
   3951                         trailingZeroCount -= 1;
   3952                     }
   3953 
   3954                     endIndex = leadingZeroIndex ? leadingZeroIndex : ((digIndx/2) + 2) ;
   3955 
   3956                     // Subtract one off of the last byte. Really the first byte here, but it's reversed...
   3957                     numTempBuf[2] -= 1;
   3958 
   3959                     /*
   3960                     We want to skip over the first two slots in the buffer. The first slot
   3961                     is reserved for the header byte UCOL_CODAN_PLACEHOLDER. The second slot is for the
   3962                     sign/exponent byte: 0x80 + (decimalPos/2) & 7f.
   3963                     The exponent must be adjusted by the number of leading zeroes, and the number of
   3964                     trailing zeroes.
   3965                     */
   3966                     numTempBuf[0] = UCOL_CODAN_PLACEHOLDER;
   3967                     uint32_t exponent = (digIndx+trailingZeroCount)/2;
   3968                     if (leadingZeroIndex)
   3969                         exponent -= ((digIndx/2) + 2 - leadingZeroIndex);
   3970                     numTempBuf[1] = (uint8_t)(0x80 + (exponent & 0x7F));
   3971 
   3972                     // Now transfer the collation key to our collIterate struct.
   3973                     // The total size for our collation key is half of endIndex, rounded up.
   3974                     int32_t size = (endIndex+1)/2;
   3975                     if(!ensureCEsCapacity(source, size)) {
   3976                         return (uint32_t)UCOL_NULLORDER;
   3977                     }
   3978                     *(source->CEpos++) = (((numTempBuf[0] << 8) | numTempBuf[1]) << UCOL_PRIMARYORDERSHIFT) | //Primary weight
   3979                         (UCOL_BYTE_COMMON << UCOL_SECONDARYORDERSHIFT) | // Secondary weight
   3980                         UCOL_BYTE_COMMON; // Tertiary weight.
   3981                     i = endIndex - 1; // Reset the index into the buffer.
   3982                     while(i >= 2) {
   3983                         uint32_t primWeight = numTempBuf[i--] << 8;
   3984                         if ( i >= 2)
   3985                             primWeight |= numTempBuf[i--];
   3986                         *(source->CEpos++) = (primWeight << UCOL_PRIMARYORDERSHIFT) | UCOL_CONTINUATION_MARKER;
   3987                     }
   3988 
   3989                     source->toReturn = source->CEpos -1;
   3990                     return *(source->toReturn);
   3991                 } else {
   3992                     CEOffset = (uint32_t *)coll->image + getExpansionOffset(CE);
   3993                     CE = *(CEOffset++);
   3994                     break;
   3995                 }
   3996             }
   3997 
   3998         case HANGUL_SYLLABLE_TAG: /* AC00-D7AF*/
   3999             {
   4000                 static const uint32_t
   4001                     SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7;
   4002                 //const uint32_t LCount = 19;
   4003                 static const uint32_t VCount = 21;
   4004                 static const uint32_t TCount = 28;
   4005                 //const uint32_t NCount = VCount * TCount;   /* 588 */
   4006                 //const uint32_t SCount = LCount * NCount;   /* 11172 */
   4007 
   4008                 uint32_t L = ch - SBase;
   4009                 /*
   4010                 divide into pieces.
   4011                 we do it in this order since some compilers can do % and / in one
   4012                 operation
   4013                 */
   4014                 uint32_t T = L % TCount;
   4015                 L /= TCount;
   4016                 uint32_t V = L % VCount;
   4017                 L /= VCount;
   4018 
   4019                 /* offset them */
   4020                 L += LBase;
   4021                 V += VBase;
   4022                 T += TBase;
   4023 
   4024                 int32_t firstOffset = (int32_t)(source->pos - source->string);
   4025                 source->appendOffset(firstOffset, *status);
   4026 
   4027                 /*
   4028                  * return the first CE, but first put the rest into the expansion buffer
   4029                  */
   4030                 if (!source->coll->image->jamoSpecial) {
   4031                     *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, L);
   4032                     *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, V);
   4033                     source->appendOffset(firstOffset + 1, *status);
   4034 
   4035                     if (T != TBase) {
   4036                         *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, T);
   4037                         source->appendOffset(firstOffset + 1, *status);
   4038                     }
   4039 
   4040                     source->toReturn = source->CEpos - 1;
   4041 
   4042                     source->offsetReturn = source->offsetStore - 1;
   4043                     if (source->offsetReturn == source->offsetBuffer) {
   4044                         source->offsetStore = source->offsetBuffer;
   4045                     }
   4046 
   4047                     return *(source->toReturn);
   4048                 } else {
   4049                     // Since Hanguls pass the FCD check, it is
   4050                     // guaranteed that we won't be in
   4051                     // the normalization buffer if something like this happens
   4052 
   4053                     // Move Jamos into normalization buffer
   4054                     UChar *tempbuffer = source->writableBuffer.getBuffer(5);
   4055                     int32_t tempbufferLength, jamoOffset;
   4056                     tempbuffer[0] = 0;
   4057                     tempbuffer[1] = (UChar)L;
   4058                     tempbuffer[2] = (UChar)V;
   4059                     if (T != TBase) {
   4060                         tempbuffer[3] = (UChar)T;
   4061                         tempbufferLength = 4;
   4062                     } else {
   4063                         tempbufferLength = 3;
   4064                     }
   4065                     source->writableBuffer.releaseBuffer(tempbufferLength);
   4066 
   4067                     // Indicate where to continue in main input string after exhausting the writableBuffer
   4068                     if (source->pos  == source->string) {
   4069                         jamoOffset = 0;
   4070                         source->fcdPosition = NULL;
   4071                     } else {
   4072                         jamoOffset = source->pos - source->string;
   4073                         source->fcdPosition       = source->pos-1;
   4074                     }
   4075 
   4076                     // Append offsets for the additional chars
   4077                     // (not the 0, and not the L whose offsets match the original Hangul)
   4078                     int32_t jamoRemaining = tempbufferLength - 2;
   4079                     jamoOffset++; // appended offsets should match end of original Hangul
   4080                     while (jamoRemaining-- > 0) {
   4081                         source->appendOffset(jamoOffset, *status);
   4082                     }
   4083 
   4084                     source->offsetRepeatValue = jamoOffset;
   4085 
   4086                     source->offsetReturn = source->offsetStore - 1;
   4087                     if (source->offsetReturn == source->offsetBuffer) {
   4088                         source->offsetStore = source->offsetBuffer;
   4089                     }
   4090 
   4091                     source->pos               = source->writableBuffer.getTerminatedBuffer() + tempbufferLength;
   4092                     source->origFlags         = source->flags;
   4093                     source->flags            |= UCOL_ITER_INNORMBUF;
   4094                     source->flags            &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
   4095 
   4096                     return(UCOL_IGNORABLE);
   4097                 }
   4098             }
   4099 
   4100         case IMPLICIT_TAG:        /* everything that is not defined otherwise */
   4101             return getPrevImplicit(ch, source);
   4102 
   4103             // TODO: Remove CJK implicits as they are handled by the getImplicitPrimary function
   4104         case CJK_IMPLICIT_TAG:    /* 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D*/
   4105             return getPrevImplicit(ch, source);
   4106 
   4107         case SURROGATE_TAG:  /* This is a surrogate pair */
   4108             /* essentially an engaged lead surrogate. */
   4109             /* if you have encountered it here, it means that a */
   4110             /* broken sequence was encountered and this is an error */
   4111             return UCOL_NOT_FOUND;
   4112 
   4113         case LEAD_SURROGATE_TAG:  /* D800-DBFF*/
   4114             return UCOL_NOT_FOUND; /* broken surrogate sequence */
   4115 
   4116         case TRAIL_SURROGATE_TAG: /* DC00-DFFF*/
   4117             {
   4118                 UChar32 cp = 0;
   4119                 UChar  prevChar;
   4120                 const UChar *prev;
   4121                 if (isAtStartPrevIterate(source)) {
   4122                     /* we are at the start of the string, wrong place to be at */
   4123                     return UCOL_NOT_FOUND;
   4124                 }
   4125                 if (source->pos != source->writableBuffer.getBuffer()) {
   4126                     prev     = source->pos - 1;
   4127                 } else {
   4128                     prev     = source->fcdPosition;
   4129                 }
   4130                 prevChar = *prev;
   4131 
   4132                 /* Handles Han and Supplementary characters here.*/
   4133                 if (U16_IS_LEAD(prevChar)) {
   4134                     cp = ((((uint32_t)prevChar)<<10UL)+(ch)-(((uint32_t)0xd800<<10UL)+0xdc00-0x10000));
   4135                     source->pos = prev;
   4136                 } else {
   4137                     return UCOL_NOT_FOUND; /* like unassigned */
   4138                 }
   4139 
   4140                 return getPrevImplicit(cp, source);
   4141             }
   4142 
   4143             /* UCA is filled with these. Tailorings are NOT_FOUND */
   4144             /* not yet implemented */
   4145         case CHARSET_TAG:  /* this tag always returns */
   4146             /* probably after 1.8 */
   4147             return UCOL_NOT_FOUND;
   4148 
   4149         default:           /* this tag always returns */
   4150             *status = U_INTERNAL_PROGRAM_ERROR;
   4151             CE=0;
   4152             break;
   4153         }
   4154 
   4155         if (CE <= UCOL_NOT_FOUND) {
   4156             break;
   4157         }
   4158     }
   4159 
   4160     return CE;
   4161 }
   4162 
   4163 /* This should really be a macro                                                                      */
   4164 /* This function is used to reverse parts of a buffer. We need this operation when doing continuation */
   4165 /* secondaries in French                                                                              */
   4166 /*
   4167 void uprv_ucol_reverse_buffer(uint8_t *start, uint8_t *end) {
   4168   uint8_t temp;
   4169   while(start<end) {
   4170     temp = *start;
   4171     *start++ = *end;
   4172     *end-- = temp;
   4173   }
   4174 }
   4175 */
   4176 
   4177 #define uprv_ucol_reverse_buffer(TYPE, start, end) { \
   4178   TYPE tempA; \
   4179 while((start)<(end)) { \
   4180     tempA = *(start); \
   4181     *(start)++ = *(end); \
   4182     *(end)-- = tempA; \
   4183 } \
   4184 }
   4185 
   4186 /****************************************************************************/
   4187 /* Following are the sortkey generation functions                           */
   4188 /*                                                                          */
   4189 /****************************************************************************/
   4190 
   4191 U_CAPI int32_t U_EXPORT2
   4192 ucol_mergeSortkeys(const uint8_t *src1, int32_t src1Length,
   4193                    const uint8_t *src2, int32_t src2Length,
   4194                    uint8_t *dest, int32_t destCapacity) {
   4195     /* check arguments */
   4196     if( src1==NULL || src1Length<-1 || src1Length==0 || (src1Length>0 && src1[src1Length-1]!=0) ||
   4197         src2==NULL || src2Length<-1 || src2Length==0 || (src2Length>0 && src2[src2Length-1]!=0) ||
   4198         destCapacity<0 || (destCapacity>0 && dest==NULL)
   4199     ) {
   4200         /* error, attempt to write a zero byte and return 0 */
   4201         if(dest!=NULL && destCapacity>0) {
   4202             *dest=0;
   4203         }
   4204         return 0;
   4205     }
   4206 
   4207     /* check lengths and capacity */
   4208     if(src1Length<0) {
   4209         src1Length=(int32_t)uprv_strlen((const char *)src1)+1;
   4210     }
   4211     if(src2Length<0) {
   4212         src2Length=(int32_t)uprv_strlen((const char *)src2)+1;
   4213     }
   4214 
   4215     int32_t destLength=src1Length+src2Length;
   4216     if(destLength>destCapacity) {
   4217         /* the merged sort key does not fit into the destination */
   4218         return destLength;
   4219     }
   4220 
   4221     /* merge the sort keys with the same number of levels */
   4222     uint8_t *p=dest;
   4223     for(;;) {
   4224         /* copy level from src1 not including 00 or 01 */
   4225         uint8_t b;
   4226         while((b=*src1)>=2) {
   4227             ++src1;
   4228             *p++=b;
   4229         }
   4230 
   4231         /* add a 02 merge separator */
   4232         *p++=2;
   4233 
   4234         /* copy level from src2 not including 00 or 01 */
   4235         while((b=*src2)>=2) {
   4236             ++src2;
   4237             *p++=b;
   4238         }
   4239 
   4240         /* if both sort keys have another level, then add a 01 level separator and continue */
   4241         if(*src1==1 && *src2==1) {
   4242             ++src1;
   4243             ++src2;
   4244             *p++=1;
   4245         } else {
   4246             break;
   4247         }
   4248     }
   4249 
   4250     /*
   4251      * here, at least one sort key is finished now, but the other one
   4252      * might have some contents left from containing more levels;
   4253      * that contents is just appended to the result
   4254      */
   4255     if(*src1!=0) {
   4256         /* src1 is not finished, therefore *src2==0, and src1 is appended */
   4257         src2=src1;
   4258     }
   4259     /* append src2, "the other, unfinished sort key" */
   4260     while((*p++=*src2++)!=0) {}
   4261 
   4262     /* the actual length might be less than destLength if either sort key contained illegally embedded zero bytes */
   4263     return (int32_t)(p-dest);
   4264 }
   4265 
   4266 U_NAMESPACE_BEGIN
   4267 
   4268 class SortKeyByteSink : public ByteSink {
   4269 public:
   4270     SortKeyByteSink(char *dest, int32_t destCapacity)
   4271             : buffer_(dest), capacity_(destCapacity),
   4272               appended_(0) {
   4273         if (buffer_ == NULL) {
   4274             capacity_ = 0;
   4275         } else if(capacity_ < 0) {
   4276             buffer_ = NULL;
   4277             capacity_ = 0;
   4278         }
   4279     }
   4280     virtual ~SortKeyByteSink();
   4281 
   4282     virtual void Append(const char *bytes, int32_t n);
   4283     void Append(uint32_t b) {
   4284         if (appended_ < capacity_ || Resize(1, appended_)) {
   4285             buffer_[appended_] = (char)b;
   4286         }
   4287         ++appended_;
   4288     }
   4289     void Append(uint32_t b1, uint32_t b2) {
   4290         int32_t a2 = appended_ + 2;
   4291         if (a2 <= capacity_ || Resize(2, appended_)) {
   4292             buffer_[appended_] = (char)b1;
   4293             buffer_[appended_ + 1] = (char)b2;
   4294         } else if(appended_ < capacity_) {
   4295             buffer_[appended_] = (char)b1;
   4296         }
   4297         appended_ = a2;
   4298     }
   4299     virtual char *GetAppendBuffer(int32_t min_capacity,
   4300                                   int32_t desired_capacity_hint,
   4301                                   char *scratch, int32_t scratch_capacity,
   4302                                   int32_t *result_capacity);
   4303     int32_t NumberOfBytesAppended() const { return appended_; }
   4304     /** @return FALSE if memory allocation failed */
   4305     UBool IsOk() const { return buffer_ != NULL; }
   4306 
   4307 protected:
   4308     virtual void AppendBeyondCapacity(const char *bytes, int32_t n, int32_t length) = 0;
   4309     virtual UBool Resize(int32_t appendCapacity, int32_t length) = 0;
   4310 
   4311     void SetNotOk() {
   4312         buffer_ = NULL;
   4313         capacity_ = 0;
   4314     }
   4315 
   4316     char *buffer_;
   4317     int32_t capacity_;
   4318     int32_t appended_;
   4319 
   4320 private:
   4321     SortKeyByteSink(const SortKeyByteSink &); // copy constructor not implemented
   4322     SortKeyByteSink &operator=(const SortKeyByteSink &); // assignment operator not implemented
   4323 };
   4324 
   4325 SortKeyByteSink::~SortKeyByteSink() {}
   4326 
   4327 void
   4328 SortKeyByteSink::Append(const char *bytes, int32_t n) {
   4329     if (n <= 0 || bytes == NULL) {
   4330         return;
   4331     }
   4332     int32_t length = appended_;
   4333     appended_ += n;
   4334     if ((buffer_ + length) == bytes) {
   4335         return;  // the caller used GetAppendBuffer() and wrote the bytes already
   4336     }
   4337     int32_t available = capacity_ - length;
   4338     if (n <= available) {
   4339         uprv_memcpy(buffer_ + length, bytes, n);
   4340     } else {
   4341         AppendBeyondCapacity(bytes, n, length);
   4342     }
   4343 }
   4344 
   4345 char *
   4346 SortKeyByteSink::GetAppendBuffer(int32_t min_capacity,
   4347                                  int32_t desired_capacity_hint,
   4348                                  char *scratch,
   4349                                  int32_t scratch_capacity,
   4350                                  int32_t *result_capacity) {
   4351     if (min_capacity < 1 || scratch_capacity < min_capacity) {
   4352         *result_capacity = 0;
   4353         return NULL;
   4354     }
   4355     int32_t available = capacity_ - appended_;
   4356     if (available >= min_capacity) {
   4357         *result_capacity = available;
   4358         return buffer_ + appended_;
   4359     } else if (Resize(desired_capacity_hint, appended_)) {
   4360         *result_capacity = capacity_ - appended_;
   4361         return buffer_ + appended_;
   4362     } else {
   4363         *result_capacity = scratch_capacity;
   4364         return scratch;
   4365     }
   4366 }
   4367 
   4368 class FixedSortKeyByteSink : public SortKeyByteSink {
   4369 public:
   4370     FixedSortKeyByteSink(char *dest, int32_t destCapacity)
   4371             : SortKeyByteSink(dest, destCapacity) {}
   4372     virtual ~FixedSortKeyByteSink();
   4373 
   4374 private:
   4375     virtual void AppendBeyondCapacity(const char *bytes, int32_t n, int32_t length);
   4376     virtual UBool Resize(int32_t appendCapacity, int32_t length);
   4377 };
   4378 
   4379 FixedSortKeyByteSink::~FixedSortKeyByteSink() {}
   4380 
   4381 void
   4382 FixedSortKeyByteSink::AppendBeyondCapacity(const char *bytes, int32_t /*n*/, int32_t length) {
   4383     // buffer_ != NULL && bytes != NULL && n > 0 && appended_ > capacity_
   4384     // Fill the buffer completely.
   4385     int32_t available = capacity_ - length;
   4386     if (available > 0) {
   4387         uprv_memcpy(buffer_ + length, bytes, available);
   4388     }
   4389 }
   4390 
   4391 UBool
   4392 FixedSortKeyByteSink::Resize(int32_t /*appendCapacity*/, int32_t /*length*/) {
   4393     return FALSE;
   4394 }
   4395 
   4396 class CollationKeyByteSink : public SortKeyByteSink {
   4397 public:
   4398     CollationKeyByteSink(CollationKey &key)
   4399             : SortKeyByteSink(reinterpret_cast<char *>(key.getBytes()), key.getCapacity()),
   4400               key_(key) {}
   4401     virtual ~CollationKeyByteSink();
   4402 
   4403 private:
   4404     virtual void AppendBeyondCapacity(const char *bytes, int32_t n, int32_t length);
   4405     virtual UBool Resize(int32_t appendCapacity, int32_t length);
   4406 
   4407     CollationKey &key_;
   4408 };
   4409 
   4410 CollationKeyByteSink::~CollationKeyByteSink() {}
   4411 
   4412 void
   4413 CollationKeyByteSink::AppendBeyondCapacity(const char *bytes, int32_t n, int32_t length) {
   4414     // buffer_ != NULL && bytes != NULL && n > 0 && appended_ > capacity_
   4415     if (Resize(n, length)) {
   4416         uprv_memcpy(buffer_ + length, bytes, n);
   4417     }
   4418 }
   4419 
   4420 UBool
   4421 CollationKeyByteSink::Resize(int32_t appendCapacity, int32_t length) {
   4422     if (buffer_ == NULL) {
   4423         return FALSE;  // allocation failed before already
   4424     }
   4425     int32_t newCapacity = 2 * capacity_;
   4426     int32_t altCapacity = length + 2 * appendCapacity;
   4427     if (newCapacity < altCapacity) {
   4428         newCapacity = altCapacity;
   4429     }
   4430     if (newCapacity < 200) {
   4431         newCapacity = 200;
   4432     }
   4433     uint8_t *newBuffer = key_.reallocate(newCapacity, length);
   4434     if (newBuffer == NULL) {
   4435         SetNotOk();
   4436         return FALSE;
   4437     }
   4438     buffer_ = reinterpret_cast<char *>(newBuffer);
   4439     capacity_ = newCapacity;
   4440     return TRUE;
   4441 }
   4442 
   4443 /**
   4444  * uint8_t byte buffer, similar to CharString but simpler.
   4445  */
   4446 class SortKeyLevel : public UMemory {
   4447 public:
   4448     SortKeyLevel() : len(0), ok(TRUE) {}
   4449     ~SortKeyLevel() {}
   4450 
   4451     /** @return FALSE if memory allocation failed */
   4452     UBool isOk() const { return ok; }
   4453     UBool isEmpty() const { return len == 0; }
   4454     int32_t length() const { return len; }
   4455     const uint8_t *data() const { return buffer.getAlias(); }
   4456     uint8_t operator[](int32_t index) const { return buffer[index]; }
   4457 
   4458     void appendByte(uint32_t b);
   4459 
   4460     void appendTo(ByteSink &sink) const {
   4461         sink.Append(reinterpret_cast<const char *>(buffer.getAlias()), len);
   4462     }
   4463 
   4464     uint8_t &lastByte() {
   4465         U_ASSERT(len > 0);
   4466         return buffer[len - 1];
   4467     }
   4468 
   4469     uint8_t *getLastFewBytes(int32_t n) {
   4470         if (ok && len >= n) {
   4471             return buffer.getAlias() + len - n;
   4472         } else {
   4473             return NULL;
   4474         }
   4475     }
   4476 
   4477 private:
   4478     MaybeStackArray<uint8_t, 40> buffer;
   4479     int32_t len;
   4480     UBool ok;
   4481 
   4482     UBool ensureCapacity(int32_t appendCapacity);
   4483 
   4484     SortKeyLevel(const SortKeyLevel &other); // forbid copying of this class
   4485     SortKeyLevel &operator=(const SortKeyLevel &other); // forbid copying of this class
   4486 };
   4487 
   4488 void SortKeyLevel::appendByte(uint32_t b) {
   4489     if(len < buffer.getCapacity() || ensureCapacity(1)) {
   4490         buffer[len++] = (uint8_t)b;
   4491     }
   4492 }
   4493 
   4494 UBool SortKeyLevel::ensureCapacity(int32_t appendCapacity) {
   4495     if(!ok) {
   4496         return FALSE;
   4497     }
   4498     int32_t newCapacity = 2 * buffer.getCapacity();
   4499     int32_t altCapacity = len + 2 * appendCapacity;
   4500     if (newCapacity < altCapacity) {
   4501         newCapacity = altCapacity;
   4502     }
   4503     if (newCapacity < 200) {
   4504         newCapacity = 200;
   4505     }
   4506     if(buffer.resize(newCapacity, len)==NULL) {
   4507         return ok = FALSE;
   4508     }
   4509     return TRUE;
   4510 }
   4511 
   4512 U_NAMESPACE_END
   4513 
   4514 /* sortkey API */
   4515 U_CAPI int32_t U_EXPORT2
   4516 ucol_getSortKey(const    UCollator    *coll,
   4517         const    UChar        *source,
   4518         int32_t        sourceLength,
   4519         uint8_t        *result,
   4520         int32_t        resultLength)
   4521 {
   4522     UTRACE_ENTRY(UTRACE_UCOL_GET_SORTKEY);
   4523     if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
   4524         UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source string = %vh ", coll, source,
   4525             ((sourceLength==-1 && source!=NULL) ? u_strlen(source) : sourceLength));
   4526     }
   4527 
   4528     if(coll->delegate != NULL) {
   4529       return ((const Collator*)coll->delegate)->getSortKey(source, sourceLength, result, resultLength);
   4530     }
   4531 
   4532     UErrorCode status = U_ZERO_ERROR;
   4533     int32_t keySize   = 0;
   4534 
   4535     if(source != NULL) {
   4536         // source == NULL is actually an error situation, but we would need to
   4537         // have an error code to return it. Until we introduce a new
   4538         // API, it stays like this
   4539 
   4540         /* this uses the function pointer that is set in updateinternalstate */
   4541         /* currently, there are two funcs: */
   4542         /*ucol_calcSortKey(...);*/
   4543         /*ucol_calcSortKeySimpleTertiary(...);*/
   4544 
   4545         uint8_t noDest[1] = { 0 };
   4546         if(result == NULL) {
   4547             // Distinguish pure preflighting from an allocation error.
   4548             result = noDest;
   4549             resultLength = 0;
   4550         }
   4551         FixedSortKeyByteSink sink(reinterpret_cast<char *>(result), resultLength);
   4552         coll->sortKeyGen(coll, source, sourceLength, sink, &status);
   4553         if(U_SUCCESS(status)) {
   4554             keySize = sink.NumberOfBytesAppended();
   4555         }
   4556     }
   4557     UTRACE_DATA2(UTRACE_VERBOSE, "Sort Key = %vb", result, keySize);
   4558     UTRACE_EXIT_STATUS(status);
   4559     return keySize;
   4560 }
   4561 
   4562 U_CFUNC int32_t
   4563 ucol_getCollationKey(const UCollator *coll,
   4564                      const UChar *source, int32_t sourceLength,
   4565                      CollationKey &key,
   4566                      UErrorCode &errorCode) {
   4567     CollationKeyByteSink sink(key);
   4568     coll->sortKeyGen(coll, source, sourceLength, sink, &errorCode);
   4569     return sink.NumberOfBytesAppended();
   4570 }
   4571 
   4572 // Is this primary weight compressible?
   4573 // Returns false for multi-lead-byte scripts (digits, Latin, Han, implicit).
   4574 // TODO: This should use per-lead-byte flags from FractionalUCA.txt.
   4575 static inline UBool
   4576 isCompressible(const UCollator * /*coll*/, uint8_t primary1) {
   4577     return UCOL_BYTE_FIRST_NON_LATIN_PRIMARY <= primary1 && primary1 <= maxRegularPrimary;
   4578 }
   4579 
   4580 static
   4581 inline void doCaseShift(SortKeyLevel &cases, uint32_t &caseShift) {
   4582     if (caseShift  == 0) {
   4583         cases.appendByte(UCOL_CASE_BYTE_START);
   4584         caseShift = UCOL_CASE_SHIFT_START;
   4585     }
   4586 }
   4587 
   4588 // Packs the secondary buffer when processing French locale.
   4589 static void
   4590 packFrench(const uint8_t *secondaries, int32_t secsize, SortKeyByteSink &result) {
   4591     secondaries += secsize;  // We read the secondary-level bytes back to front.
   4592     uint8_t secondary;
   4593     int32_t count2 = 0;
   4594     int32_t i = 0;
   4595     // we use i here since the key size already accounts for terminators, so we'll discard the increment
   4596     for(i = 0; i<secsize; i++) {
   4597         secondary = *(secondaries-i-1);
   4598         /* This is compression code. */
   4599         if (secondary == UCOL_COMMON2) {
   4600             ++count2;
   4601         } else {
   4602             if (count2 > 0) {
   4603                 if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
   4604                     while (count2 > UCOL_TOP_COUNT2) {
   4605                         result.Append(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2);
   4606                         count2 -= (uint32_t)UCOL_TOP_COUNT2;
   4607                     }
   4608                     result.Append(UCOL_COMMON_TOP2 - (count2-1));
   4609                 } else {
   4610                     while (count2 > UCOL_BOT_COUNT2) {
   4611                         result.Append(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
   4612                         count2 -= (uint32_t)UCOL_BOT_COUNT2;
   4613                     }
   4614                     result.Append(UCOL_COMMON_BOT2 + (count2-1));
   4615                 }
   4616                 count2 = 0;
   4617             }
   4618             result.Append(secondary);
   4619         }
   4620     }
   4621     if (count2 > 0) {
   4622         while (count2 > UCOL_BOT_COUNT2) {
   4623             result.Append(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
   4624             count2 -= (uint32_t)UCOL_BOT_COUNT2;
   4625         }
   4626         result.Append(UCOL_COMMON_BOT2 + (count2-1));
   4627     }
   4628 }
   4629 
   4630 #define DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY 0
   4631 
   4632 /* This is the sortkey work horse function */
   4633 U_CFUNC void U_CALLCONV
   4634 ucol_calcSortKey(const    UCollator    *coll,
   4635         const    UChar        *source,
   4636         int32_t        sourceLength,
   4637         SortKeyByteSink &result,
   4638         UErrorCode *status)
   4639 {
   4640     if(U_FAILURE(*status)) {
   4641         return;
   4642     }
   4643 
   4644     SortKeyByteSink &primaries = result;
   4645     SortKeyLevel secondaries;
   4646     SortKeyLevel tertiaries;
   4647     SortKeyLevel cases;
   4648     SortKeyLevel quads;
   4649 
   4650     UnicodeString normSource;
   4651 
   4652     int32_t len = (sourceLength == -1 ? u_strlen(source) : sourceLength);
   4653 
   4654     UColAttributeValue strength = coll->strength;
   4655 
   4656     uint8_t compareSec   = (uint8_t)((strength >= UCOL_SECONDARY)?0:0xFF);
   4657     uint8_t compareTer   = (uint8_t)((strength >= UCOL_TERTIARY)?0:0xFF);
   4658     uint8_t compareQuad  = (uint8_t)((strength >= UCOL_QUATERNARY)?0:0xFF);
   4659     UBool  compareIdent = (strength == UCOL_IDENTICAL);
   4660     UBool  doCase = (coll->caseLevel == UCOL_ON);
   4661     UBool  isFrenchSec = (coll->frenchCollation == UCOL_ON) && (compareSec == 0);
   4662     UBool  shifted = (coll->alternateHandling == UCOL_SHIFTED);
   4663     //UBool  qShifted = shifted && (compareQuad == 0);
   4664     UBool  doHiragana = (coll->hiraganaQ == UCOL_ON) && (compareQuad == 0);
   4665 
   4666     uint32_t variableTopValue = coll->variableTopValue;
   4667     // TODO: UCOL_COMMON_BOT4 should be a function of qShifted. If we have no
   4668     // qShifted, we don't need to set UCOL_COMMON_BOT4 so high.
   4669     uint8_t UCOL_COMMON_BOT4 = (uint8_t)((coll->variableTopValue>>8)+1);
   4670     uint8_t UCOL_HIRAGANA_QUAD = 0;
   4671     if(doHiragana) {
   4672         UCOL_HIRAGANA_QUAD=UCOL_COMMON_BOT4++;
   4673         /* allocate one more space for hiragana, value for hiragana */
   4674     }
   4675     uint8_t UCOL_BOT_COUNT4 = (uint8_t)(0xFF - UCOL_COMMON_BOT4);
   4676 
   4677     /* support for special features like caselevel and funky secondaries */
   4678     int32_t lastSecondaryLength = 0;
   4679     uint32_t caseShift = 0;
   4680 
   4681     /* If we need to normalize, we'll do it all at once at the beginning! */
   4682     const Normalizer2 *norm2;
   4683     if(compareIdent) {
   4684         norm2 = Normalizer2Factory::getNFDInstance(*status);
   4685     } else if(coll->normalizationMode != UCOL_OFF) {
   4686         norm2 = Normalizer2Factory::getFCDInstance(*status);
   4687     } else {
   4688         norm2 = NULL;
   4689     }
   4690     if(norm2 != NULL) {
   4691         normSource.setTo(FALSE, source, len);
   4692         int32_t qcYesLength = norm2->spanQuickCheckYes(normSource, *status);
   4693         if(qcYesLength != len) {
   4694             UnicodeString unnormalized = normSource.tempSubString(qcYesLength);
   4695             normSource.truncate(qcYesLength);
   4696             norm2->normalizeSecondAndAppend(normSource, unnormalized, *status);
   4697             source = normSource.getBuffer();
   4698             len = normSource.length();
   4699         }
   4700     }
   4701     collIterate s;
   4702     IInit_collIterate(coll, source, len, &s, status);
   4703     if(U_FAILURE(*status)) {
   4704         return;
   4705     }
   4706     s.flags &= ~UCOL_ITER_NORM;  // source passed the FCD test or else was normalized.
   4707 
   4708     uint32_t order = 0;
   4709 
   4710     uint8_t primary1 = 0;
   4711     uint8_t primary2 = 0;
   4712     uint8_t secondary = 0;
   4713     uint8_t tertiary = 0;
   4714     uint8_t caseSwitch = coll->caseSwitch;
   4715     uint8_t tertiaryMask = coll->tertiaryMask;
   4716     int8_t tertiaryAddition = coll->tertiaryAddition;
   4717     uint8_t tertiaryTop = coll->tertiaryTop;
   4718     uint8_t tertiaryBottom = coll->tertiaryBottom;
   4719     uint8_t tertiaryCommon = coll->tertiaryCommon;
   4720     uint8_t caseBits = 0;
   4721 
   4722     UBool wasShifted = FALSE;
   4723     UBool notIsContinuation = FALSE;
   4724 
   4725     uint32_t count2 = 0, count3 = 0, count4 = 0;
   4726     uint8_t leadPrimary = 0;
   4727 
   4728     for(;;) {
   4729         order = ucol_IGetNextCE(coll, &s, status);
   4730         if(order == UCOL_NO_MORE_CES) {
   4731             break;
   4732         }
   4733 
   4734         if(order == 0) {
   4735             continue;
   4736         }
   4737 
   4738         notIsContinuation = !isContinuation(order);
   4739 
   4740         if(notIsContinuation) {
   4741             tertiary = (uint8_t)(order & UCOL_BYTE_SIZE_MASK);
   4742         } else {
   4743             tertiary = (uint8_t)((order & UCOL_REMOVE_CONTINUATION));
   4744         }
   4745 
   4746         secondary = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
   4747         primary2 = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
   4748         primary1 = (uint8_t)(order >> 8);
   4749 
   4750         uint8_t originalPrimary1 = primary1;
   4751         if(notIsContinuation && coll->leadBytePermutationTable != NULL) {
   4752             primary1 = coll->leadBytePermutationTable[primary1];
   4753         }
   4754 
   4755         if((shifted && ((notIsContinuation && order <= variableTopValue && primary1 > 0)
   4756                         || (!notIsContinuation && wasShifted)))
   4757             || (wasShifted && primary1 == 0)) /* amendment to the UCA says that primary ignorables */
   4758         {
   4759             /* and other ignorables should be removed if following a shifted code point */
   4760             if(primary1 == 0) { /* if we were shifted and we got an ignorable code point */
   4761                 /* we should just completely ignore it */
   4762                 continue;
   4763             }
   4764             if(compareQuad == 0) {
   4765                 if(count4 > 0) {
   4766                     while (count4 > UCOL_BOT_COUNT4) {
   4767                         quads.appendByte(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4);
   4768                         count4 -= UCOL_BOT_COUNT4;
   4769                     }
   4770                     quads.appendByte(UCOL_COMMON_BOT4 + (count4-1));
   4771                     count4 = 0;
   4772                 }
   4773                 /* We are dealing with a variable and we're treating them as shifted */
   4774                 /* This is a shifted ignorable */
   4775                 if(primary1 != 0) { /* we need to check this since we could be in continuation */
   4776                     quads.appendByte(primary1);
   4777                 }
   4778                 if(primary2 != 0) {
   4779                     quads.appendByte(primary2);
   4780                 }
   4781             }
   4782             wasShifted = TRUE;
   4783         } else {
   4784             wasShifted = FALSE;
   4785             /* Note: This code assumes that the table is well built i.e. not having 0 bytes where they are not supposed to be. */
   4786             /* Usually, we'll have non-zero primary1 & primary2, except in cases of a-z and friends, when primary2 will   */
   4787             /* regular and simple sortkey calc */
   4788             if(primary1 != UCOL_IGNORABLE) {
   4789                 if(notIsContinuation) {
   4790                     if(leadPrimary == primary1) {
   4791                         primaries.Append(primary2);
   4792                     } else {
   4793                         if(leadPrimary != 0) {
   4794                             primaries.Append((primary1 > leadPrimary) ? UCOL_BYTE_UNSHIFTED_MAX : UCOL_BYTE_UNSHIFTED_MIN);
   4795                         }
   4796                         if(primary2 == UCOL_IGNORABLE) {
   4797                             /* one byter, not compressed */
   4798                             primaries.Append(primary1);
   4799                             leadPrimary = 0;
   4800                         } else if(isCompressible(coll, originalPrimary1)) {
   4801                             /* compress */
   4802                             primaries.Append(leadPrimary = primary1, primary2);
   4803                         } else {
   4804                             leadPrimary = 0;
   4805                             primaries.Append(primary1, primary2);
   4806                         }
   4807                     }
   4808                 } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
   4809                     if(primary2 == UCOL_IGNORABLE) {
   4810                         primaries.Append(primary1);
   4811                     } else {
   4812                         primaries.Append(primary1, primary2);
   4813                     }
   4814                 }
   4815             }
   4816 
   4817             if(secondary > compareSec) {
   4818                 if(!isFrenchSec) {
   4819                     /* This is compression code. */
   4820                     if (secondary == UCOL_COMMON2 && notIsContinuation) {
   4821                         ++count2;
   4822                     } else {
   4823                         if (count2 > 0) {
   4824                             if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
   4825                                 while (count2 > UCOL_TOP_COUNT2) {
   4826                                     secondaries.appendByte(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2);
   4827                                     count2 -= (uint32_t)UCOL_TOP_COUNT2;
   4828                                 }
   4829                                 secondaries.appendByte(UCOL_COMMON_TOP2 - (count2-1));
   4830                             } else {
   4831                                 while (count2 > UCOL_BOT_COUNT2) {
   4832                                     secondaries.appendByte(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
   4833                                     count2 -= (uint32_t)UCOL_BOT_COUNT2;
   4834                                 }
   4835                                 secondaries.appendByte(UCOL_COMMON_BOT2 + (count2-1));
   4836                             }
   4837                             count2 = 0;
   4838                         }
   4839                         secondaries.appendByte(secondary);
   4840                     }
   4841                 } else {
   4842                     /* Do the special handling for French secondaries */
   4843                     /* We need to get continuation elements and do intermediate restore */
   4844                     /* abc1c2c3de with french secondaries need to be edc1c2c3ba NOT edc3c2c1ba */
   4845                     if(notIsContinuation) {
   4846                         if (lastSecondaryLength > 1) {
   4847                             uint8_t *frenchStartPtr = secondaries.getLastFewBytes(lastSecondaryLength);
   4848                             if (frenchStartPtr != NULL) {
   4849                                 /* reverse secondaries from frenchStartPtr up to frenchEndPtr */
   4850                                 uint8_t *frenchEndPtr = frenchStartPtr + lastSecondaryLength - 1;
   4851                                 uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
   4852                             }
   4853                         }
   4854                         lastSecondaryLength = 1;
   4855                     } else {
   4856                         ++lastSecondaryLength;
   4857                     }
   4858                     secondaries.appendByte(secondary);
   4859                 }
   4860             }
   4861 
   4862             if(doCase && (primary1 > 0 || strength >= UCOL_SECONDARY)) {
   4863                 // do the case level if we need to do it. We don't want to calculate
   4864                 // case level for primary ignorables if we have only primary strength and case level
   4865                 // otherwise we would break well formedness of CEs
   4866                 doCaseShift(cases, caseShift);
   4867                 if(notIsContinuation) {
   4868                     caseBits = (uint8_t)(tertiary & 0xC0);
   4869 
   4870                     if(tertiary != 0) {
   4871                         if(coll->caseFirst == UCOL_UPPER_FIRST) {
   4872                             if((caseBits & 0xC0) == 0) {
   4873                                 cases.lastByte() |= 1 << (--caseShift);
   4874                             } else {
   4875                                 cases.lastByte() |= 0 << (--caseShift);
   4876                                 /* second bit */
   4877                                 doCaseShift(cases, caseShift);
   4878                                 cases.lastByte() |= ((caseBits>>6)&1) << (--caseShift);
   4879                             }
   4880                         } else {
   4881                             if((caseBits & 0xC0) == 0) {
   4882                                 cases.lastByte() |= 0 << (--caseShift);
   4883                             } else {
   4884                                 cases.lastByte() |= 1 << (--caseShift);
   4885                                 /* second bit */
   4886                                 doCaseShift(cases, caseShift);
   4887                                 cases.lastByte() |= ((caseBits>>7)&1) << (--caseShift);
   4888                             }
   4889                         }
   4890                     }
   4891                 }
   4892             } else {
   4893                 if(notIsContinuation) {
   4894                     tertiary ^= caseSwitch;
   4895                 }
   4896             }
   4897 
   4898             tertiary &= tertiaryMask;
   4899             if(tertiary > compareTer) {
   4900                 /* This is compression code. */
   4901                 /* sequence size check is included in the if clause */
   4902                 if (tertiary == tertiaryCommon && notIsContinuation) {
   4903                     ++count3;
   4904                 } else {
   4905                     if(tertiary > tertiaryCommon && tertiaryCommon == UCOL_COMMON3_NORMAL) {
   4906                         tertiary += tertiaryAddition;
   4907                     } else if(tertiary <= tertiaryCommon && tertiaryCommon == UCOL_COMMON3_UPPERFIRST) {
   4908                         tertiary -= tertiaryAddition;
   4909                     }
   4910                     if (count3 > 0) {
   4911                         if ((tertiary > tertiaryCommon)) {
   4912                             while (count3 > coll->tertiaryTopCount) {
   4913                                 tertiaries.appendByte(tertiaryTop - coll->tertiaryTopCount);
   4914                                 count3 -= (uint32_t)coll->tertiaryTopCount;
   4915                             }
   4916                             tertiaries.appendByte(tertiaryTop - (count3-1));
   4917                         } else {
   4918                             while (count3 > coll->tertiaryBottomCount) {
   4919                                 tertiaries.appendByte(tertiaryBottom + coll->tertiaryBottomCount);
   4920                                 count3 -= (uint32_t)coll->tertiaryBottomCount;
   4921                             }
   4922                             tertiaries.appendByte(tertiaryBottom + (count3-1));
   4923                         }
   4924                         count3 = 0;
   4925                     }
   4926                     tertiaries.appendByte(tertiary);
   4927                 }
   4928             }
   4929 
   4930             if(/*qShifted*/(compareQuad==0)  && notIsContinuation) {
   4931                 if(s.flags & UCOL_WAS_HIRAGANA) { // This was Hiragana and we need to note it
   4932                     if(count4>0) { // Close this part
   4933                         while (count4 > UCOL_BOT_COUNT4) {
   4934                             quads.appendByte(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4);
   4935                             count4 -= UCOL_BOT_COUNT4;
   4936                         }
   4937                         quads.appendByte(UCOL_COMMON_BOT4 + (count4-1));
   4938                         count4 = 0;
   4939                     }
   4940                     quads.appendByte(UCOL_HIRAGANA_QUAD); // Add the Hiragana
   4941                 } else { // This wasn't Hiragana, so we can continue adding stuff
   4942                     count4++;
   4943                 }
   4944             }
   4945         }
   4946     }
   4947 
   4948     /* Here, we are generally done with processing */
   4949     /* bailing out would not be too productive */
   4950 
   4951     UBool ok = TRUE;
   4952     if(U_SUCCESS(*status)) {
   4953         /* we have done all the CE's, now let's put them together to form a key */
   4954         if(compareSec == 0) {
   4955             if (count2 > 0) {
   4956                 while (count2 > UCOL_BOT_COUNT2) {
   4957                     secondaries.appendByte(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
   4958                     count2 -= (uint32_t)UCOL_BOT_COUNT2;
   4959                 }
   4960                 secondaries.appendByte(UCOL_COMMON_BOT2 + (count2-1));
   4961             }
   4962             result.Append(UCOL_LEVELTERMINATOR);
   4963             if(!secondaries.isOk()) {
   4964                 ok = FALSE;
   4965             } else if(!isFrenchSec) {
   4966                 secondaries.appendTo(result);
   4967             } else {
   4968                 // If there are any unresolved continuation secondaries,
   4969                 // reverse them here so that we can reverse the whole secondary thing.
   4970                 if (lastSecondaryLength > 1) {
   4971                     uint8_t *frenchStartPtr = secondaries.getLastFewBytes(lastSecondaryLength);
   4972                     if (frenchStartPtr != NULL) {
   4973                         /* reverse secondaries from frenchStartPtr up to frenchEndPtr */
   4974                         uint8_t *frenchEndPtr = frenchStartPtr + lastSecondaryLength - 1;
   4975                         uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
   4976                     }
   4977                 }
   4978                 packFrench(secondaries.data(), secondaries.length(), result);
   4979             }
   4980         }
   4981 
   4982         if(doCase) {
   4983             ok &= cases.isOk();
   4984             result.Append(UCOL_LEVELTERMINATOR);
   4985             cases.appendTo(result);
   4986         }
   4987 
   4988         if(compareTer == 0) {
   4989             if (count3 > 0) {
   4990                 if (coll->tertiaryCommon != UCOL_COMMON_BOT3) {
   4991                     while (count3 >= coll->tertiaryTopCount) {
   4992                         tertiaries.appendByte(tertiaryTop - coll->tertiaryTopCount);
   4993                         count3 -= (uint32_t)coll->tertiaryTopCount;
   4994                     }
   4995                     tertiaries.appendByte(tertiaryTop - count3);
   4996                 } else {
   4997                     while (count3 > coll->tertiaryBottomCount) {
   4998                         tertiaries.appendByte(tertiaryBottom + coll->tertiaryBottomCount);
   4999                         count3 -= (uint32_t)coll->tertiaryBottomCount;
   5000                     }
   5001                     tertiaries.appendByte(tertiaryBottom + (count3-1));
   5002                 }
   5003             }
   5004             ok &= tertiaries.isOk();
   5005             result.Append(UCOL_LEVELTERMINATOR);
   5006             tertiaries.appendTo(result);
   5007 
   5008             if(compareQuad == 0/*qShifted == TRUE*/) {
   5009                 if(count4 > 0) {
   5010                     while (count4 > UCOL_BOT_COUNT4) {
   5011                         quads.appendByte(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4);
   5012                         count4 -= UCOL_BOT_COUNT4;
   5013                     }
   5014                     quads.appendByte(UCOL_COMMON_BOT4 + (count4-1));
   5015                 }
   5016                 ok &= quads.isOk();
   5017                 result.Append(UCOL_LEVELTERMINATOR);
   5018                 quads.appendTo(result);
   5019             }
   5020 
   5021             if(compareIdent) {
   5022                 result.Append(UCOL_LEVELTERMINATOR);
   5023                 u_writeIdenticalLevelRun(s.string, len, result);
   5024             }
   5025         }
   5026         result.Append(0);
   5027     }
   5028 
   5029     /* To avoid memory leak, free the offset buffer if necessary. */
   5030     ucol_freeOffsetBuffer(&s);
   5031 
   5032     ok &= result.IsOk();
   5033     if(!ok && U_SUCCESS(*status)) { *status = U_MEMORY_ALLOCATION_ERROR; }
   5034 }
   5035 
   5036 
   5037 U_CFUNC void U_CALLCONV
   5038 ucol_calcSortKeySimpleTertiary(const    UCollator    *coll,
   5039         const    UChar        *source,
   5040         int32_t        sourceLength,
   5041         SortKeyByteSink &result,
   5042         UErrorCode *status)
   5043 {
   5044     U_ALIGN_CODE(16);
   5045 
   5046     if(U_FAILURE(*status)) {
   5047         return;
   5048     }
   5049 
   5050     SortKeyByteSink &primaries = result;
   5051     SortKeyLevel secondaries;
   5052     SortKeyLevel tertiaries;
   5053 
   5054     UnicodeString normSource;
   5055 
   5056     int32_t len =  sourceLength;
   5057 
   5058     /* If we need to normalize, we'll do it all at once at the beginning! */
   5059     if(coll->normalizationMode != UCOL_OFF) {
   5060         normSource.setTo(len < 0, source, len);
   5061         const Normalizer2 *norm2 = Normalizer2Factory::getFCDInstance(*status);
   5062         int32_t qcYesLength = norm2->spanQuickCheckYes(normSource, *status);
   5063         if(qcYesLength != normSource.length()) {
   5064             UnicodeString unnormalized = normSource.tempSubString(qcYesLength);
   5065             normSource.truncate(qcYesLength);
   5066             norm2->normalizeSecondAndAppend(normSource, unnormalized, *status);
   5067             source = normSource.getBuffer();
   5068             len = normSource.length();
   5069         }
   5070     }
   5071     collIterate s;
   5072     IInit_collIterate(coll, (UChar *)source, len, &s, status);
   5073     if(U_FAILURE(*status)) {
   5074         return;
   5075     }
   5076     s.flags &= ~UCOL_ITER_NORM;  // source passed the FCD test or else was normalized.
   5077 
   5078     uint32_t order = 0;
   5079 
   5080     uint8_t primary1 = 0;
   5081     uint8_t primary2 = 0;
   5082     uint8_t secondary = 0;
   5083     uint8_t tertiary = 0;
   5084     uint8_t caseSwitch = coll->caseSwitch;
   5085     uint8_t tertiaryMask = coll->tertiaryMask;
   5086     int8_t tertiaryAddition = coll->tertiaryAddition;
   5087     uint8_t tertiaryTop = coll->tertiaryTop;
   5088     uint8_t tertiaryBottom = coll->tertiaryBottom;
   5089     uint8_t tertiaryCommon = coll->tertiaryCommon;
   5090 
   5091     UBool notIsContinuation = FALSE;
   5092 
   5093     uint32_t count2 = 0, count3 = 0;
   5094     uint8_t leadPrimary = 0;
   5095 
   5096     for(;;) {
   5097         order = ucol_IGetNextCE(coll, &s, status);
   5098 
   5099         if(order == 0) {
   5100             continue;
   5101         }
   5102 
   5103         if(order == UCOL_NO_MORE_CES) {
   5104             break;
   5105         }
   5106 
   5107         notIsContinuation = !isContinuation(order);
   5108 
   5109         if(notIsContinuation) {
   5110             tertiary = (uint8_t)((order & tertiaryMask));
   5111         } else {
   5112             tertiary = (uint8_t)((order & UCOL_REMOVE_CONTINUATION));
   5113         }
   5114 
   5115         secondary = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
   5116         primary2 = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
   5117         primary1 = (uint8_t)(order >> 8);
   5118 
   5119         uint8_t originalPrimary1 = primary1;
   5120         if (coll->leadBytePermutationTable != NULL && notIsContinuation) {
   5121             primary1 = coll->leadBytePermutationTable[primary1];
   5122         }
   5123 
   5124         /* Note: This code assumes that the table is well built i.e. not having 0 bytes where they are not supposed to be. */
   5125         /* Usually, we'll have non-zero primary1 & primary2, except in cases of a-z and friends, when primary2 will   */
   5126         /* be zero with non zero primary1. primary3 is different than 0 only for long primaries - see above.               */
   5127         /* regular and simple sortkey calc */
   5128         if(primary1 != UCOL_IGNORABLE) {
   5129             if(notIsContinuation) {
   5130                 if(leadPrimary == primary1) {
   5131                     primaries.Append(primary2);
   5132                 } else {
   5133                     if(leadPrimary != 0) {
   5134                         primaries.Append((primary1 > leadPrimary) ? UCOL_BYTE_UNSHIFTED_MAX : UCOL_BYTE_UNSHIFTED_MIN);
   5135                     }
   5136                     if(primary2 == UCOL_IGNORABLE) {
   5137                         /* one byter, not compressed */
   5138                         primaries.Append(primary1);
   5139                         leadPrimary = 0;
   5140                     } else if(isCompressible(coll, originalPrimary1)) {
   5141                         /* compress */
   5142                         primaries.Append(leadPrimary = primary1, primary2);
   5143                     } else {
   5144                         leadPrimary = 0;
   5145                         primaries.Append(primary1, primary2);
   5146                     }
   5147                 }
   5148             } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
   5149                 if(primary2 == UCOL_IGNORABLE) {
   5150                     primaries.Append(primary1);
   5151                 } else {
   5152                     primaries.Append(primary1, primary2);
   5153                 }
   5154             }
   5155         }
   5156 
   5157         if(secondary > 0) { /* I think that != 0 test should be != IGNORABLE */
   5158             /* This is compression code. */
   5159             if (secondary == UCOL_COMMON2 && notIsContinuation) {
   5160                 ++count2;
   5161             } else {
   5162                 if (count2 > 0) {
   5163                     if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
   5164                         while (count2 > UCOL_TOP_COUNT2) {
   5165                             secondaries.appendByte(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2);
   5166                             count2 -= (uint32_t)UCOL_TOP_COUNT2;
   5167                         }
   5168                         secondaries.appendByte(UCOL_COMMON_TOP2 - (count2-1));
   5169                     } else {
   5170                         while (count2 > UCOL_BOT_COUNT2) {
   5171                             secondaries.appendByte(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
   5172                             count2 -= (uint32_t)UCOL_BOT_COUNT2;
   5173                         }
   5174                         secondaries.appendByte(UCOL_COMMON_BOT2 + (count2-1));
   5175                     }
   5176                     count2 = 0;
   5177                 }
   5178                 secondaries.appendByte(secondary);
   5179             }
   5180         }
   5181 
   5182         if(notIsContinuation) {
   5183             tertiary ^= caseSwitch;
   5184         }
   5185 
   5186         if(tertiary > 0) {
   5187             /* This is compression code. */
   5188             /* sequence size check is included in the if clause */
   5189             if (tertiary == tertiaryCommon && notIsContinuation) {
   5190                 ++count3;
   5191             } else {
   5192                 if(tertiary > tertiaryCommon && tertiaryCommon == UCOL_COMMON3_NORMAL) {
   5193                     tertiary += tertiaryAddition;
   5194                 } else if (tertiary <= tertiaryCommon && tertiaryCommon == UCOL_COMMON3_UPPERFIRST) {
   5195                     tertiary -= tertiaryAddition;
   5196                 }
   5197                 if (count3 > 0) {
   5198                     if ((tertiary > tertiaryCommon)) {
   5199                         while (count3 > coll->tertiaryTopCount) {
   5200                             tertiaries.appendByte(tertiaryTop - coll->tertiaryTopCount);
   5201                             count3 -= (uint32_t)coll->tertiaryTopCount;
   5202                         }
   5203                         tertiaries.appendByte(tertiaryTop - (count3-1));
   5204                     } else {
   5205                         while (count3 > coll->tertiaryBottomCount) {
   5206                             tertiaries.appendByte(tertiaryBottom + coll->tertiaryBottomCount);
   5207                             count3 -= (uint32_t)coll->tertiaryBottomCount;
   5208                         }
   5209                         tertiaries.appendByte(tertiaryBottom + (count3-1));
   5210                     }
   5211                     count3 = 0;
   5212                 }
   5213                 tertiaries.appendByte(tertiary);
   5214             }
   5215         }
   5216     }
   5217 
   5218     UBool ok = TRUE;
   5219     if(U_SUCCESS(*status)) {
   5220         /* we have done all the CE's, now let's put them together to form a key */
   5221         if (count2 > 0) {
   5222             while (count2 > UCOL_BOT_COUNT2) {
   5223                 secondaries.appendByte(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
   5224                 count2 -= (uint32_t)UCOL_BOT_COUNT2;
   5225             }
   5226             secondaries.appendByte(UCOL_COMMON_BOT2 + (count2-1));
   5227         }
   5228         ok &= secondaries.isOk();
   5229         result.Append(UCOL_LEVELTERMINATOR);
   5230         secondaries.appendTo(result);
   5231 
   5232         if (count3 > 0) {
   5233             if (coll->tertiaryCommon != UCOL_COMMON3_NORMAL) {
   5234                 while (count3 >= coll->tertiaryTopCount) {
   5235                     tertiaries.appendByte(tertiaryTop - coll->tertiaryTopCount);
   5236                     count3 -= (uint32_t)coll->tertiaryTopCount;
   5237                 }
   5238                 tertiaries.appendByte(tertiaryTop - count3);
   5239             } else {
   5240                 while (count3 > coll->tertiaryBottomCount) {
   5241                     tertiaries.appendByte(tertiaryBottom + coll->tertiaryBottomCount);
   5242                     count3 -= (uint32_t)coll->tertiaryBottomCount;
   5243                 }
   5244                 tertiaries.appendByte(tertiaryBottom + (count3-1));
   5245             }
   5246         }
   5247         ok &= tertiaries.isOk();
   5248         result.Append(UCOL_LEVELTERMINATOR);
   5249         tertiaries.appendTo(result);
   5250 
   5251         result.Append(0);
   5252     }
   5253 
   5254     /* To avoid memory leak, free the offset buffer if necessary. */
   5255     ucol_freeOffsetBuffer(&s);
   5256 
   5257     ok &= result.IsOk();
   5258     if(!ok && U_SUCCESS(*status)) { *status = U_MEMORY_ALLOCATION_ERROR; }
   5259 }
   5260 
   5261 static inline
   5262 UBool isShiftedCE(uint32_t CE, uint32_t LVT, UBool *wasShifted) {
   5263     UBool notIsContinuation = !isContinuation(CE);
   5264     uint8_t primary1 = (uint8_t)((CE >> 24) & 0xFF);
   5265     if((LVT && ((notIsContinuation && (CE & 0xFFFF0000)<= LVT && primary1 > 0)
   5266                || (!notIsContinuation && *wasShifted)))
   5267         || (*wasShifted && primary1 == 0)) /* amendment to the UCA says that primary ignorables */
   5268     {
   5269         // The stuff below should probably be in the sortkey code... maybe not...
   5270         if(primary1 != 0) { /* if we were shifted and we got an ignorable code point */
   5271             /* we should just completely ignore it */
   5272             *wasShifted = TRUE;
   5273             //continue;
   5274         }
   5275         //*wasShifted = TRUE;
   5276         return TRUE;
   5277     } else {
   5278         *wasShifted = FALSE;
   5279         return FALSE;
   5280     }
   5281 }
   5282 static inline
   5283 void terminatePSKLevel(int32_t level, int32_t maxLevel, int32_t &i, uint8_t *dest) {
   5284     if(level < maxLevel) {
   5285         dest[i++] = UCOL_LEVELTERMINATOR;
   5286     } else {
   5287         dest[i++] = 0;
   5288     }
   5289 }
   5290 
   5291 /** enumeration of level identifiers for partial sort key generation */
   5292 enum {
   5293   UCOL_PSK_PRIMARY = 0,
   5294     UCOL_PSK_SECONDARY = 1,
   5295     UCOL_PSK_CASE = 2,
   5296     UCOL_PSK_TERTIARY = 3,
   5297     UCOL_PSK_QUATERNARY = 4,
   5298     UCOL_PSK_QUIN = 5,      /** This is an extra level, not used - but we have three bits to blow */
   5299     UCOL_PSK_IDENTICAL = 6,
   5300     UCOL_PSK_NULL = 7,      /** level for the end of sort key. Will just produce zeros */
   5301     UCOL_PSK_LIMIT
   5302 };
   5303 
   5304 /** collation state enum. *_SHIFT value is how much to shift right
   5305  *  to get the state piece to the right. *_MASK value should be
   5306  *  ANDed with the shifted state. This data is stored in state[1]
   5307  *  field.
   5308  */
   5309 enum {
   5310     UCOL_PSK_LEVEL_SHIFT = 0,      /** level identificator. stores an enum value from above */
   5311     UCOL_PSK_LEVEL_MASK = 7,       /** three bits */
   5312     UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT = 3, /** number of bytes of primary or quaternary already written */
   5313     UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK = 1,
   5314     /** can be only 0 or 1, since we get up to two bytes from primary or quaternary
   5315      *  This field is also used to denote that the French secondary level is finished
   5316      */
   5317     UCOL_PSK_WAS_SHIFTED_SHIFT = 4,/** was the last value shifted */
   5318     UCOL_PSK_WAS_SHIFTED_MASK = 1, /** can be 0 or 1 (Boolean) */
   5319     UCOL_PSK_USED_FRENCH_SHIFT = 5,/** how many French bytes have we already written */
   5320     UCOL_PSK_USED_FRENCH_MASK = 3, /** up to 4 bytes. See comment just below */
   5321     /** When we do French we need to reverse secondary values. However, continuations
   5322      *  need to stay the same. So if you had abc1c2c3de, you need to have edc1c2c3ba
   5323      */
   5324     UCOL_PSK_BOCSU_BYTES_SHIFT = 7,
   5325     UCOL_PSK_BOCSU_BYTES_MASK = 3,
   5326     UCOL_PSK_CONSUMED_CES_SHIFT = 9,
   5327     UCOL_PSK_CONSUMED_CES_MASK = 0x7FFFF
   5328 };
   5329 
   5330 // macro calculating the number of expansion CEs available
   5331 #define uprv_numAvailableExpCEs(s) (s).CEpos - (s).toReturn
   5332 
   5333 
   5334 /** main sortkey part procedure. On the first call,
   5335  *  you should pass in a collator, an iterator, empty state
   5336  *  state[0] == state[1] == 0, a buffer to hold results
   5337  *  number of bytes you need and an error code pointer.
   5338  *  Make sure your buffer is big enough to hold the wanted
   5339  *  number of sortkey bytes. I don't check.
   5340  *  The only meaningful status you can get back is
   5341  *  U_BUFFER_OVERFLOW_ERROR, which basically means that you
   5342  *  have been dealt a raw deal and that you probably won't
   5343  *  be able to use partial sortkey generation for this
   5344  *  particular combination of string and collator. This
   5345  *  is highly unlikely, but you should still check the error code.
   5346  *  Any other status means that you're not in a sane situation
   5347  *  anymore. After the first call, preserve state values and
   5348  *  use them on subsequent calls to obtain more bytes of a sortkey.
   5349  *  Use until the number of bytes written is smaller than the requested
   5350  *  number of bytes. Generated sortkey is not compatible with the
   5351  *  one generated by ucol_getSortKey, as we don't do any compression.
   5352  *  However, levels are still terminated by a 1 (one) and the sortkey
   5353  *  is terminated by a 0 (zero). Identical level is the same as in the
   5354  *  regular sortkey - internal bocu-1 implementation is used.
   5355  *  For curious, although you cannot do much about this, here is
   5356  *  the structure of state words.
   5357  *  state[0] - iterator state. Depends on the iterator implementation,
   5358  *             but allows the iterator to continue where it stopped in
   5359  *             the last iteration.
   5360  *  state[1] - collation processing state. Here is the distribution
   5361  *             of the bits:
   5362  *   0, 1, 2 - level of the sortkey - primary, secondary, case, tertiary
   5363  *             quaternary, quin (we don't use this one), identical and
   5364  *             null (producing only zeroes - first one to terminate the
   5365  *             sortkey and subsequent to fill the buffer).
   5366  *   3       - byte count. Number of bytes written on the primary level.
   5367  *   4       - was shifted. Whether the previous iteration finished in the
   5368  *             shifted state.
   5369  *   5, 6    - French continuation bytes written. See the comment in the enum
   5370  *   7,8     - Bocsu bytes used. Number of bytes from a bocu sequence on
   5371  *             the identical level.
   5372  *   9..31   - CEs consumed. Number of getCE or next32 operations performed
   5373  *             since thes last successful update of the iterator state.
   5374  */
   5375 U_CAPI int32_t U_EXPORT2
   5376 ucol_nextSortKeyPart(const UCollator *coll,
   5377                      UCharIterator *iter,
   5378                      uint32_t state[2],
   5379                      uint8_t *dest, int32_t count,
   5380                      UErrorCode *status)
   5381 {
   5382     /* error checking */
   5383     if(status==NULL || U_FAILURE(*status)) {
   5384         return 0;
   5385     }
   5386     UTRACE_ENTRY(UTRACE_UCOL_NEXTSORTKEYPART);
   5387     if( coll==NULL || iter==NULL ||
   5388         state==NULL ||
   5389         count<0 || (count>0 && dest==NULL)
   5390     ) {
   5391         *status=U_ILLEGAL_ARGUMENT_ERROR;
   5392         UTRACE_EXIT_STATUS(status);
   5393         return 0;
   5394     }
   5395 
   5396     UTRACE_DATA6(UTRACE_VERBOSE, "coll=%p, iter=%p, state=%d %d, dest=%p, count=%d",
   5397                   coll, iter, state[0], state[1], dest, count);
   5398 
   5399     if(count==0) {
   5400         /* nothing to do */
   5401         UTRACE_EXIT_VALUE(0);
   5402         return 0;
   5403     }
   5404     /** Setting up situation according to the state we got from the previous iteration */
   5405     // The state of the iterator from the previous invocation
   5406     uint32_t iterState = state[0];
   5407     // Has the last iteration ended in the shifted state
   5408     UBool wasShifted = ((state[1] >> UCOL_PSK_WAS_SHIFTED_SHIFT) & UCOL_PSK_WAS_SHIFTED_MASK)?TRUE:FALSE;
   5409     // What is the current level of the sortkey?
   5410     int32_t level= (state[1] >> UCOL_PSK_LEVEL_SHIFT) & UCOL_PSK_LEVEL_MASK;
   5411     // Have we written only one byte from a two byte primary in the previous iteration?
   5412     // Also on secondary level - have we finished with the French secondary?
   5413     int32_t byteCountOrFrenchDone = (state[1] >> UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT) & UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK;
   5414     // number of bytes in the continuation buffer for French
   5415     int32_t usedFrench = (state[1] >> UCOL_PSK_USED_FRENCH_SHIFT) & UCOL_PSK_USED_FRENCH_MASK;
   5416     // Number of bytes already written from a bocsu sequence. Since
   5417     // the longes bocsu sequence is 4 long, this can be up to 3.
   5418     int32_t bocsuBytesUsed = (state[1] >> UCOL_PSK_BOCSU_BYTES_SHIFT) & UCOL_PSK_BOCSU_BYTES_MASK;
   5419     // Number of elements that need to be consumed in this iteration because
   5420     // the iterator returned UITER_NO_STATE at the end of the last iteration,
   5421     // so we had to save the last valid state.
   5422     int32_t cces = (state[1] >> UCOL_PSK_CONSUMED_CES_SHIFT) & UCOL_PSK_CONSUMED_CES_MASK;
   5423 
   5424     /** values that depend on the collator attributes */
   5425     // strength of the collator.
   5426     int32_t strength = ucol_getAttribute(coll, UCOL_STRENGTH, status);
   5427     // maximal level of the partial sortkey. Need to take whether case level is done
   5428     int32_t maxLevel = 0;
   5429     if(strength < UCOL_TERTIARY) {
   5430         if(ucol_getAttribute(coll, UCOL_CASE_LEVEL, status) == UCOL_ON) {
   5431             maxLevel = UCOL_PSK_CASE;
   5432         } else {
   5433             maxLevel = strength;
   5434         }
   5435     } else {
   5436         if(strength == UCOL_TERTIARY) {
   5437             maxLevel = UCOL_PSK_TERTIARY;
   5438         } else if(strength == UCOL_QUATERNARY) {
   5439             maxLevel = UCOL_PSK_QUATERNARY;
   5440         } else { // identical
   5441             maxLevel = UCOL_IDENTICAL;
   5442         }
   5443     }
   5444     // value for the quaternary level if Hiragana is encountered. Used for JIS X 4061 collation
   5445     uint8_t UCOL_HIRAGANA_QUAD =
   5446       (ucol_getAttribute(coll, UCOL_HIRAGANA_QUATERNARY_MODE, status) == UCOL_ON)?0xFE:0xFF;
   5447     // Boundary value that decides whether a CE is shifted or not
   5448     uint32_t LVT = (coll->alternateHandling == UCOL_SHIFTED)?(coll->variableTopValue<<16):0;
   5449     // Are we doing French collation?
   5450     UBool doingFrench = (ucol_getAttribute(coll, UCOL_FRENCH_COLLATION, status) == UCOL_ON);
   5451 
   5452     /** initializing the collation state */
   5453     UBool notIsContinuation = FALSE;
   5454     uint32_t CE = UCOL_NO_MORE_CES;
   5455 
   5456     collIterate s;
   5457     IInit_collIterate(coll, NULL, -1, &s, status);
   5458     if(U_FAILURE(*status)) {
   5459         UTRACE_EXIT_STATUS(*status);
   5460         return 0;
   5461     }
   5462     s.iterator = iter;
   5463     s.flags |= UCOL_USE_ITERATOR;
   5464     // This variable tells us whether we have produced some other levels in this iteration
   5465     // before we moved to the identical level. In that case, we need to switch the
   5466     // type of the iterator.
   5467     UBool doingIdenticalFromStart = FALSE;
   5468     // Normalizing iterator
   5469     // The division for the array length may truncate the array size to
   5470     // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
   5471     // for all platforms anyway.
   5472     UAlignedMemory stackNormIter[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
   5473     UNormIterator *normIter = NULL;
   5474     // If the normalization is turned on for the collator and we are below identical level
   5475     // we will use a FCD normalizing iterator
   5476     if(ucol_getAttribute(coll, UCOL_NORMALIZATION_MODE, status) == UCOL_ON && level < UCOL_PSK_IDENTICAL) {
   5477         normIter = unorm_openIter(stackNormIter, sizeof(stackNormIter), status);
   5478         s.iterator = unorm_setIter(normIter, iter, UNORM_FCD, status);
   5479         s.flags &= ~UCOL_ITER_NORM;
   5480         if(U_FAILURE(*status)) {
   5481             UTRACE_EXIT_STATUS(*status);
   5482             return 0;
   5483         }
   5484     } else if(level == UCOL_PSK_IDENTICAL) {
   5485         // for identical level, we need a NFD iterator. We need to instantiate it here, since we
   5486         // will be updating the state - and this cannot be done on an ordinary iterator.
   5487         normIter = unorm_openIter(stackNormIter, sizeof(stackNormIter), status);
   5488         s.iterator = unorm_setIter(normIter, iter, UNORM_NFD, status);
   5489         s.flags &= ~UCOL_ITER_NORM;
   5490         if(U_FAILURE(*status)) {
   5491             UTRACE_EXIT_STATUS(*status);
   5492             return 0;
   5493         }
   5494         doingIdenticalFromStart = TRUE;
   5495     }
   5496 
   5497     // This is the tentative new state of the iterator. The problem
   5498     // is that the iterator might return an undefined state, in
   5499     // which case we should save the last valid state and increase
   5500     // the iterator skip value.
   5501     uint32_t newState = 0;
   5502 
   5503     // First, we set the iterator to the last valid position
   5504     // from the last iteration. This was saved in state[0].
   5505     if(iterState == 0) {
   5506         /* initial state */
   5507         if(level == UCOL_PSK_SECONDARY && doingFrench && !byteCountOrFrenchDone) {
   5508             s.iterator->move(s.iterator, 0, UITER_LIMIT);
   5509         } else {
   5510             s.iterator->move(s.iterator, 0, UITER_START);
   5511         }
   5512     } else {
   5513         /* reset to previous state */
   5514         s.iterator->setState(s.iterator, iterState, status);
   5515         if(U_FAILURE(*status)) {
   5516             UTRACE_EXIT_STATUS(*status);
   5517             return 0;
   5518         }
   5519     }
   5520 
   5521 
   5522 
   5523     // This variable tells us whether we can attempt to update the state
   5524     // of iterator. Situations where we don't want to update iterator state
   5525     // are the existence of expansion CEs that are not yet processed, and
   5526     // finishing the case level without enough space in the buffer to insert
   5527     // a level terminator.
   5528     UBool canUpdateState = TRUE;
   5529 
   5530     // Consume all the CEs that were consumed at the end of the previous
   5531     // iteration without updating the iterator state. On identical level,
   5532     // consume the code points.
   5533     int32_t counter = cces;
   5534     if(level < UCOL_PSK_IDENTICAL) {
   5535         while(counter-->0) {
   5536             // If we're doing French and we are on the secondary level,
   5537             // we go backwards.
   5538             if(level == UCOL_PSK_SECONDARY && doingFrench) {
   5539                 CE = ucol_IGetPrevCE(coll, &s, status);
   5540             } else {
   5541                 CE = ucol_IGetNextCE(coll, &s, status);
   5542             }
   5543             if(CE==UCOL_NO_MORE_CES) {
   5544                 /* should not happen */
   5545                 *status=U_INTERNAL_PROGRAM_ERROR;
   5546                 UTRACE_EXIT_STATUS(*status);
   5547                 return 0;
   5548             }
   5549             if(uprv_numAvailableExpCEs(s)) {
   5550                 canUpdateState = FALSE;
   5551             }
   5552         }
   5553     } else {
   5554         while(counter-->0) {
   5555             uiter_next32(s.iterator);
   5556         }
   5557     }
   5558 
   5559     // French secondary needs to know whether the iterator state of zero came from previous level OR
   5560     // from a new invocation...
   5561     UBool wasDoingPrimary = FALSE;
   5562     // destination buffer byte counter. When this guy
   5563     // gets to count, we're done with the iteration
   5564     int32_t i = 0;
   5565     // used to count the zero bytes written after we
   5566     // have finished with the sort key
   5567     int32_t j = 0;
   5568 
   5569 
   5570     // Hm.... I think we're ready to plunge in. Basic story is as following:
   5571     // we have a fall through case based on level. This is used for initial
   5572     // positioning on iteration start. Every level processor contains a
   5573     // for(;;) which will be broken when we exhaust all the CEs. Other
   5574     // way to exit is a goto saveState, which happens when we have filled
   5575     // out our buffer.
   5576     switch(level) {
   5577     case UCOL_PSK_PRIMARY:
   5578         wasDoingPrimary = TRUE;
   5579         for(;;) {
   5580             if(i==count) {
   5581                 goto saveState;
   5582             }
   5583             // We should save the state only if we
   5584             // are sure that we are done with the
   5585             // previous iterator state
   5586             if(canUpdateState && byteCountOrFrenchDone == 0) {
   5587                 newState = s.iterator->getState(s.iterator);
   5588                 if(newState != UITER_NO_STATE) {
   5589                     iterState = newState;
   5590                     cces = 0;
   5591                 }
   5592             }
   5593             CE = ucol_IGetNextCE(coll, &s, status);
   5594             cces++;
   5595             if(CE==UCOL_NO_MORE_CES) {
   5596                 // Add the level separator
   5597                 terminatePSKLevel(level, maxLevel, i, dest);
   5598                 byteCountOrFrenchDone=0;
   5599                 // Restart the iteration an move to the
   5600                 // second level
   5601                 s.iterator->move(s.iterator, 0, UITER_START);
   5602                 cces = 0;
   5603                 level = UCOL_PSK_SECONDARY;
   5604                 break;
   5605             }
   5606             if(!isContinuation(CE)){
   5607                 if(coll->leadBytePermutationTable != NULL){
   5608                     CE = (coll->leadBytePermutationTable[CE>>24] << 24) | (CE & 0x00FFFFFF);
   5609                 }
   5610             }
   5611             if(!isShiftedCE(CE, LVT, &wasShifted)) {
   5612                 CE >>= UCOL_PRIMARYORDERSHIFT; /* get primary */
   5613                 if(CE != 0) {
   5614                     if(byteCountOrFrenchDone == 0) {
   5615                         // get the second byte of primary
   5616                         dest[i++]=(uint8_t)(CE >> 8);
   5617                     } else {
   5618                         byteCountOrFrenchDone = 0;
   5619                     }
   5620                     if((CE &=0xff)!=0) {
   5621                         if(i==count) {
   5622                             /* overflow */
   5623                             byteCountOrFrenchDone = 1;
   5624                             cces--;
   5625                             goto saveState;
   5626                         }
   5627                         dest[i++]=(uint8_t)CE;
   5628                     }
   5629                 }
   5630             }
   5631             if(uprv_numAvailableExpCEs(s)) {
   5632                 canUpdateState = FALSE;
   5633             } else {
   5634                 canUpdateState = TRUE;
   5635             }
   5636         }
   5637         /* fall through to next level */
   5638     case UCOL_PSK_SECONDARY:
   5639         if(strength >= UCOL_SECONDARY) {
   5640             if(!doingFrench) {
   5641                 for(;;) {
   5642                     if(i == count) {
   5643                         goto saveState;
   5644                     }
   5645                     // We should save the state only if we
   5646                     // are sure that we are done with the
   5647                     // previous iterator state
   5648                     if(canUpdateState) {
   5649                         newState = s.iterator->getState(s.iterator);
   5650                         if(newState != UITER_NO_STATE) {
   5651                             iterState = newState;
   5652                             cces = 0;
   5653                         }
   5654                     }
   5655                     CE = ucol_IGetNextCE(coll, &s, status);
   5656                     cces++;
   5657                     if(CE==UCOL_NO_MORE_CES) {
   5658                         // Add the level separator
   5659                         terminatePSKLevel(level, maxLevel, i, dest);
   5660                         byteCountOrFrenchDone = 0;
   5661                         // Restart the iteration an move to the
   5662                         // second level
   5663                         s.iterator->move(s.iterator, 0, UITER_START);
   5664                         cces = 0;
   5665                         level = UCOL_PSK_CASE;
   5666                         break;
   5667                     }
   5668                     if(!isShiftedCE(CE, LVT, &wasShifted)) {
   5669                         CE >>= 8; /* get secondary */
   5670                         if(CE != 0) {
   5671                             dest[i++]=(uint8_t)CE;
   5672                         }
   5673                     }
   5674                     if(uprv_numAvailableExpCEs(s)) {
   5675                         canUpdateState = FALSE;
   5676                     } else {
   5677                         canUpdateState = TRUE;
   5678                     }
   5679                 }
   5680             } else { // French secondary processing
   5681                 uint8_t frenchBuff[UCOL_MAX_BUFFER];
   5682                 int32_t frenchIndex = 0;
   5683                 // Here we are going backwards.
   5684                 // If the iterator is at the beggining, it should be
   5685                 // moved to end.
   5686                 if(wasDoingPrimary) {
   5687                     s.iterator->move(s.iterator, 0, UITER_LIMIT);
   5688                     cces = 0;
   5689                 }
   5690                 for(;;) {
   5691                     if(i == count) {
   5692                         goto saveState;
   5693                     }
   5694                     if(canUpdateState) {
   5695                         newState = s.iterator->getState(s.iterator);
   5696                         if(newState != UITER_NO_STATE) {
   5697                             iterState = newState;
   5698                             cces = 0;
   5699                         }
   5700                     }
   5701                     CE = ucol_IGetPrevCE(coll, &s, status);
   5702                     cces++;
   5703                     if(CE==UCOL_NO_MORE_CES) {
   5704                         // Add the level separator
   5705                         terminatePSKLevel(level, maxLevel, i, dest);
   5706                         byteCountOrFrenchDone = 0;
   5707                         // Restart the iteration an move to the next level
   5708                         s.iterator->move(s.iterator, 0, UITER_START);
   5709                         level = UCOL_PSK_CASE;
   5710                         break;
   5711                     }
   5712                     if(isContinuation(CE)) { // if it's a continuation, we want to save it and
   5713                         // reverse when we get a first non-continuation CE.
   5714                         CE >>= 8;
   5715                         frenchBuff[frenchIndex++] = (uint8_t)CE;
   5716                     } else if(!isShiftedCE(CE, LVT, &wasShifted)) {
   5717                         CE >>= 8; /* get secondary */
   5718                         if(!frenchIndex) {
   5719                             if(CE != 0) {
   5720                                 dest[i++]=(uint8_t)CE;
   5721                             }
   5722                         } else {
   5723                             frenchBuff[frenchIndex++] = (uint8_t)CE;
   5724                             frenchIndex -= usedFrench;
   5725                             usedFrench = 0;
   5726                             while(i < count && frenchIndex) {
   5727                                 dest[i++] = frenchBuff[--frenchIndex];
   5728                                 usedFrench++;
   5729                             }
   5730                         }
   5731                     }
   5732                     if(uprv_numAvailableExpCEs(s)) {
   5733                         canUpdateState = FALSE;
   5734                     } else {
   5735                         canUpdateState = TRUE;
   5736                     }
   5737                 }
   5738             }
   5739         } else {
   5740             level = UCOL_PSK_CASE;
   5741         }
   5742         /* fall through to next level */
   5743     case UCOL_PSK_CASE:
   5744         if(ucol_getAttribute(coll, UCOL_CASE_LEVEL, status) == UCOL_ON) {
   5745             uint32_t caseShift = UCOL_CASE_SHIFT_START;
   5746             uint8_t caseByte = UCOL_CASE_BYTE_START;
   5747             uint8_t caseBits = 0;
   5748 
   5749             for(;;) {
   5750                 U_ASSERT(caseShift <= UCOL_CASE_SHIFT_START);
   5751                 if(i == count) {
   5752                     goto saveState;
   5753                 }
   5754                 // We should save the state only if we
   5755                 // are sure that we are done with the
   5756                 // previous iterator state
   5757                 if(canUpdateState) {
   5758                     newState = s.iterator->getState(s.iterator);
   5759                     if(newState != UITER_NO_STATE) {
   5760                         iterState = newState;
   5761                         cces = 0;
   5762                     }
   5763                 }
   5764                 CE = ucol_IGetNextCE(coll, &s, status);
   5765                 cces++;
   5766                 if(CE==UCOL_NO_MORE_CES) {
   5767                     // On the case level we might have an unfinished
   5768                     // case byte. Add one if it's started.
   5769                     if(caseShift != UCOL_CASE_SHIFT_START) {
   5770                         dest[i++] = caseByte;
   5771                     }
   5772                     cces = 0;
   5773                     // We have finished processing CEs on this level.
   5774                     // However, we don't know if we have enough space
   5775                     // to add a case level terminator.
   5776                     if(i < count) {
   5777                         // Add the level separator
   5778                         terminatePSKLevel(level, maxLevel, i, dest);
   5779                         // Restart the iteration and move to the
   5780                         // next level
   5781                         s.iterator->move(s.iterator, 0, UITER_START);
   5782                         level = UCOL_PSK_TERTIARY;
   5783                     } else {
   5784                         canUpdateState = FALSE;
   5785                     }
   5786                     break;
   5787                 }
   5788 
   5789                 if(!isShiftedCE(CE, LVT, &wasShifted)) {
   5790                     if(!isContinuation(CE) && ((CE & UCOL_PRIMARYMASK) != 0 || strength > UCOL_PRIMARY)) {
   5791                         // do the case level if we need to do it. We don't want to calculate
   5792                         // case level for primary ignorables if we have only primary strength and case level
   5793                         // otherwise we would break well formedness of CEs
   5794                         CE = (uint8_t)(CE & UCOL_BYTE_SIZE_MASK);
   5795                         caseBits = (uint8_t)(CE & 0xC0);
   5796                         // this copies the case level logic from the
   5797                         // sort key generation code
   5798                         if(CE != 0) {
   5799                             if (caseShift == 0) {
   5800                                 dest[i++] = caseByte;
   5801                                 caseShift = UCOL_CASE_SHIFT_START;
   5802                                 caseByte = UCOL_CASE_BYTE_START;
   5803                             }
   5804                             if(coll->caseFirst == UCOL_UPPER_FIRST) {
   5805                                 if((caseBits & 0xC0) == 0) {
   5806                                     caseByte |= 1 << (--caseShift);
   5807                                 } else {
   5808                                     caseByte |= 0 << (--caseShift);
   5809                                     /* second bit */
   5810                                     if(caseShift == 0) {
   5811                                         dest[i++] = caseByte;
   5812                                         caseShift = UCOL_CASE_SHIFT_START;
   5813                                         caseByte = UCOL_CASE_BYTE_START;
   5814                                     }
   5815                                     caseByte |= ((caseBits>>6)&1) << (--caseShift);
   5816                                 }
   5817                             } else {
   5818                                 if((caseBits & 0xC0) == 0) {
   5819                                     caseByte |= 0 << (--caseShift);
   5820                                 } else {
   5821                                     caseByte |= 1 << (--caseShift);
   5822                                     /* second bit */
   5823                                     if(caseShift == 0) {
   5824                                         dest[i++] = caseByte;
   5825                                         caseShift = UCOL_CASE_SHIFT_START;
   5826                                         caseByte = UCOL_CASE_BYTE_START;
   5827                                     }
   5828                                     caseByte |= ((caseBits>>7)&1) << (--caseShift);
   5829                                 }
   5830                             }
   5831                         }
   5832 
   5833                     }
   5834                 }
   5835                 // Not sure this is correct for the case level - revisit
   5836                 if(uprv_numAvailableExpCEs(s)) {
   5837                     canUpdateState = FALSE;
   5838                 } else {
   5839                     canUpdateState = TRUE;
   5840                 }
   5841             }
   5842         } else {
   5843             level = UCOL_PSK_TERTIARY;
   5844         }
   5845         /* fall through to next level */
   5846     case UCOL_PSK_TERTIARY:
   5847         if(strength >= UCOL_TERTIARY) {
   5848             for(;;) {
   5849                 if(i == count) {
   5850                     goto saveState;
   5851                 }
   5852                 // We should save the state only if we
   5853                 // are sure that we are done with the
   5854                 // previous iterator state
   5855                 if(canUpdateState) {
   5856                     newState = s.iterator->getState(s.iterator);
   5857                     if(newState != UITER_NO_STATE) {
   5858                         iterState = newState;
   5859                         cces = 0;
   5860                     }
   5861                 }
   5862                 CE = ucol_IGetNextCE(coll, &s, status);
   5863                 cces++;
   5864                 if(CE==UCOL_NO_MORE_CES) {
   5865                     // Add the level separator
   5866                     terminatePSKLevel(level, maxLevel, i, dest);
   5867                     byteCountOrFrenchDone = 0;
   5868                     // Restart the iteration an move to the
   5869                     // second level
   5870                     s.iterator->move(s.iterator, 0, UITER_START);
   5871                     cces = 0;
   5872                     level = UCOL_PSK_QUATERNARY;
   5873                     break;
   5874                 }
   5875                 if(!isShiftedCE(CE, LVT, &wasShifted)) {
   5876                     notIsContinuation = !isContinuation(CE);
   5877 
   5878                     if(notIsContinuation) {
   5879                         CE = (uint8_t)(CE & UCOL_BYTE_SIZE_MASK);
   5880                         CE ^= coll->caseSwitch;
   5881                         CE &= coll->tertiaryMask;
   5882                     } else {
   5883                         CE = (uint8_t)((CE & UCOL_REMOVE_CONTINUATION));
   5884                     }
   5885 
   5886                     if(CE != 0) {
   5887                         dest[i++]=(uint8_t)CE;
   5888                     }
   5889                 }
   5890                 if(uprv_numAvailableExpCEs(s)) {
   5891                     canUpdateState = FALSE;
   5892                 } else {
   5893                     canUpdateState = TRUE;
   5894                 }
   5895             }
   5896         } else {
   5897             // if we're not doing tertiary
   5898             // skip to the end
   5899             level = UCOL_PSK_NULL;
   5900         }
   5901         /* fall through to next level */
   5902     case UCOL_PSK_QUATERNARY:
   5903         if(strength >= UCOL_QUATERNARY) {
   5904             for(;;) {
   5905                 if(i == count) {
   5906                     goto saveState;
   5907                 }
   5908                 // We should save the state only if we
   5909                 // are sure that we are done with the
   5910                 // previous iterator state
   5911                 if(canUpdateState) {
   5912                     newState = s.iterator->getState(s.iterator);
   5913                     if(newState != UITER_NO_STATE) {
   5914                         iterState = newState;
   5915                         cces = 0;
   5916                     }
   5917                 }
   5918                 CE = ucol_IGetNextCE(coll, &s, status);
   5919                 cces++;
   5920                 if(CE==UCOL_NO_MORE_CES) {
   5921                     // Add the level separator
   5922                     terminatePSKLevel(level, maxLevel, i, dest);
   5923                     //dest[i++] = UCOL_LEVELTERMINATOR;
   5924                     byteCountOrFrenchDone = 0;
   5925                     // Restart the iteration an move to the
   5926                     // second level
   5927                     s.iterator->move(s.iterator, 0, UITER_START);
   5928                     cces = 0;
   5929                     level = UCOL_PSK_QUIN;
   5930                     break;
   5931                 }
   5932                 if(CE==0)
   5933                     continue;
   5934                 if(isShiftedCE(CE, LVT, &wasShifted)) {
   5935                     CE >>= 16; /* get primary */
   5936                     if(CE != 0) {
   5937                         if(byteCountOrFrenchDone == 0) {
   5938                             dest[i++]=(uint8_t)(CE >> 8);
   5939                         } else {
   5940                             byteCountOrFrenchDone = 0;
   5941                         }
   5942                         if((CE &=0xff)!=0) {
   5943                             if(i==count) {
   5944                                 /* overflow */
   5945                                 byteCountOrFrenchDone = 1;
   5946                                 goto saveState;
   5947                             }
   5948                             dest[i++]=(uint8_t)CE;
   5949                         }
   5950                     }
   5951                 } else {
   5952                     notIsContinuation = !isContinuation(CE);
   5953                     if(notIsContinuation) {
   5954                         if(s.flags & UCOL_WAS_HIRAGANA) { // This was Hiragana and we need to note it
   5955                             dest[i++] = UCOL_HIRAGANA_QUAD;
   5956                         } else {
   5957                             dest[i++] = 0xFF;
   5958                         }
   5959                     }
   5960                 }
   5961                 if(uprv_numAvailableExpCEs(s)) {
   5962                     canUpdateState = FALSE;
   5963                 } else {
   5964                     canUpdateState = TRUE;
   5965                 }
   5966             }
   5967         } else {
   5968             // if we're not doing quaternary
   5969             // skip to the end
   5970             level = UCOL_PSK_NULL;
   5971         }
   5972         /* fall through to next level */
   5973     case UCOL_PSK_QUIN:
   5974         level = UCOL_PSK_IDENTICAL;
   5975         /* fall through to next level */
   5976     case UCOL_PSK_IDENTICAL:
   5977         if(strength >= UCOL_IDENTICAL) {
   5978             UChar32 first, second;
   5979             int32_t bocsuBytesWritten = 0;
   5980             // We always need to do identical on
   5981             // the NFD form of the string.
   5982             if(normIter == NULL) {
   5983                 // we arrived from the level below and
   5984                 // normalization was not turned on.
   5985                 // therefore, we need to make a fresh NFD iterator
   5986                 normIter = unorm_openIter(stackNormIter, sizeof(stackNormIter), status);
   5987                 s.iterator = unorm_setIter(normIter, iter, UNORM_NFD, status);
   5988             } else if(!doingIdenticalFromStart) {
   5989                 // there is an iterator, but we did some other levels.
   5990                 // therefore, we have a FCD iterator - need to make
   5991                 // a NFD one.
   5992                 // normIter being at the beginning does not guarantee
   5993                 // that the underlying iterator is at the beginning
   5994                 iter->move(iter, 0, UITER_START);
   5995                 s.iterator = unorm_setIter(normIter, iter, UNORM_NFD, status);
   5996             }
   5997             // At this point we have a NFD iterator that is positioned
   5998             // in the right place
   5999             if(U_FAILURE(*status)) {
   6000                 UTRACE_EXIT_STATUS(*status);
   6001                 return 0;
   6002             }
   6003             first = uiter_previous32(s.iterator);
   6004             // maybe we're at the start of the string
   6005             if(first == U_SENTINEL) {
   6006                 first = 0;
   6007             } else {
   6008                 uiter_next32(s.iterator);
   6009             }
   6010 
   6011             j = 0;
   6012             for(;;) {
   6013                 if(i == count) {
   6014                     if(j+1 < bocsuBytesWritten) {
   6015                         bocsuBytesUsed = j+1;
   6016                     }
   6017                     goto saveState;
   6018                 }
   6019 
   6020                 // On identical level, we will always save
   6021                 // the state if we reach this point, since
   6022                 // we don't depend on getNextCE for content
   6023                 // all the content is in our buffer and we
   6024                 // already either stored the full buffer OR
   6025                 // otherwise we won't arrive here.
   6026                 newState = s.iterator->getState(s.iterator);
   6027                 if(newState != UITER_NO_STATE) {
   6028                     iterState = newState;
   6029                     cces = 0;
   6030                 }
   6031 
   6032                 uint8_t buff[4];
   6033                 second = uiter_next32(s.iterator);
   6034                 cces++;
   6035 
   6036                 // end condition for identical level
   6037                 if(second == U_SENTINEL) {
   6038                     terminatePSKLevel(level, maxLevel, i, dest);
   6039                     level = UCOL_PSK_NULL;
   6040                     break;
   6041                 }
   6042                 bocsuBytesWritten = u_writeIdenticalLevelRunTwoChars(first, second, buff);
   6043                 first = second;
   6044 
   6045                 j = 0;
   6046                 if(bocsuBytesUsed != 0) {
   6047                     while(bocsuBytesUsed-->0) {
   6048                         j++;
   6049                     }
   6050                 }
   6051 
   6052                 while(i < count && j < bocsuBytesWritten) {
   6053                     dest[i++] = buff[j++];
   6054                 }
   6055             }
   6056 
   6057         } else {
   6058             level = UCOL_PSK_NULL;
   6059         }
   6060         /* fall through to next level */
   6061     case UCOL_PSK_NULL:
   6062         j = i;
   6063         while(j<count) {
   6064             dest[j++]=0;
   6065         }
   6066         break;
   6067     default:
   6068         *status = U_INTERNAL_PROGRAM_ERROR;
   6069         UTRACE_EXIT_STATUS(*status);
   6070         return 0;
   6071     }
   6072 
   6073 saveState:
   6074     // Now we need to return stuff. First we want to see whether we have
   6075     // done everything for the current state of iterator.
   6076     if(byteCountOrFrenchDone
   6077         || canUpdateState == FALSE
   6078         || (newState = s.iterator->getState(s.iterator)) == UITER_NO_STATE)
   6079     {
   6080         // Any of above mean that the previous transaction
   6081         // wasn't finished and that we should store the
   6082         // previous iterator state.
   6083         state[0] = iterState;
   6084     } else {
   6085         // The transaction is complete. We will continue in the next iteration.
   6086         state[0] = s.iterator->getState(s.iterator);
   6087         cces = 0;
   6088     }
   6089     // Store the number of bocsu bytes written.
   6090     if((bocsuBytesUsed & UCOL_PSK_BOCSU_BYTES_MASK) != bocsuBytesUsed) {
   6091         *status = U_INDEX_OUTOFBOUNDS_ERROR;
   6092     }
   6093     state[1] = (bocsuBytesUsed & UCOL_PSK_BOCSU_BYTES_MASK) << UCOL_PSK_BOCSU_BYTES_SHIFT;
   6094 
   6095     // Next we put in the level of comparison
   6096     state[1] |= ((level & UCOL_PSK_LEVEL_MASK) << UCOL_PSK_LEVEL_SHIFT);
   6097 
   6098     // If we are doing French, we need to store whether we have just finished the French level
   6099     if(level == UCOL_PSK_SECONDARY && doingFrench) {
   6100         state[1] |= (((int32_t)(state[0] == 0) & UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK) << UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT);
   6101     } else {
   6102         state[1] |= ((byteCountOrFrenchDone & UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK) << UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT);
   6103     }
   6104 
   6105     // Was the latest CE shifted
   6106     if(wasShifted) {
   6107         state[1] |= 1 << UCOL_PSK_WAS_SHIFTED_SHIFT;
   6108     }
   6109     // Check for cces overflow
   6110     if((cces & UCOL_PSK_CONSUMED_CES_MASK) != cces) {
   6111         *status = U_INDEX_OUTOFBOUNDS_ERROR;
   6112     }
   6113     // Store cces
   6114     state[1] |= ((cces & UCOL_PSK_CONSUMED_CES_MASK) << UCOL_PSK_CONSUMED_CES_SHIFT);
   6115 
   6116     // Check for French overflow
   6117     if((usedFrench & UCOL_PSK_USED_FRENCH_MASK) != usedFrench) {
   6118         *status = U_INDEX_OUTOFBOUNDS_ERROR;
   6119     }
   6120     // Store number of bytes written in the French secondary continuation sequence
   6121     state[1] |= ((usedFrench & UCOL_PSK_USED_FRENCH_MASK) << UCOL_PSK_USED_FRENCH_SHIFT);
   6122 
   6123 
   6124     // If we have used normalizing iterator, get rid of it
   6125     if(normIter != NULL) {
   6126         unorm_closeIter(normIter);
   6127     }
   6128 
   6129     /* To avoid memory leak, free the offset buffer if necessary. */
   6130     ucol_freeOffsetBuffer(&s);
   6131 
   6132     // Return number of meaningful sortkey bytes.
   6133     UTRACE_DATA4(UTRACE_VERBOSE, "dest = %vb, state=%d %d",
   6134                   dest,i, state[0], state[1]);
   6135     UTRACE_EXIT_VALUE(i);
   6136     return i;
   6137 }
   6138 
   6139 /**
   6140  * Produce a bound for a given sortkey and a number of levels.
   6141  */
   6142 U_CAPI int32_t U_EXPORT2
   6143 ucol_getBound(const uint8_t       *source,
   6144         int32_t             sourceLength,
   6145         UColBoundMode       boundType,
   6146         uint32_t            noOfLevels,
   6147         uint8_t             *result,
   6148         int32_t             resultLength,
   6149         UErrorCode          *status)
   6150 {
   6151     // consistency checks
   6152     if(status == NULL || U_FAILURE(*status)) {
   6153         return 0;
   6154     }
   6155     if(source == NULL) {
   6156         *status = U_ILLEGAL_ARGUMENT_ERROR;
   6157         return 0;
   6158     }
   6159 
   6160     int32_t sourceIndex = 0;
   6161     // Scan the string until we skip enough of the key OR reach the end of the key
   6162     do {
   6163         sourceIndex++;
   6164         if(source[sourceIndex] == UCOL_LEVELTERMINATOR) {
   6165             noOfLevels--;
   6166         }
   6167     } while (noOfLevels > 0
   6168         && (source[sourceIndex] != 0 || sourceIndex < sourceLength));
   6169 
   6170     if((source[sourceIndex] == 0 || sourceIndex == sourceLength)
   6171         && noOfLevels > 0) {
   6172             *status = U_SORT_KEY_TOO_SHORT_WARNING;
   6173     }
   6174 
   6175 
   6176     // READ ME: this code assumes that the values for boundType
   6177     // enum will not changes. They are set so that the enum value
   6178     // corresponds to the number of extra bytes each bound type
   6179     // needs.
   6180     if(result != NULL && resultLength >= sourceIndex+boundType) {
   6181         uprv_memcpy(result, source, sourceIndex);
   6182         switch(boundType) {
   6183             // Lower bound just gets terminated. No extra bytes
   6184         case UCOL_BOUND_LOWER: // = 0
   6185             break;
   6186             // Upper bound needs one extra byte
   6187         case UCOL_BOUND_UPPER: // = 1
   6188             result[sourceIndex++] = 2;
   6189             break;
   6190             // Upper long bound needs two extra bytes
   6191         case UCOL_BOUND_UPPER_LONG: // = 2
   6192             result[sourceIndex++] = 0xFF;
   6193             result[sourceIndex++] = 0xFF;
   6194             break;
   6195         default:
   6196             *status = U_ILLEGAL_ARGUMENT_ERROR;
   6197             return 0;
   6198         }
   6199         result[sourceIndex++] = 0;
   6200 
   6201         return sourceIndex;
   6202     } else {
   6203         return sourceIndex+boundType+1;
   6204     }
   6205 }
   6206 
   6207 /****************************************************************************/
   6208 /* Following are the functions that deal with the properties of a collator  */
   6209 /* there are new APIs and some compatibility APIs                           */
   6210 /****************************************************************************/
   6211 
   6212 static inline void
   6213 ucol_addLatinOneEntry(UCollator *coll, UChar ch, uint32_t CE,
   6214                     int32_t *primShift, int32_t *secShift, int32_t *terShift)
   6215 {
   6216     uint8_t primary1 = 0, primary2 = 0, secondary = 0, tertiary = 0;
   6217     UBool reverseSecondary = FALSE;
   6218     UBool continuation = isContinuation(CE);
   6219     if(!continuation) {
   6220         tertiary = (uint8_t)((CE & coll->tertiaryMask));
   6221         tertiary ^= coll->caseSwitch;
   6222         reverseSecondary = TRUE;
   6223     } else {
   6224         tertiary = (uint8_t)((CE & UCOL_REMOVE_CONTINUATION));
   6225         tertiary &= UCOL_REMOVE_CASE;
   6226         reverseSecondary = FALSE;
   6227     }
   6228 
   6229     secondary = (uint8_t)((CE >>= 8) & UCOL_BYTE_SIZE_MASK);
   6230     primary2 = (uint8_t)((CE >>= 8) & UCOL_BYTE_SIZE_MASK);
   6231     primary1 = (uint8_t)(CE >> 8);
   6232 
   6233     if(primary1 != 0) {
   6234         if (coll->leadBytePermutationTable != NULL && !continuation) {
   6235             primary1 = coll->leadBytePermutationTable[primary1];
   6236         }
   6237 
   6238         coll->latinOneCEs[ch] |= (primary1 << *primShift);
   6239         *primShift -= 8;
   6240     }
   6241     if(primary2 != 0) {
   6242         if(*primShift < 0) {
   6243             coll->latinOneCEs[ch] = UCOL_BAIL_OUT_CE;
   6244             coll->latinOneCEs[coll->latinOneTableLen+ch] = UCOL_BAIL_OUT_CE;
   6245             coll->latinOneCEs[2*coll->latinOneTableLen+ch] = UCOL_BAIL_OUT_CE;
   6246             return;
   6247         }
   6248         coll->latinOneCEs[ch] |= (primary2 << *primShift);
   6249         *primShift -= 8;
   6250     }
   6251     if(secondary != 0) {
   6252         if(reverseSecondary && coll->frenchCollation == UCOL_ON) { // reverse secondary
   6253             coll->latinOneCEs[coll->latinOneTableLen+ch] >>= 8; // make space for secondary
   6254             coll->latinOneCEs[coll->latinOneTableLen+ch] |= (secondary << 24);
   6255         } else { // normal case
   6256             coll->latinOneCEs[coll->latinOneTableLen+ch] |= (secondary << *secShift);
   6257         }
   6258         *secShift -= 8;
   6259     }
   6260     if(tertiary != 0) {
   6261         coll->latinOneCEs[2*coll->latinOneTableLen+ch] |= (tertiary << *terShift);
   6262         *terShift -= 8;
   6263     }
   6264 }
   6265 
   6266 static inline UBool
   6267 ucol_resizeLatinOneTable(UCollator *coll, int32_t size, UErrorCode *status) {
   6268     uint32_t *newTable = (uint32_t *)uprv_malloc(size*sizeof(uint32_t)*3);
   6269     if(newTable == NULL) {
   6270       *status = U_MEMORY_ALLOCATION_ERROR;
   6271       coll->latinOneFailed = TRUE;
   6272       return FALSE;
   6273     }
   6274     int32_t sizeToCopy = ((size<coll->latinOneTableLen)?size:coll->latinOneTableLen)*sizeof(uint32_t);
   6275     uprv_memset(newTable, 0, size*sizeof(uint32_t)*3);
   6276     uprv_memcpy(newTable, coll->latinOneCEs, sizeToCopy);
   6277     uprv_memcpy(newTable+size, coll->latinOneCEs+coll->latinOneTableLen, sizeToCopy);
   6278     uprv_memcpy(newTable+2*size, coll->latinOneCEs+2*coll->latinOneTableLen, sizeToCopy);
   6279     coll->latinOneTableLen = size;
   6280     uprv_free(coll->latinOneCEs);
   6281     coll->latinOneCEs = newTable;
   6282     return TRUE;
   6283 }
   6284 
   6285 static UBool
   6286 ucol_setUpLatinOne(UCollator *coll, UErrorCode *status) {
   6287     UBool result = TRUE;
   6288     if(coll->latinOneCEs == NULL) {
   6289         coll->latinOneCEs = (uint32_t *)uprv_malloc(sizeof(uint32_t)*UCOL_LATINONETABLELEN*3);
   6290         if(coll->latinOneCEs == NULL) {
   6291             *status = U_MEMORY_ALLOCATION_ERROR;
   6292             return FALSE;
   6293         }
   6294         coll->latinOneTableLen = UCOL_LATINONETABLELEN;
   6295     }
   6296     UChar ch = 0;
   6297     UCollationElements *it = ucol_openElements(coll, &ch, 1, status);
   6298     // Check for null pointer
   6299     if (U_FAILURE(*status)) {
   6300         ucol_closeElements(it);
   6301         return FALSE;
   6302     }
   6303     uprv_memset(coll->latinOneCEs, 0, sizeof(uint32_t)*coll->latinOneTableLen*3);
   6304 
   6305     int32_t primShift = 24, secShift = 24, terShift = 24;
   6306     uint32_t CE = 0;
   6307     int32_t contractionOffset = UCOL_ENDOFLATINONERANGE+1;
   6308 
   6309     // TODO: make safe if you get more than you wanted...
   6310     for(ch = 0; ch <= UCOL_ENDOFLATINONERANGE; ch++) {
   6311         primShift = 24; secShift = 24; terShift = 24;
   6312         if(ch < 0x100) {
   6313             CE = coll->latinOneMapping[ch];
   6314         } else {
   6315             CE = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
   6316             if(CE == UCOL_NOT_FOUND && coll->UCA) {
   6317                 CE = UTRIE_GET32_FROM_LEAD(&coll->UCA->mapping, ch);
   6318             }
   6319         }
   6320         if(CE < UCOL_NOT_FOUND) {
   6321             ucol_addLatinOneEntry(coll, ch, CE, &primShift, &secShift, &terShift);
   6322         } else {
   6323             switch (getCETag(CE)) {
   6324             case EXPANSION_TAG:
   6325             case DIGIT_TAG:
   6326                 ucol_setText(it, &ch, 1, status);
   6327                 while((int32_t)(CE = ucol_next(it, status)) != UCOL_NULLORDER) {
   6328                     if(primShift < 0 || secShift < 0 || terShift < 0) {
   6329                         coll->latinOneCEs[ch] = UCOL_BAIL_OUT_CE;
   6330                         coll->latinOneCEs[coll->latinOneTableLen+ch] = UCOL_BAIL_OUT_CE;
   6331                         coll->latinOneCEs[2*coll->latinOneTableLen+ch] = UCOL_BAIL_OUT_CE;
   6332                         break;
   6333                     }
   6334                     ucol_addLatinOneEntry(coll, ch, CE, &primShift, &secShift, &terShift);
   6335                 }
   6336                 break;
   6337             case CONTRACTION_TAG:
   6338                 // here is the trick
   6339                 // F2 is contraction. We do something very similar to contractions
   6340                 // but have two indices, one in the real contraction table and the
   6341                 // other to where we stuffed things. This hopes that we don't have
   6342                 // many contractions (this should work for latin-1 tables).
   6343                 {
   6344                     if((CE & 0x00FFF000) != 0) {
   6345                         *status = U_UNSUPPORTED_ERROR;
   6346                         goto cleanup_after_failure;
   6347                     }
   6348 
   6349                     const UChar *UCharOffset = (UChar *)coll->image+getContractOffset(CE);
   6350 
   6351                     CE |= (contractionOffset & 0xFFF) << 12; // insert the offset in latin-1 table
   6352 
   6353                     coll->latinOneCEs[ch] = CE;
   6354                     coll->latinOneCEs[coll->latinOneTableLen+ch] = CE;
   6355                     coll->latinOneCEs[2*coll->latinOneTableLen+ch] = CE;
   6356 
   6357                     // We're going to jump into contraction table, pick the elements
   6358                     // and use them
   6359                     do {
   6360                         CE = *(coll->contractionCEs +
   6361                             (UCharOffset - coll->contractionIndex));
   6362                         if(CE > UCOL_NOT_FOUND && getCETag(CE) == EXPANSION_TAG) {
   6363                             uint32_t size;
   6364                             uint32_t i;    /* general counter */
   6365                             uint32_t *CEOffset = (uint32_t *)coll->image+getExpansionOffset(CE); /* find the offset to expansion table */
   6366                             size = getExpansionCount(CE);
   6367                             //CE = *CEOffset++;
   6368                             if(size != 0) { /* if there are less than 16 elements in expansion, we don't terminate */
   6369                                 for(i = 0; i<size; i++) {
   6370                                     if(primShift < 0 || secShift < 0 || terShift < 0) {
   6371                                         coll->latinOneCEs[(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
   6372                                         coll->latinOneCEs[coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
   6373                                         coll->latinOneCEs[2*coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
   6374                                         break;
   6375                                     }
   6376                                     ucol_addLatinOneEntry(coll, (UChar)contractionOffset, *CEOffset++, &primShift, &secShift, &terShift);
   6377                                 }
   6378                             } else { /* else, we do */
   6379                                 while(*CEOffset != 0) {
   6380                                     if(primShift < 0 || secShift < 0 || terShift < 0) {
   6381                                         coll->latinOneCEs[(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
   6382                                         coll->latinOneCEs[coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
   6383                                         coll->latinOneCEs[2*coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
   6384                                         break;
   6385                                     }
   6386                                     ucol_addLatinOneEntry(coll, (UChar)contractionOffset, *CEOffset++, &primShift, &secShift, &terShift);
   6387                                 }
   6388                             }
   6389                             contractionOffset++;
   6390                         } else if(CE < UCOL_NOT_FOUND) {
   6391                             ucol_addLatinOneEntry(coll, (UChar)contractionOffset++, CE, &primShift, &secShift, &terShift);
   6392                         } else {
   6393                             coll->latinOneCEs[(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
   6394                             coll->latinOneCEs[coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
   6395                             coll->latinOneCEs[2*coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
   6396                             contractionOffset++;
   6397                         }
   6398                         UCharOffset++;
   6399                         primShift = 24; secShift = 24; terShift = 24;
   6400                         if(contractionOffset == coll->latinOneTableLen) { // we need to reallocate
   6401                             if(!ucol_resizeLatinOneTable(coll, 2*coll->latinOneTableLen, status)) {
   6402                                 goto cleanup_after_failure;
   6403                             }
   6404                         }
   6405                     } while(*UCharOffset != 0xFFFF);
   6406                 }
   6407                 break;;
   6408             case SPEC_PROC_TAG:
   6409                 {
   6410                     // 0xB7 is a precontext character defined in UCA5.1, a special
   6411                     // handle is implemeted in order to save LatinOne table for
   6412                     // most locales.
   6413                     if (ch==0xb7) {
   6414                         ucol_addLatinOneEntry(coll, ch, CE, &primShift, &secShift, &terShift);
   6415                     }
   6416                     else {
   6417                         goto cleanup_after_failure;
   6418                     }
   6419                 }
   6420                 break;
   6421             default:
   6422                 goto cleanup_after_failure;
   6423             }
   6424         }
   6425     }
   6426     // compact table
   6427     if(contractionOffset < coll->latinOneTableLen) {
   6428         if(!ucol_resizeLatinOneTable(coll, contractionOffset, status)) {
   6429             goto cleanup_after_failure;
   6430         }
   6431     }
   6432     ucol_closeElements(it);
   6433     return result;
   6434 
   6435 cleanup_after_failure:
   6436     // status should already be set before arriving here.
   6437     coll->latinOneFailed = TRUE;
   6438     ucol_closeElements(it);
   6439     return FALSE;
   6440 }
   6441 
   6442 void ucol_updateInternalState(UCollator *coll, UErrorCode *status) {
   6443     if(U_SUCCESS(*status)) {
   6444         if(coll->caseFirst == UCOL_UPPER_FIRST) {
   6445             coll->caseSwitch = UCOL_CASE_SWITCH;
   6446         } else {
   6447             coll->caseSwitch = UCOL_NO_CASE_SWITCH;
   6448         }
   6449 
   6450         if(coll->caseLevel == UCOL_ON || coll->caseFirst == UCOL_OFF) {
   6451             coll->tertiaryMask = UCOL_REMOVE_CASE;
   6452             coll->tertiaryCommon = UCOL_COMMON3_NORMAL;
   6453             coll->tertiaryAddition = (int8_t)UCOL_FLAG_BIT_MASK_CASE_SW_OFF; /* Should be 0x80 */
   6454             coll->tertiaryTop = UCOL_COMMON_TOP3_CASE_SW_OFF;
   6455             coll->tertiaryBottom = UCOL_COMMON_BOT3;
   6456         } else {
   6457             coll->tertiaryMask = UCOL_KEEP_CASE;
   6458             coll->tertiaryAddition = UCOL_FLAG_BIT_MASK_CASE_SW_ON;
   6459             if(coll->caseFirst == UCOL_UPPER_FIRST) {
   6460                 coll->tertiaryCommon = UCOL_COMMON3_UPPERFIRST;
   6461                 coll->tertiaryTop = UCOL_COMMON_TOP3_CASE_SW_UPPER;
   6462                 coll->tertiaryBottom = UCOL_COMMON_BOTTOM3_CASE_SW_UPPER;
   6463             } else {
   6464                 coll->tertiaryCommon = UCOL_COMMON3_NORMAL;
   6465                 coll->tertiaryTop = UCOL_COMMON_TOP3_CASE_SW_LOWER;
   6466                 coll->tertiaryBottom = UCOL_COMMON_BOTTOM3_CASE_SW_LOWER;
   6467             }
   6468         }
   6469 
   6470         /* Set the compression values */
   6471         uint8_t tertiaryTotal = (uint8_t)(coll->tertiaryTop - coll->tertiaryBottom - 1);
   6472         coll->tertiaryTopCount = (uint8_t)(UCOL_PROPORTION3*tertiaryTotal); /* we multilply double with int, but need only int */
   6473         coll->tertiaryBottomCount = (uint8_t)(tertiaryTotal - coll->tertiaryTopCount);
   6474 
   6475         if(coll->caseLevel == UCOL_OFF && coll->strength == UCOL_TERTIARY
   6476             && coll->frenchCollation == UCOL_OFF && coll->alternateHandling == UCOL_NON_IGNORABLE)
   6477         {
   6478             coll->sortKeyGen = ucol_calcSortKeySimpleTertiary;
   6479         } else {
   6480             coll->sortKeyGen = ucol_calcSortKey;
   6481         }
   6482         if(coll->caseLevel == UCOL_OFF && coll->strength <= UCOL_TERTIARY && coll->numericCollation == UCOL_OFF
   6483             && coll->alternateHandling == UCOL_NON_IGNORABLE && !coll->latinOneFailed)
   6484         {
   6485             if(coll->latinOneCEs == NULL || coll->latinOneRegenTable) {
   6486                 if(ucol_setUpLatinOne(coll, status)) { // if we succeed in building latin1 table, we'll use it
   6487                     //fprintf(stderr, "F");
   6488                     coll->latinOneUse = TRUE;
   6489                 } else {
   6490                     coll->latinOneUse = FALSE;
   6491                 }
   6492                 if(*status == U_UNSUPPORTED_ERROR) {
   6493                     *status = U_ZERO_ERROR;
   6494                 }
   6495             } else { // latin1Table exists and it doesn't need to be regenerated, just use it
   6496                 coll->latinOneUse = TRUE;
   6497             }
   6498         } else {
   6499             coll->latinOneUse = FALSE;
   6500         }
   6501     }
   6502 }
   6503 
   6504 U_CAPI uint32_t  U_EXPORT2
   6505 ucol_setVariableTop(UCollator *coll, const UChar *varTop, int32_t len, UErrorCode *status) {
   6506     if(U_FAILURE(*status) || coll == NULL) {
   6507         return 0;
   6508     }
   6509     if(len == -1) {
   6510         len = u_strlen(varTop);
   6511     }
   6512     if(len == 0) {
   6513         *status = U_ILLEGAL_ARGUMENT_ERROR;
   6514         return 0;
   6515     }
   6516 
   6517     if(coll->delegate!=NULL) {
   6518       return ((Collator*)coll->delegate)->setVariableTop(varTop, len, *status);
   6519     }
   6520 
   6521 
   6522     collIterate s;
   6523     IInit_collIterate(coll, varTop, len, &s, status);
   6524     if(U_FAILURE(*status)) {
   6525         return 0;
   6526     }
   6527 
   6528     uint32_t CE = ucol_IGetNextCE(coll, &s, status);
   6529 
   6530     /* here we check if we have consumed all characters */
   6531     /* you can put in either one character or a contraction */
   6532     /* you shouldn't put more... */
   6533     if(s.pos != s.endp || CE == UCOL_NO_MORE_CES) {
   6534         *status = U_CE_NOT_FOUND_ERROR;
   6535         return 0;
   6536     }
   6537 
   6538     uint32_t nextCE = ucol_IGetNextCE(coll, &s, status);
   6539 
   6540     if(isContinuation(nextCE) && (nextCE & UCOL_PRIMARYMASK) != 0) {
   6541         *status = U_PRIMARY_TOO_LONG_ERROR;
   6542         return 0;
   6543     }
   6544     if(coll->variableTopValue != (CE & UCOL_PRIMARYMASK)>>16) {
   6545         coll->variableTopValueisDefault = FALSE;
   6546         coll->variableTopValue = (CE & UCOL_PRIMARYMASK)>>16;
   6547     }
   6548 
   6549     /* To avoid memory leak, free the offset buffer if necessary. */
   6550     ucol_freeOffsetBuffer(&s);
   6551 
   6552     return CE & UCOL_PRIMARYMASK;
   6553 }
   6554 
   6555 U_CAPI uint32_t U_EXPORT2 ucol_getVariableTop(const UCollator *coll, UErrorCode *status) {
   6556     if(U_FAILURE(*status) || coll == NULL) {
   6557         return 0;
   6558     }
   6559     if(coll->delegate!=NULL) {
   6560       return ((const Collator*)coll->delegate)->getVariableTop(*status);
   6561     }
   6562     return coll->variableTopValue<<16;
   6563 }
   6564 
   6565 U_CAPI void  U_EXPORT2
   6566 ucol_restoreVariableTop(UCollator *coll, const uint32_t varTop, UErrorCode *status) {
   6567     if(U_FAILURE(*status) || coll == NULL) {
   6568         return;
   6569     }
   6570 
   6571     if(coll->variableTopValue != (varTop & UCOL_PRIMARYMASK)>>16) {
   6572         coll->variableTopValueisDefault = FALSE;
   6573         coll->variableTopValue = (varTop & UCOL_PRIMARYMASK)>>16;
   6574     }
   6575 }
   6576 /* Attribute setter API */
   6577 U_CAPI void  U_EXPORT2
   6578 ucol_setAttribute(UCollator *coll, UColAttribute attr, UColAttributeValue value, UErrorCode *status) {
   6579     if(U_FAILURE(*status) || coll == NULL) {
   6580       return;
   6581     }
   6582 
   6583     if(coll->delegate != NULL) {
   6584       ((Collator*)coll->delegate)->setAttribute(attr,value,*status);
   6585       return;
   6586     }
   6587 
   6588     UColAttributeValue oldFrench = coll->frenchCollation;
   6589     UColAttributeValue oldCaseFirst = coll->caseFirst;
   6590     switch(attr) {
   6591     case UCOL_NUMERIC_COLLATION: /* sort substrings of digits as numbers */
   6592         if(value == UCOL_ON) {
   6593             coll->numericCollation = UCOL_ON;
   6594             coll->numericCollationisDefault = FALSE;
   6595         } else if (value == UCOL_OFF) {
   6596             coll->numericCollation = UCOL_OFF;
   6597             coll->numericCollationisDefault = FALSE;
   6598         } else if (value == UCOL_DEFAULT) {
   6599             coll->numericCollationisDefault = TRUE;
   6600             coll->numericCollation = (UColAttributeValue)coll->options->numericCollation;
   6601         } else {
   6602             *status = U_ILLEGAL_ARGUMENT_ERROR;
   6603         }
   6604         break;
   6605     case UCOL_HIRAGANA_QUATERNARY_MODE: /* special quaternary values for Hiragana */
   6606         if(value == UCOL_ON || value == UCOL_OFF || value == UCOL_DEFAULT) {
   6607             // This attribute is an implementation detail of the CLDR Japanese tailoring.
   6608             // The implementation might change to use a different mechanism
   6609             // to achieve the same Japanese sort order.
   6610             // Since ICU 50, this attribute is not settable any more via API functions.
   6611         } else {
   6612             *status = U_ILLEGAL_ARGUMENT_ERROR;
   6613         }
   6614         break;
   6615     case UCOL_FRENCH_COLLATION: /* attribute for direction of secondary weights*/
   6616         if(value == UCOL_ON) {
   6617             coll->frenchCollation = UCOL_ON;
   6618             coll->frenchCollationisDefault = FALSE;
   6619         } else if (value == UCOL_OFF) {
   6620             coll->frenchCollation = UCOL_OFF;
   6621             coll->frenchCollationisDefault = FALSE;
   6622         } else if (value == UCOL_DEFAULT) {
   6623             coll->frenchCollationisDefault = TRUE;
   6624             coll->frenchCollation = (UColAttributeValue)coll->options->frenchCollation;
   6625         } else {
   6626             *status = U_ILLEGAL_ARGUMENT_ERROR  ;
   6627         }
   6628         break;
   6629     case UCOL_ALTERNATE_HANDLING: /* attribute for handling variable elements*/
   6630         if(value == UCOL_SHIFTED) {
   6631             coll->alternateHandling = UCOL_SHIFTED;
   6632             coll->alternateHandlingisDefault = FALSE;
   6633         } else if (value == UCOL_NON_IGNORABLE) {
   6634             coll->alternateHandling = UCOL_NON_IGNORABLE;
   6635             coll->alternateHandlingisDefault = FALSE;
   6636         } else if (value == UCOL_DEFAULT) {
   6637             coll->alternateHandlingisDefault = TRUE;
   6638             coll->alternateHandling = (UColAttributeValue)coll->options->alternateHandling ;
   6639         } else {
   6640             *status = U_ILLEGAL_ARGUMENT_ERROR  ;
   6641         }
   6642         break;
   6643     case UCOL_CASE_FIRST: /* who goes first, lower case or uppercase */
   6644         if(value == UCOL_LOWER_FIRST) {
   6645             coll->caseFirst = UCOL_LOWER_FIRST;
   6646             coll->caseFirstisDefault = FALSE;
   6647         } else if (value == UCOL_UPPER_FIRST) {
   6648             coll->caseFirst = UCOL_UPPER_FIRST;
   6649             coll->caseFirstisDefault = FALSE;
   6650         } else if (value == UCOL_OFF) {
   6651             coll->caseFirst = UCOL_OFF;
   6652             coll->caseFirstisDefault = FALSE;
   6653         } else if (value == UCOL_DEFAULT) {
   6654             coll->caseFirst = (UColAttributeValue)coll->options->caseFirst;
   6655             coll->caseFirstisDefault = TRUE;
   6656         } else {
   6657             *status = U_ILLEGAL_ARGUMENT_ERROR  ;
   6658         }
   6659         break;
   6660     case UCOL_CASE_LEVEL: /* do we have an extra case level */
   6661         if(value == UCOL_ON) {
   6662             coll->caseLevel = UCOL_ON;
   6663             coll->caseLevelisDefault = FALSE;
   6664         } else if (value == UCOL_OFF) {
   6665             coll->caseLevel = UCOL_OFF;
   6666             coll->caseLevelisDefault = FALSE;
   6667         } else if (value == UCOL_DEFAULT) {
   6668             coll->caseLevel = (UColAttributeValue)coll->options->caseLevel;
   6669             coll->caseLevelisDefault = TRUE;
   6670         } else {
   6671             *status = U_ILLEGAL_ARGUMENT_ERROR  ;
   6672         }
   6673         break;
   6674     case UCOL_NORMALIZATION_MODE: /* attribute for normalization */
   6675         if(value == UCOL_ON) {
   6676             coll->normalizationMode = UCOL_ON;
   6677             coll->normalizationModeisDefault = FALSE;
   6678             initializeFCD(status);
   6679         } else if (value == UCOL_OFF) {
   6680             coll->normalizationMode = UCOL_OFF;
   6681             coll->normalizationModeisDefault = FALSE;
   6682         } else if (value == UCOL_DEFAULT) {
   6683             coll->normalizationModeisDefault = TRUE;
   6684             coll->normalizationMode = (UColAttributeValue)coll->options->normalizationMode;
   6685             if(coll->normalizationMode == UCOL_ON) {
   6686                 initializeFCD(status);
   6687             }
   6688         } else {
   6689             *status = U_ILLEGAL_ARGUMENT_ERROR  ;
   6690         }
   6691         break;
   6692     case UCOL_STRENGTH:         /* attribute for strength */
   6693         if (value == UCOL_DEFAULT) {
   6694             coll->strengthisDefault = TRUE;
   6695             coll->strength = (UColAttributeValue)coll->options->strength;
   6696         } else if (value <= UCOL_IDENTICAL) {
   6697             coll->strengthisDefault = FALSE;
   6698             coll->strength = value;
   6699         } else {
   6700             *status = U_ILLEGAL_ARGUMENT_ERROR  ;
   6701         }
   6702         break;
   6703     case UCOL_ATTRIBUTE_COUNT:
   6704     default:
   6705         *status = U_ILLEGAL_ARGUMENT_ERROR;
   6706         break;
   6707     }
   6708     if(oldFrench != coll->frenchCollation || oldCaseFirst != coll->caseFirst) {
   6709         coll->latinOneRegenTable = TRUE;
   6710     } else {
   6711         coll->latinOneRegenTable = FALSE;
   6712     }
   6713     ucol_updateInternalState(coll, status);
   6714 }
   6715 
   6716 U_CAPI UColAttributeValue  U_EXPORT2
   6717 ucol_getAttribute(const UCollator *coll, UColAttribute attr, UErrorCode *status) {
   6718     if(U_FAILURE(*status) || coll == NULL) {
   6719       return UCOL_DEFAULT;
   6720     }
   6721 
   6722     if(coll->delegate != NULL) {
   6723       return ((Collator*)coll->delegate)->getAttribute(attr,*status);
   6724     }
   6725 
   6726     switch(attr) {
   6727     case UCOL_NUMERIC_COLLATION:
   6728       return coll->numericCollation;
   6729     case UCOL_HIRAGANA_QUATERNARY_MODE:
   6730       return coll->hiraganaQ;
   6731     case UCOL_FRENCH_COLLATION: /* attribute for direction of secondary weights*/
   6732         return coll->frenchCollation;
   6733     case UCOL_ALTERNATE_HANDLING: /* attribute for handling variable elements*/
   6734         return coll->alternateHandling;
   6735     case UCOL_CASE_FIRST: /* who goes first, lower case or uppercase */
   6736         return coll->caseFirst;
   6737     case UCOL_CASE_LEVEL: /* do we have an extra case level */
   6738         return coll->caseLevel;
   6739     case UCOL_NORMALIZATION_MODE: /* attribute for normalization */
   6740         return coll->normalizationMode;
   6741     case UCOL_STRENGTH:         /* attribute for strength */
   6742         return coll->strength;
   6743     case UCOL_ATTRIBUTE_COUNT:
   6744     default:
   6745         *status = U_ILLEGAL_ARGUMENT_ERROR;
   6746         break;
   6747     }
   6748     return UCOL_DEFAULT;
   6749 }
   6750 
   6751 U_CAPI void U_EXPORT2
   6752 ucol_setStrength(    UCollator                *coll,
   6753             UCollationStrength        strength)
   6754 {
   6755     UErrorCode status = U_ZERO_ERROR;
   6756     ucol_setAttribute(coll, UCOL_STRENGTH, strength, &status);
   6757 }
   6758 
   6759 U_CAPI UCollationStrength U_EXPORT2
   6760 ucol_getStrength(const UCollator *coll)
   6761 {
   6762     UErrorCode status = U_ZERO_ERROR;
   6763     return ucol_getAttribute(coll, UCOL_STRENGTH, &status);
   6764 }
   6765 
   6766 U_CAPI int32_t U_EXPORT2
   6767 ucol_getReorderCodes(const UCollator *coll,
   6768                     int32_t *dest,
   6769                     int32_t destCapacity,
   6770                     UErrorCode *status) {
   6771     if (U_FAILURE(*status)) {
   6772         return 0;
   6773     }
   6774 
   6775     if(coll->delegate!=NULL) {
   6776       return ((const Collator*)coll->delegate)->getReorderCodes(dest, destCapacity, *status);
   6777     }
   6778 
   6779     if (destCapacity < 0 || (destCapacity > 0 && dest == NULL)) {
   6780         *status = U_ILLEGAL_ARGUMENT_ERROR;
   6781         return 0;
   6782     }
   6783 
   6784 #ifdef UCOL_DEBUG
   6785     printf("coll->reorderCodesLength = %d\n", coll->reorderCodesLength);
   6786     printf("coll->defaultReorderCodesLength = %d\n", coll->defaultReorderCodesLength);
   6787 #endif
   6788 
   6789     if (coll->reorderCodesLength > destCapacity) {
   6790         *status = U_BUFFER_OVERFLOW_ERROR;
   6791         return coll->reorderCodesLength;
   6792     }
   6793     for (int32_t i = 0; i < coll->reorderCodesLength; i++) {
   6794         dest[i] = coll->reorderCodes[i];
   6795     }
   6796     return coll->reorderCodesLength;
   6797 }
   6798 
   6799 U_CAPI void U_EXPORT2
   6800 ucol_setReorderCodes(UCollator* coll,
   6801                     const int32_t* reorderCodes,
   6802                     int32_t reorderCodesLength,
   6803                     UErrorCode *status) {
   6804     if (U_FAILURE(*status)) {
   6805         return;
   6806     }
   6807 
   6808     if (reorderCodesLength < 0 || (reorderCodesLength > 0 && reorderCodes == NULL)) {
   6809         *status = U_ILLEGAL_ARGUMENT_ERROR;
   6810         return;
   6811     }
   6812 
   6813     if(coll->delegate!=NULL) {
   6814       ((Collator*)coll->delegate)->setReorderCodes(reorderCodes, reorderCodesLength, *status);
   6815       return;
   6816     }
   6817 
   6818     if (coll->reorderCodes != NULL && coll->freeReorderCodesOnClose == TRUE) {
   6819         uprv_free(coll->reorderCodes);
   6820     }
   6821     coll->reorderCodes = NULL;
   6822     coll->reorderCodesLength = 0;
   6823     if (reorderCodesLength == 0) {
   6824         if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
   6825             uprv_free(coll->leadBytePermutationTable);
   6826         }
   6827         coll->leadBytePermutationTable = NULL;
   6828         return;
   6829     }
   6830     coll->reorderCodes = (int32_t*) uprv_malloc(reorderCodesLength * sizeof(int32_t));
   6831     if (coll->reorderCodes == NULL) {
   6832         *status = U_MEMORY_ALLOCATION_ERROR;
   6833         return;
   6834     }
   6835     coll->freeReorderCodesOnClose = TRUE;
   6836     for (int32_t i = 0; i < reorderCodesLength; i++) {
   6837         coll->reorderCodes[i] = reorderCodes[i];
   6838     }
   6839     coll->reorderCodesLength = reorderCodesLength;
   6840     ucol_buildPermutationTable(coll, status);
   6841 }
   6842 
   6843 U_CAPI int32_t U_EXPORT2
   6844 ucol_getEquivalentReorderCodes(int32_t reorderCode,
   6845                     int32_t* dest,
   6846                     int32_t destCapacity,
   6847                     UErrorCode *pErrorCode) {
   6848     bool equivalentCodesSet[USCRIPT_CODE_LIMIT];
   6849     uint16_t leadBytes[256];
   6850     int leadBytesCount;
   6851     int leadByteIndex;
   6852     int16_t reorderCodesForLeadByte[USCRIPT_CODE_LIMIT];
   6853     int reorderCodesForLeadByteCount;
   6854     int reorderCodeIndex;
   6855 
   6856     int32_t equivalentCodesCount = 0;
   6857     int setIndex;
   6858 
   6859     if (U_FAILURE(*pErrorCode)) {
   6860         return 0;
   6861     }
   6862 
   6863     if (destCapacity < 0 || (destCapacity > 0 && dest == NULL)) {
   6864         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
   6865         return 0;
   6866     }
   6867 
   6868     uprv_memset(equivalentCodesSet, 0, USCRIPT_CODE_LIMIT * sizeof(bool));
   6869 
   6870     const UCollator* uca = ucol_initUCA(pErrorCode);
   6871     if (U_FAILURE(*pErrorCode)) {
   6872 	return 0;
   6873     }
   6874     leadBytesCount = ucol_getLeadBytesForReorderCode(uca, reorderCode, leadBytes, 256);
   6875     for (leadByteIndex = 0; leadByteIndex < leadBytesCount; leadByteIndex++) {
   6876         reorderCodesForLeadByteCount = ucol_getReorderCodesForLeadByte(
   6877             uca, leadBytes[leadByteIndex], reorderCodesForLeadByte, USCRIPT_CODE_LIMIT);
   6878         for (reorderCodeIndex = 0; reorderCodeIndex < reorderCodesForLeadByteCount; reorderCodeIndex++) {
   6879             equivalentCodesSet[reorderCodesForLeadByte[reorderCodeIndex]] = true;
   6880         }
   6881     }
   6882 
   6883     for (setIndex = 0; setIndex < USCRIPT_CODE_LIMIT; setIndex++) {
   6884         if (equivalentCodesSet[setIndex] == true) {
   6885             equivalentCodesCount++;
   6886         }
   6887     }
   6888 
   6889     if (destCapacity == 0) {
   6890         return equivalentCodesCount;
   6891     }
   6892 
   6893     equivalentCodesCount = 0;
   6894     for (setIndex = 0; setIndex < USCRIPT_CODE_LIMIT; setIndex++) {
   6895         if (equivalentCodesSet[setIndex] == true) {
   6896             dest[equivalentCodesCount++] = setIndex;
   6897             if (equivalentCodesCount >= destCapacity) {
   6898                 break;
   6899             }
   6900         }
   6901     }
   6902     return equivalentCodesCount;
   6903 }
   6904 
   6905 
   6906 /****************************************************************************/
   6907 /* Following are misc functions                                             */
   6908 /* there are new APIs and some compatibility APIs                           */
   6909 /****************************************************************************/
   6910 
   6911 U_CAPI void U_EXPORT2
   6912 ucol_getVersion(const UCollator* coll,
   6913                 UVersionInfo versionInfo)
   6914 {
   6915     if(coll->delegate!=NULL) {
   6916       ((const Collator*)coll->delegate)->getVersion(versionInfo);
   6917       return;
   6918     }
   6919     /* RunTime version  */
   6920     uint8_t rtVersion = UCOL_RUNTIME_VERSION;
   6921     /* Builder version*/
   6922     uint8_t bdVersion = coll->image->version[0];
   6923 
   6924     /* Charset Version. Need to get the version from cnv files
   6925      * makeconv should populate cnv files with version and
   6926      * an api has to be provided in ucnv.h to obtain this version
   6927      */
   6928     uint8_t csVersion = 0;
   6929 
   6930     /* combine the version info */
   6931     uint16_t cmbVersion = (uint16_t)((rtVersion<<11) | (bdVersion<<6) | (csVersion));
   6932 
   6933     /* Tailoring rules */
   6934     versionInfo[0] = (uint8_t)(cmbVersion>>8);
   6935     versionInfo[1] = (uint8_t)cmbVersion;
   6936     versionInfo[2] = coll->image->version[1];
   6937     if(coll->UCA) {
   6938         /* Include the minor number when getting the UCA version. (major & 1f) << 3 | (minor & 7) */
   6939         versionInfo[3] = (coll->UCA->image->UCAVersion[0] & 0x1f) << 3 | (coll->UCA->image->UCAVersion[1] & 0x07);
   6940     } else {
   6941         versionInfo[3] = 0;
   6942     }
   6943 }
   6944 
   6945 
   6946 /* This internal API checks whether a character is tailored or not */
   6947 U_CAPI UBool  U_EXPORT2
   6948 ucol_isTailored(const UCollator *coll, const UChar u, UErrorCode *status) {
   6949     if(U_FAILURE(*status) || coll == NULL || coll == coll->UCA) {
   6950         return FALSE;
   6951     }
   6952 
   6953     uint32_t CE = UCOL_NOT_FOUND;
   6954     const UChar *ContractionStart = NULL;
   6955     if(u < 0x100) { /* latin-1 */
   6956         CE = coll->latinOneMapping[u];
   6957         if(coll->UCA && CE == coll->UCA->latinOneMapping[u]) {
   6958             return FALSE;
   6959         }
   6960     } else { /* regular */
   6961         CE = UTRIE_GET32_FROM_LEAD(&coll->mapping, u);
   6962     }
   6963 
   6964     if(isContraction(CE)) {
   6965         ContractionStart = (UChar *)coll->image+getContractOffset(CE);
   6966         CE = *(coll->contractionCEs + (ContractionStart- coll->contractionIndex));
   6967     }
   6968 
   6969     return (UBool)(CE != UCOL_NOT_FOUND);
   6970 }
   6971 
   6972 
   6973 /****************************************************************************/
   6974 /* Following are the string compare functions                               */
   6975 /*                                                                          */
   6976 /****************************************************************************/
   6977 
   6978 
   6979 /*  ucol_checkIdent    internal function.  Does byte level string compare.   */
   6980 /*                     Used by strcoll if strength == identical and strings  */
   6981 /*                     are otherwise equal.                                  */
   6982 /*                                                                           */
   6983 /*                     Comparison must be done on NFD normalized strings.    */
   6984 /*                     FCD is not good enough.                               */
   6985 
   6986 static
   6987 UCollationResult    ucol_checkIdent(collIterate *sColl, collIterate *tColl, UBool normalize, UErrorCode *status)
   6988 {
   6989     // When we arrive here, we can have normal strings or UCharIterators. Currently they are both
   6990     // of same type, but that doesn't really mean that it will stay that way.
   6991     int32_t            comparison;
   6992 
   6993     if (sColl->flags & UCOL_USE_ITERATOR) {
   6994         // The division for the array length may truncate the array size to
   6995         // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
   6996         // for all platforms anyway.
   6997         UAlignedMemory stackNormIter1[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
   6998         UAlignedMemory stackNormIter2[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
   6999         UNormIterator *sNIt = NULL, *tNIt = NULL;
   7000         sNIt = unorm_openIter(stackNormIter1, sizeof(stackNormIter1), status);
   7001         tNIt = unorm_openIter(stackNormIter2, sizeof(stackNormIter2), status);
   7002         sColl->iterator->move(sColl->iterator, 0, UITER_START);
   7003         tColl->iterator->move(tColl->iterator, 0, UITER_START);
   7004         UCharIterator *sIt = unorm_setIter(sNIt, sColl->iterator, UNORM_NFD, status);
   7005         UCharIterator *tIt = unorm_setIter(tNIt, tColl->iterator, UNORM_NFD, status);
   7006         comparison = u_strCompareIter(sIt, tIt, TRUE);
   7007         unorm_closeIter(sNIt);
   7008         unorm_closeIter(tNIt);
   7009     } else {
   7010         int32_t sLen      = (sColl->flags & UCOL_ITER_HASLEN) ? (int32_t)(sColl->endp - sColl->string) : -1;
   7011         const UChar *sBuf = sColl->string;
   7012         int32_t tLen      = (tColl->flags & UCOL_ITER_HASLEN) ? (int32_t)(tColl->endp - tColl->string) : -1;
   7013         const UChar *tBuf = tColl->string;
   7014 
   7015         if (normalize) {
   7016             *status = U_ZERO_ERROR;
   7017             // Note: We could use Normalizer::compare() or similar, but for short strings
   7018             // which may not be in FCD it might be faster to just NFD them.
   7019             // Note: spanQuickCheckYes() + normalizeSecondAndAppend() rather than
   7020             // NFD'ing immediately might be faster for long strings,
   7021             // but string comparison is usually done on relatively short strings.
   7022             sColl->nfd->normalize(UnicodeString((sColl->flags & UCOL_ITER_HASLEN) == 0, sBuf, sLen),
   7023                                   sColl->writableBuffer,
   7024                                   *status);
   7025             tColl->nfd->normalize(UnicodeString((tColl->flags & UCOL_ITER_HASLEN) == 0, tBuf, tLen),
   7026                                   tColl->writableBuffer,
   7027                                   *status);
   7028             if(U_FAILURE(*status)) {
   7029                 return UCOL_LESS;
   7030             }
   7031             comparison = sColl->writableBuffer.compareCodePointOrder(tColl->writableBuffer);
   7032         } else {
   7033             comparison = u_strCompare(sBuf, sLen, tBuf, tLen, TRUE);
   7034         }
   7035     }
   7036 
   7037     if (comparison < 0) {
   7038         return UCOL_LESS;
   7039     } else if (comparison == 0) {
   7040         return UCOL_EQUAL;
   7041     } else /* comparison > 0 */ {
   7042         return UCOL_GREATER;
   7043     }
   7044 }
   7045 
   7046 /*  CEBuf - A struct and some inline functions to handle the saving    */
   7047 /*          of CEs in a buffer within ucol_strcoll                     */
   7048 
   7049 #define UCOL_CEBUF_SIZE 512
   7050 typedef struct ucol_CEBuf {
   7051     uint32_t    *buf;
   7052     uint32_t    *endp;
   7053     uint32_t    *pos;
   7054     uint32_t     localArray[UCOL_CEBUF_SIZE];
   7055 } ucol_CEBuf;
   7056 
   7057 
   7058 static
   7059 inline void UCOL_INIT_CEBUF(ucol_CEBuf *b) {
   7060     (b)->buf = (b)->pos = (b)->localArray;
   7061     (b)->endp = (b)->buf + UCOL_CEBUF_SIZE;
   7062 }
   7063 
   7064 static
   7065 void ucol_CEBuf_Expand(ucol_CEBuf *b, collIterate *ci, UErrorCode *status) {
   7066     uint32_t  oldSize;
   7067     uint32_t  newSize;
   7068     uint32_t  *newBuf;
   7069 
   7070     ci->flags |= UCOL_ITER_ALLOCATED;
   7071     oldSize = (uint32_t)(b->pos - b->buf);
   7072     newSize = oldSize * 2;
   7073     newBuf = (uint32_t *)uprv_malloc(newSize * sizeof(uint32_t));
   7074     if(newBuf == NULL) {
   7075         *status = U_MEMORY_ALLOCATION_ERROR;
   7076     }
   7077     else {
   7078         uprv_memcpy(newBuf, b->buf, oldSize * sizeof(uint32_t));
   7079         if (b->buf != b->localArray) {
   7080             uprv_free(b->buf);
   7081         }
   7082         b->buf = newBuf;
   7083         b->endp = b->buf + newSize;
   7084         b->pos  = b->buf + oldSize;
   7085     }
   7086 }
   7087 
   7088 static
   7089 inline void UCOL_CEBUF_PUT(ucol_CEBuf *b, uint32_t ce, collIterate *ci, UErrorCode *status) {
   7090     if (b->pos == b->endp) {
   7091         ucol_CEBuf_Expand(b, ci, status);
   7092     }
   7093     if (U_SUCCESS(*status)) {
   7094         *(b)->pos++ = ce;
   7095     }
   7096 }
   7097 
   7098 /* This is a trick string compare function that goes in and uses sortkeys to compare */
   7099 /* It is used when compare gets in trouble and needs to bail out                     */
   7100 static UCollationResult ucol_compareUsingSortKeys(collIterate *sColl,
   7101                                                   collIterate *tColl,
   7102                                                   UErrorCode *status)
   7103 {
   7104     uint8_t sourceKey[UCOL_MAX_BUFFER], targetKey[UCOL_MAX_BUFFER];
   7105     uint8_t *sourceKeyP = sourceKey;
   7106     uint8_t *targetKeyP = targetKey;
   7107     int32_t sourceKeyLen = UCOL_MAX_BUFFER, targetKeyLen = UCOL_MAX_BUFFER;
   7108     const UCollator *coll = sColl->coll;
   7109     const UChar *source = NULL;
   7110     const UChar *target = NULL;
   7111     int32_t result = UCOL_EQUAL;
   7112     UnicodeString sourceString, targetString;
   7113     int32_t sourceLength;
   7114     int32_t targetLength;
   7115 
   7116     if(sColl->flags & UCOL_USE_ITERATOR) {
   7117         sColl->iterator->move(sColl->iterator, 0, UITER_START);
   7118         tColl->iterator->move(tColl->iterator, 0, UITER_START);
   7119         UChar32 c;
   7120         while((c=sColl->iterator->next(sColl->iterator))>=0) {
   7121             sourceString.append((UChar)c);
   7122         }
   7123         while((c=tColl->iterator->next(tColl->iterator))>=0) {
   7124             targetString.append((UChar)c);
   7125         }
   7126         source = sourceString.getBuffer();
   7127         sourceLength = sourceString.length();
   7128         target = targetString.getBuffer();
   7129         targetLength = targetString.length();
   7130     } else { // no iterators
   7131         sourceLength = (sColl->flags&UCOL_ITER_HASLEN)?(int32_t)(sColl->endp-sColl->string):-1;
   7132         targetLength = (tColl->flags&UCOL_ITER_HASLEN)?(int32_t)(tColl->endp-tColl->string):-1;
   7133         source = sColl->string;
   7134         target = tColl->string;
   7135     }
   7136 
   7137 
   7138 
   7139     sourceKeyLen = ucol_getSortKey(coll, source, sourceLength, sourceKeyP, sourceKeyLen);
   7140     if(sourceKeyLen > UCOL_MAX_BUFFER) {
   7141         sourceKeyP = (uint8_t*)uprv_malloc(sourceKeyLen*sizeof(uint8_t));
   7142         if(sourceKeyP == NULL) {
   7143             *status = U_MEMORY_ALLOCATION_ERROR;
   7144             goto cleanup_and_do_compare;
   7145         }
   7146         sourceKeyLen = ucol_getSortKey(coll, source, sourceLength, sourceKeyP, sourceKeyLen);
   7147     }
   7148 
   7149     targetKeyLen = ucol_getSortKey(coll, target, targetLength, targetKeyP, targetKeyLen);
   7150     if(targetKeyLen > UCOL_MAX_BUFFER) {
   7151         targetKeyP = (uint8_t*)uprv_malloc(targetKeyLen*sizeof(uint8_t));
   7152         if(targetKeyP == NULL) {
   7153             *status = U_MEMORY_ALLOCATION_ERROR;
   7154             goto cleanup_and_do_compare;
   7155         }
   7156         targetKeyLen = ucol_getSortKey(coll, target, targetLength, targetKeyP, targetKeyLen);
   7157     }
   7158 
   7159     result = uprv_strcmp((const char*)sourceKeyP, (const char*)targetKeyP);
   7160 
   7161 cleanup_and_do_compare:
   7162     if(sourceKeyP != NULL && sourceKeyP != sourceKey) {
   7163         uprv_free(sourceKeyP);
   7164     }
   7165 
   7166     if(targetKeyP != NULL && targetKeyP != targetKey) {
   7167         uprv_free(targetKeyP);
   7168     }
   7169 
   7170     if(result<0) {
   7171         return UCOL_LESS;
   7172     } else if(result>0) {
   7173         return UCOL_GREATER;
   7174     } else {
   7175         return UCOL_EQUAL;
   7176     }
   7177 }
   7178 
   7179 
   7180 static UCollationResult
   7181 ucol_strcollRegular(collIterate *sColl, collIterate *tColl, UErrorCode *status)
   7182 {
   7183     U_ALIGN_CODE(16);
   7184 
   7185     const UCollator *coll = sColl->coll;
   7186 
   7187 
   7188     // setting up the collator parameters
   7189     UColAttributeValue strength = coll->strength;
   7190     UBool initialCheckSecTer = (strength  >= UCOL_SECONDARY);
   7191 
   7192     UBool checkSecTer = initialCheckSecTer;
   7193     UBool checkTertiary = (strength  >= UCOL_TERTIARY);
   7194     UBool checkQuad = (strength  >= UCOL_QUATERNARY);
   7195     UBool checkIdent = (strength == UCOL_IDENTICAL);
   7196     UBool checkCase = (coll->caseLevel == UCOL_ON);
   7197     UBool isFrenchSec = (coll->frenchCollation == UCOL_ON) && checkSecTer;
   7198     UBool shifted = (coll->alternateHandling == UCOL_SHIFTED);
   7199     UBool qShifted = shifted && checkQuad;
   7200     UBool doHiragana = (coll->hiraganaQ == UCOL_ON) && checkQuad;
   7201 
   7202     if(doHiragana && shifted) {
   7203         return (ucol_compareUsingSortKeys(sColl, tColl, status));
   7204     }
   7205     uint8_t caseSwitch = coll->caseSwitch;
   7206     uint8_t tertiaryMask = coll->tertiaryMask;
   7207 
   7208     // This is the lowest primary value that will not be ignored if shifted
   7209     uint32_t LVT = (shifted)?(coll->variableTopValue<<16):0;
   7210 
   7211     UCollationResult result = UCOL_EQUAL;
   7212     UCollationResult hirResult = UCOL_EQUAL;
   7213 
   7214     // Preparing the CE buffers. They will be filled during the primary phase
   7215     ucol_CEBuf   sCEs;
   7216     ucol_CEBuf   tCEs;
   7217     UCOL_INIT_CEBUF(&sCEs);
   7218     UCOL_INIT_CEBUF(&tCEs);
   7219 
   7220     uint32_t secS = 0, secT = 0;
   7221     uint32_t sOrder=0, tOrder=0;
   7222 
   7223     // Non shifted primary processing is quite simple
   7224     if(!shifted) {
   7225         for(;;) {
   7226 
   7227             // We fetch CEs until we hit a non ignorable primary or end.
   7228             do {
   7229                 // We get the next CE
   7230                 sOrder = ucol_IGetNextCE(coll, sColl, status);
   7231                 // Stuff it in the buffer
   7232                 UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
   7233                 // And keep just the primary part.
   7234                 sOrder &= UCOL_PRIMARYMASK;
   7235             } while(sOrder == 0);
   7236 
   7237             // see the comments on the above block
   7238             do {
   7239                 tOrder = ucol_IGetNextCE(coll, tColl, status);
   7240                 UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
   7241                 tOrder &= UCOL_PRIMARYMASK;
   7242             } while(tOrder == 0);
   7243 
   7244             // if both primaries are the same
   7245             if(sOrder == tOrder) {
   7246                 // and there are no more CEs, we advance to the next level
   7247                 if(sOrder == UCOL_NO_MORE_CES_PRIMARY) {
   7248                     break;
   7249                 }
   7250                 if(doHiragana && hirResult == UCOL_EQUAL) {
   7251                     if((sColl->flags & UCOL_WAS_HIRAGANA) != (tColl->flags & UCOL_WAS_HIRAGANA)) {
   7252                         hirResult = ((sColl->flags & UCOL_WAS_HIRAGANA) > (tColl->flags & UCOL_WAS_HIRAGANA))
   7253                             ? UCOL_LESS:UCOL_GREATER;
   7254                     }
   7255                 }
   7256             } else {
   7257                 // only need to check one for continuation
   7258                 // if one is then the other must be or the preceding CE would be a prefix of the other
   7259                 if (coll->leadBytePermutationTable != NULL && !isContinuation(sOrder)) {
   7260                     sOrder = (coll->leadBytePermutationTable[sOrder>>24] << 24) | (sOrder & 0x00FFFFFF);
   7261                     tOrder = (coll->leadBytePermutationTable[tOrder>>24] << 24) | (tOrder & 0x00FFFFFF);
   7262                 }
   7263                 // if two primaries are different, we are done
   7264                 result = (sOrder < tOrder) ?  UCOL_LESS: UCOL_GREATER;
   7265                 goto commonReturn;
   7266             }
   7267         } // no primary difference... do the rest from the buffers
   7268     } else { // shifted - do a slightly more complicated processing :)
   7269         for(;;) {
   7270             UBool sInShifted = FALSE;
   7271             UBool tInShifted = FALSE;
   7272             // This version of code can be refactored. However, it seems easier to understand this way.
   7273             // Source loop. Sam as the target loop.
   7274             for(;;) {
   7275                 sOrder = ucol_IGetNextCE(coll, sColl, status);
   7276                 if(sOrder == UCOL_NO_MORE_CES) {
   7277                     UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
   7278                     break;
   7279                 } else if(sOrder == 0 || (sInShifted && (sOrder & UCOL_PRIMARYMASK) == 0)) {
   7280                     /* UCA amendment - ignore ignorables that follow shifted code points */
   7281                     continue;
   7282                 } else if(isContinuation(sOrder)) {
   7283                     if((sOrder & UCOL_PRIMARYMASK) > 0) { /* There is primary value */
   7284                         if(sInShifted) {
   7285                             sOrder = (sOrder & UCOL_PRIMARYMASK) | 0xC0; /* preserve interesting continuation */
   7286                             UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
   7287                             continue;
   7288                         } else {
   7289                             UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
   7290                             break;
   7291                         }
   7292                     } else { /* Just lower level values */
   7293                         if(sInShifted) {
   7294                             continue;
   7295                         } else {
   7296                             UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
   7297                             continue;
   7298                         }
   7299                     }
   7300                 } else { /* regular */
   7301                     if(coll->leadBytePermutationTable != NULL){
   7302                         sOrder = (coll->leadBytePermutationTable[sOrder>>24] << 24) | (sOrder & 0x00FFFFFF);
   7303                     }
   7304                     if((sOrder & UCOL_PRIMARYMASK) > LVT) {
   7305                         UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
   7306                         break;
   7307                     } else {
   7308                         if((sOrder & UCOL_PRIMARYMASK) > 0) {
   7309                             sInShifted = TRUE;
   7310                             sOrder &= UCOL_PRIMARYMASK;
   7311                             UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
   7312                             continue;
   7313                         } else {
   7314                             UCOL_CEBUF_PUT(&sCEs, sOrder, sColl, status);
   7315                             sInShifted = FALSE;
   7316                             continue;
   7317                         }
   7318                     }
   7319                 }
   7320             }
   7321             sOrder &= UCOL_PRIMARYMASK;
   7322             sInShifted = FALSE;
   7323 
   7324             for(;;) {
   7325                 tOrder = ucol_IGetNextCE(coll, tColl, status);
   7326                 if(tOrder == UCOL_NO_MORE_CES) {
   7327                     UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
   7328                     break;
   7329                 } else if(tOrder == 0 || (tInShifted && (tOrder & UCOL_PRIMARYMASK) == 0)) {
   7330                     /* UCA amendment - ignore ignorables that follow shifted code points */
   7331                     continue;
   7332                 } else if(isContinuation(tOrder)) {
   7333                     if((tOrder & UCOL_PRIMARYMASK) > 0) { /* There is primary value */
   7334                         if(tInShifted) {
   7335                             tOrder = (tOrder & UCOL_PRIMARYMASK) | 0xC0; /* preserve interesting continuation */
   7336                             UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
   7337                             continue;
   7338                         } else {
   7339                             UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
   7340                             break;
   7341                         }
   7342                     } else { /* Just lower level values */
   7343                         if(tInShifted) {
   7344                             continue;
   7345                         } else {
   7346                             UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
   7347                             continue;
   7348                         }
   7349                     }
   7350                 } else { /* regular */
   7351                     if(coll->leadBytePermutationTable != NULL){
   7352                         tOrder = (coll->leadBytePermutationTable[tOrder>>24] << 24) | (tOrder & 0x00FFFFFF);
   7353                     }
   7354                     if((tOrder & UCOL_PRIMARYMASK) > LVT) {
   7355                         UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
   7356                         break;
   7357                     } else {
   7358                         if((tOrder & UCOL_PRIMARYMASK) > 0) {
   7359                             tInShifted = TRUE;
   7360                             tOrder &= UCOL_PRIMARYMASK;
   7361                             UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
   7362                             continue;
   7363                         } else {
   7364                             UCOL_CEBUF_PUT(&tCEs, tOrder, tColl, status);
   7365                             tInShifted = FALSE;
   7366                             continue;
   7367                         }
   7368                     }
   7369                 }
   7370             }
   7371             tOrder &= UCOL_PRIMARYMASK;
   7372             tInShifted = FALSE;
   7373 
   7374             if(sOrder == tOrder) {
   7375                 /*
   7376                 if(doHiragana && hirResult == UCOL_EQUAL) {
   7377                 if((sColl.flags & UCOL_WAS_HIRAGANA) != (tColl.flags & UCOL_WAS_HIRAGANA)) {
   7378                 hirResult = ((sColl.flags & UCOL_WAS_HIRAGANA) > (tColl.flags & UCOL_WAS_HIRAGANA))
   7379                 ? UCOL_LESS:UCOL_GREATER;
   7380                 }
   7381                 }
   7382                 */
   7383                 if(sOrder == UCOL_NO_MORE_CES_PRIMARY) {
   7384                     break;
   7385                 } else {
   7386                     sOrder = 0;
   7387                     tOrder = 0;
   7388                     continue;
   7389                 }
   7390             } else {
   7391                 result = (sOrder < tOrder) ? UCOL_LESS : UCOL_GREATER;
   7392                 goto commonReturn;
   7393             }
   7394         } /* no primary difference... do the rest from the buffers */
   7395     }
   7396 
   7397     /* now, we're gonna reexamine collected CEs */
   7398     uint32_t    *sCE;
   7399     uint32_t    *tCE;
   7400 
   7401     /* This is the secondary level of comparison */
   7402     if(checkSecTer) {
   7403         if(!isFrenchSec) { /* normal */
   7404             sCE = sCEs.buf;
   7405             tCE = tCEs.buf;
   7406             for(;;) {
   7407                 while (secS == 0) {
   7408                     secS = *(sCE++) & UCOL_SECONDARYMASK;
   7409                 }
   7410 
   7411                 while(secT == 0) {
   7412                     secT = *(tCE++) & UCOL_SECONDARYMASK;
   7413                 }
   7414 
   7415                 if(secS == secT) {
   7416                     if(secS == UCOL_NO_MORE_CES_SECONDARY) {
   7417                         break;
   7418                     } else {
   7419                         secS = 0; secT = 0;
   7420                         continue;
   7421                     }
   7422                 } else {
   7423                     result = (secS < secT) ? UCOL_LESS : UCOL_GREATER;
   7424                     goto commonReturn;
   7425                 }
   7426             }
   7427         } else { /* do the French */
   7428             uint32_t *sCESave = NULL;
   7429             uint32_t *tCESave = NULL;
   7430             sCE = sCEs.pos-2; /* this could also be sCEs-- if needs to be optimized */
   7431             tCE = tCEs.pos-2;
   7432             for(;;) {
   7433                 while (secS == 0 && sCE >= sCEs.buf) {
   7434                     if(sCESave == NULL) {
   7435                         secS = *(sCE--);
   7436                         if(isContinuation(secS)) {
   7437                             while(isContinuation(secS = *(sCE--)))
   7438                                 ;
   7439                             /* after this, secS has the start of continuation, and sCEs points before that */
   7440                             sCESave = sCE; /* we save it, so that we know where to come back AND that we need to go forward */
   7441                             sCE+=2;  /* need to point to the first continuation CP */
   7442                             /* However, now you can just continue doing stuff */
   7443                         }
   7444                     } else {
   7445                         secS = *(sCE++);
   7446                         if(!isContinuation(secS)) { /* This means we have finished with this cont */
   7447                             sCE = sCESave;            /* reset the pointer to before continuation */
   7448                             sCESave = NULL;
   7449                             secS = 0;  /* Fetch a fresh CE before the continuation sequence. */
   7450                             continue;
   7451                         }
   7452                     }
   7453                     secS &= UCOL_SECONDARYMASK; /* remove the continuation bit */
   7454                 }
   7455 
   7456                 while(secT == 0 && tCE >= tCEs.buf) {
   7457                     if(tCESave == NULL) {
   7458                         secT = *(tCE--);
   7459                         if(isContinuation(secT)) {
   7460                             while(isContinuation(secT = *(tCE--)))
   7461                                 ;
   7462                             /* after this, secS has the start of continuation, and sCEs points before that */
   7463                             tCESave = tCE; /* we save it, so that we know where to come back AND that we need to go forward */
   7464                             tCE+=2;  /* need to point to the first continuation CP */
   7465                             /* However, now you can just continue doing stuff */
   7466                         }
   7467                     } else {
   7468                         secT = *(tCE++);
   7469                         if(!isContinuation(secT)) { /* This means we have finished with this cont */
   7470                             tCE = tCESave;          /* reset the pointer to before continuation */
   7471                             tCESave = NULL;
   7472                             secT = 0;  /* Fetch a fresh CE before the continuation sequence. */
   7473                             continue;
   7474                         }
   7475                     }
   7476                     secT &= UCOL_SECONDARYMASK; /* remove the continuation bit */
   7477                 }
   7478 
   7479                 if(secS == secT) {
   7480                     if(secS == UCOL_NO_MORE_CES_SECONDARY || (sCE < sCEs.buf && tCE < tCEs.buf)) {
   7481                         break;
   7482                     } else {
   7483                         secS = 0; secT = 0;
   7484                         continue;
   7485                     }
   7486                 } else {
   7487                     result = (secS < secT) ? UCOL_LESS : UCOL_GREATER;
   7488                     goto commonReturn;
   7489                 }
   7490             }
   7491         }
   7492     }
   7493 
   7494     /* doing the case bit */
   7495     if(checkCase) {
   7496         sCE = sCEs.buf;
   7497         tCE = tCEs.buf;
   7498         for(;;) {
   7499             while((secS & UCOL_REMOVE_CASE) == 0) {
   7500                 if(!isContinuation(*sCE++)) {
   7501                     secS =*(sCE-1);
   7502                     if(((secS & UCOL_PRIMARYMASK) != 0) || strength > UCOL_PRIMARY) {
   7503                         // primary ignorables should not be considered on the case level when the strength is primary
   7504                         // otherwise, the CEs stop being well-formed
   7505                         secS &= UCOL_TERT_CASE_MASK;
   7506                         secS ^= caseSwitch;
   7507                     } else {
   7508                         secS = 0;
   7509                     }
   7510                 } else {
   7511                     secS = 0;
   7512                 }
   7513             }
   7514 
   7515             while((secT & UCOL_REMOVE_CASE) == 0) {
   7516                 if(!isContinuation(*tCE++)) {
   7517                     secT = *(tCE-1);
   7518                     if(((secT & UCOL_PRIMARYMASK) != 0) || strength > UCOL_PRIMARY) {
   7519                         // primary ignorables should not be considered on the case level when the strength is primary
   7520                         // otherwise, the CEs stop being well-formed
   7521                         secT &= UCOL_TERT_CASE_MASK;
   7522                         secT ^= caseSwitch;
   7523                     } else {
   7524                         secT = 0;
   7525                     }
   7526                 } else {
   7527                     secT = 0;
   7528                 }
   7529             }
   7530 
   7531             if((secS & UCOL_CASE_BIT_MASK) < (secT & UCOL_CASE_BIT_MASK)) {
   7532                 result = UCOL_LESS;
   7533                 goto commonReturn;
   7534             } else if((secS & UCOL_CASE_BIT_MASK) > (secT & UCOL_CASE_BIT_MASK)) {
   7535                 result = UCOL_GREATER;
   7536                 goto commonReturn;
   7537             }
   7538 
   7539             if((secS & UCOL_REMOVE_CASE) == UCOL_NO_MORE_CES_TERTIARY || (secT & UCOL_REMOVE_CASE) == UCOL_NO_MORE_CES_TERTIARY ) {
   7540                 break;
   7541             } else {
   7542                 secS = 0;
   7543                 secT = 0;
   7544             }
   7545         }
   7546     }
   7547 
   7548     /* Tertiary level */
   7549     if(checkTertiary) {
   7550         secS = 0;
   7551         secT = 0;
   7552         sCE = sCEs.buf;
   7553         tCE = tCEs.buf;
   7554         for(;;) {
   7555             while((secS & UCOL_REMOVE_CASE) == 0) {
   7556                 secS = *(sCE++) & tertiaryMask;
   7557                 if(!isContinuation(secS)) {
   7558                     secS ^= caseSwitch;
   7559                 } else {
   7560                     secS &= UCOL_REMOVE_CASE;
   7561                 }
   7562             }
   7563 
   7564             while((secT & UCOL_REMOVE_CASE)  == 0) {
   7565                 secT = *(tCE++) & tertiaryMask;
   7566                 if(!isContinuation(secT)) {
   7567                     secT ^= caseSwitch;
   7568                 } else {
   7569                     secT &= UCOL_REMOVE_CASE;
   7570                 }
   7571             }
   7572 
   7573             if(secS == secT) {
   7574                 if((secS & UCOL_REMOVE_CASE) == 1) {
   7575                     break;
   7576                 } else {
   7577                     secS = 0; secT = 0;
   7578                     continue;
   7579                 }
   7580             } else {
   7581                 result = (secS < secT) ? UCOL_LESS : UCOL_GREATER;
   7582                 goto commonReturn;
   7583             }
   7584         }
   7585     }
   7586 
   7587 
   7588     if(qShifted /*checkQuad*/) {
   7589         UBool sInShifted = TRUE;
   7590         UBool tInShifted = TRUE;
   7591         secS = 0;
   7592         secT = 0;
   7593         sCE = sCEs.buf;
   7594         tCE = tCEs.buf;
   7595         for(;;) {
   7596             while((secS == 0 && secS != UCOL_NO_MORE_CES) || (isContinuation(secS) && !sInShifted)) {
   7597                 secS = *(sCE++);
   7598                 if(isContinuation(secS)) {
   7599                     if(!sInShifted) {
   7600                         continue;
   7601                     }
   7602                 } else if(secS > LVT || (secS & UCOL_PRIMARYMASK) == 0) { /* non continuation */
   7603                     secS = UCOL_PRIMARYMASK;
   7604                     sInShifted = FALSE;
   7605                 } else {
   7606                     sInShifted = TRUE;
   7607                 }
   7608             }
   7609             secS &= UCOL_PRIMARYMASK;
   7610 
   7611 
   7612             while((secT == 0 && secT != UCOL_NO_MORE_CES) || (isContinuation(secT) && !tInShifted)) {
   7613                 secT = *(tCE++);
   7614                 if(isContinuation(secT)) {
   7615                     if(!tInShifted) {
   7616                         continue;
   7617                     }
   7618                 } else if(secT > LVT || (secT & UCOL_PRIMARYMASK) == 0) {
   7619                     secT = UCOL_PRIMARYMASK;
   7620                     tInShifted = FALSE;
   7621                 } else {
   7622                     tInShifted = TRUE;
   7623                 }
   7624             }
   7625             secT &= UCOL_PRIMARYMASK;
   7626 
   7627             if(secS == secT) {
   7628                 if(secS == UCOL_NO_MORE_CES_PRIMARY) {
   7629                     break;
   7630                 } else {
   7631                     secS = 0; secT = 0;
   7632                     continue;
   7633                 }
   7634             } else {
   7635                 result = (secS < secT) ? UCOL_LESS : UCOL_GREATER;
   7636                 goto commonReturn;
   7637             }
   7638         }
   7639     } else if(doHiragana && hirResult != UCOL_EQUAL) {
   7640         // If we're fine on quaternaries, we might be different
   7641         // on Hiragana. This, however, might fail us in shifted.
   7642         result = hirResult;
   7643         goto commonReturn;
   7644     }
   7645 
   7646     /*  For IDENTICAL comparisons, we use a bitwise character comparison */
   7647     /*  as a tiebreaker if all else is equal.                                */
   7648     /*  Getting here  should be quite rare - strings are not identical -     */
   7649     /*     that is checked first, but compared == through all other checks.  */
   7650     if(checkIdent)
   7651     {
   7652         //result = ucol_checkIdent(&sColl, &tColl, coll->normalizationMode == UCOL_ON);
   7653         result = ucol_checkIdent(sColl, tColl, TRUE, status);
   7654     }
   7655 
   7656 commonReturn:
   7657     if ((sColl->flags | tColl->flags) & UCOL_ITER_ALLOCATED) {
   7658         if (sCEs.buf != sCEs.localArray ) {
   7659             uprv_free(sCEs.buf);
   7660         }
   7661         if (tCEs.buf != tCEs.localArray ) {
   7662             uprv_free(tCEs.buf);
   7663         }
   7664     }
   7665 
   7666     return result;
   7667 }
   7668 
   7669 static UCollationResult
   7670 ucol_strcollRegular(const UCollator *coll,
   7671                     const UChar *source, int32_t sourceLength,
   7672                     const UChar *target, int32_t targetLength,
   7673                     UErrorCode *status) {
   7674     collIterate sColl, tColl;
   7675     // Preparing the context objects for iterating over strings
   7676     IInit_collIterate(coll, source, sourceLength, &sColl, status);
   7677     IInit_collIterate(coll, target, targetLength, &tColl, status);
   7678     if(U_FAILURE(*status)) {
   7679         return UCOL_LESS;
   7680     }
   7681     return ucol_strcollRegular(&sColl, &tColl, status);
   7682 }
   7683 
   7684 static inline uint32_t
   7685 ucol_getLatinOneContraction(const UCollator *coll, int32_t strength,
   7686                           uint32_t CE, const UChar *s, int32_t *index, int32_t len)
   7687 {
   7688     const UChar *UCharOffset = (UChar *)coll->image+getContractOffset(CE&0xFFF);
   7689     int32_t latinOneOffset = (CE & 0x00FFF000) >> 12;
   7690     int32_t offset = 1;
   7691     UChar schar = 0, tchar = 0;
   7692 
   7693     for(;;) {
   7694         if(len == -1) {
   7695             if(s[*index] == 0) { // end of string
   7696                 return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset]);
   7697             } else {
   7698                 schar = s[*index];
   7699             }
   7700         } else {
   7701             if(*index == len) {
   7702                 return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset]);
   7703             } else {
   7704                 schar = s[*index];
   7705             }
   7706         }
   7707 
   7708         while(schar > (tchar = *(UCharOffset+offset))) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
   7709             offset++;
   7710         }
   7711 
   7712         if (schar == tchar) {
   7713             (*index)++;
   7714             return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset+offset]);
   7715         }
   7716         else
   7717         {
   7718             if(schar & 0xFF00 /*> UCOL_ENDOFLATIN1RANGE*/) {
   7719                 return UCOL_BAIL_OUT_CE;
   7720             }
   7721             // skip completely ignorables
   7722             uint32_t isZeroCE = UTRIE_GET32_FROM_LEAD(&coll->mapping, schar);
   7723             if(isZeroCE == 0) { // we have to ignore completely ignorables
   7724                 (*index)++;
   7725                 continue;
   7726             }
   7727 
   7728             return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset]);
   7729         }
   7730     }
   7731 }
   7732 
   7733 
   7734 /**
   7735  * This is a fast strcoll, geared towards text in Latin-1.
   7736  * It supports contractions of size two, French secondaries
   7737  * and case switching. You can use it with strengths primary
   7738  * to tertiary. It does not support shifted and case level.
   7739  * It relies on the table build by setupLatin1Table. If it
   7740  * doesn't understand something, it will go to the regular
   7741  * strcoll.
   7742  */
   7743 static UCollationResult
   7744 ucol_strcollUseLatin1( const UCollator    *coll,
   7745               const UChar        *source,
   7746               int32_t            sLen,
   7747               const UChar        *target,
   7748               int32_t            tLen,
   7749               UErrorCode *status)
   7750 {
   7751     U_ALIGN_CODE(16);
   7752     int32_t strength = coll->strength;
   7753 
   7754     int32_t sIndex = 0, tIndex = 0;
   7755     UChar sChar = 0, tChar = 0;
   7756     uint32_t sOrder=0, tOrder=0;
   7757 
   7758     UBool endOfSource = FALSE;
   7759 
   7760     uint32_t *elements = coll->latinOneCEs;
   7761 
   7762     UBool haveContractions = FALSE; // if we have contractions in our string
   7763                                     // we cannot do French secondary
   7764 
   7765     // Do the primary level
   7766     for(;;) {
   7767         while(sOrder==0) { // this loop skips primary ignorables
   7768             // sOrder=getNextlatinOneCE(source);
   7769             if(sLen==-1) {   // handling zero terminated strings
   7770                 sChar=source[sIndex++];
   7771                 if(sChar==0) {
   7772                     endOfSource = TRUE;
   7773                     break;
   7774                 }
   7775             } else {        // handling strings with known length
   7776                 if(sIndex==sLen) {
   7777                     endOfSource = TRUE;
   7778                     break;
   7779                 }
   7780                 sChar=source[sIndex++];
   7781             }
   7782             if(sChar&0xFF00) { // if we encounter non-latin-1, we bail out (sChar > 0xFF, but this is faster on win32)
   7783                 //fprintf(stderr, "R");
   7784                 return ucol_strcollRegular(coll, source, sLen, target, tLen, status);
   7785             }
   7786             sOrder = elements[sChar];
   7787             if(sOrder >= UCOL_NOT_FOUND) { // if we got a special
   7788                 // specials can basically be either contractions or bail-out signs. If we get anything
   7789                 // else, we'll bail out anywasy
   7790                 if(getCETag(sOrder) == CONTRACTION_TAG) {
   7791                     sOrder = ucol_getLatinOneContraction(coll, UCOL_PRIMARY, sOrder, source, &sIndex, sLen);
   7792                     haveContractions = TRUE; // if there are contractions, we cannot do French secondary
   7793                     // However, if there are contractions in the table, but we always use just one char,
   7794                     // we might be able to do French. This should be checked out.
   7795                 }
   7796                 if(sOrder >= UCOL_NOT_FOUND /*== UCOL_BAIL_OUT_CE*/) {
   7797                     //fprintf(stderr, "S");
   7798                     return ucol_strcollRegular(coll, source, sLen, target, tLen, status);
   7799                 }
   7800             }
   7801         }
   7802 
   7803         while(tOrder==0) {  // this loop skips primary ignorables
   7804             // tOrder=getNextlatinOneCE(target);
   7805             if(tLen==-1) {    // handling zero terminated strings
   7806                 tChar=target[tIndex++];
   7807                 if(tChar==0) {
   7808                     if(endOfSource) { // this is different than source loop,
   7809                         // as we already know that source loop is done here,
   7810                         // so we can either finish the primary loop if both
   7811                         // strings are done or anounce the result if only
   7812                         // target is done. Same below.
   7813                         goto endOfPrimLoop;
   7814                     } else {
   7815                         return UCOL_GREATER;
   7816                     }
   7817                 }
   7818             } else {          // handling strings with known length
   7819                 if(tIndex==tLen) {
   7820                     if(endOfSource) {
   7821                         goto endOfPrimLoop;
   7822                     } else {
   7823                         return UCOL_GREATER;
   7824                     }
   7825                 }
   7826                 tChar=target[tIndex++];
   7827             }
   7828             if(tChar&0xFF00) { // if we encounter non-latin-1, we bail out (sChar > 0xFF, but this is faster on win32)
   7829                 //fprintf(stderr, "R");
   7830                 return ucol_strcollRegular(coll, source, sLen, target, tLen, status);
   7831             }
   7832             tOrder = elements[tChar];
   7833             if(tOrder >= UCOL_NOT_FOUND) {
   7834                 // Handling specials, see the comments for source
   7835                 if(getCETag(tOrder) == CONTRACTION_TAG) {
   7836                     tOrder = ucol_getLatinOneContraction(coll, UCOL_PRIMARY, tOrder, target, &tIndex, tLen);
   7837                     haveContractions = TRUE;
   7838                 }
   7839                 if(tOrder >= UCOL_NOT_FOUND /*== UCOL_BAIL_OUT_CE*/) {
   7840                     //fprintf(stderr, "S");
   7841                     return ucol_strcollRegular(coll, source, sLen, target, tLen, status);
   7842                 }
   7843             }
   7844         }
   7845         if(endOfSource) { // source is finished, but target is not, say the result.
   7846             return UCOL_LESS;
   7847         }
   7848 
   7849         if(sOrder == tOrder) { // if we have same CEs, we continue the loop
   7850             sOrder = 0; tOrder = 0;
   7851             continue;
   7852         } else {
   7853             // compare current top bytes
   7854             if(((sOrder^tOrder)&0xFF000000)!=0) {
   7855                 // top bytes differ, return difference
   7856                 if(sOrder < tOrder) {
   7857                     return UCOL_LESS;
   7858                 } else if(sOrder > tOrder) {
   7859                     return UCOL_GREATER;
   7860                 }
   7861                 // instead of return (int32_t)(sOrder>>24)-(int32_t)(tOrder>>24);
   7862                 // since we must return enum value
   7863             }
   7864 
   7865             // top bytes match, continue with following bytes
   7866             sOrder<<=8;
   7867             tOrder<<=8;
   7868         }
   7869     }
   7870 
   7871 endOfPrimLoop:
   7872     // after primary loop, we definitely know the sizes of strings,
   7873     // so we set it and use simpler loop for secondaries and tertiaries
   7874     sLen = sIndex; tLen = tIndex;
   7875     if(strength >= UCOL_SECONDARY) {
   7876         // adjust the table beggining
   7877         elements += coll->latinOneTableLen;
   7878         endOfSource = FALSE;
   7879 
   7880         if(coll->frenchCollation == UCOL_OFF) { // non French
   7881             // This loop is a simplified copy of primary loop
   7882             // at this point we know that whole strings are latin-1, so we don't
   7883             // check for that. We also know that we only have contractions as
   7884             // specials.
   7885             sIndex = 0; tIndex = 0;
   7886             for(;;) {
   7887                 while(sOrder==0) {
   7888                     if(sIndex==sLen) {
   7889                         endOfSource = TRUE;
   7890                         break;
   7891                     }
   7892                     sChar=source[sIndex++];
   7893                     sOrder = elements[sChar];
   7894                     if(sOrder > UCOL_NOT_FOUND) {
   7895                         sOrder = ucol_getLatinOneContraction(coll, UCOL_SECONDARY, sOrder, source, &sIndex, sLen);
   7896                     }
   7897                 }
   7898 
   7899                 while(tOrder==0) {
   7900                     if(tIndex==tLen) {
   7901                         if(endOfSource) {
   7902                             goto endOfSecLoop;
   7903                         } else {
   7904                             return UCOL_GREATER;
   7905                         }
   7906                     }
   7907                     tChar=target[tIndex++];
   7908                     tOrder = elements[tChar];
   7909                     if(tOrder > UCOL_NOT_FOUND) {
   7910                         tOrder = ucol_getLatinOneContraction(coll, UCOL_SECONDARY, tOrder, target, &tIndex, tLen);
   7911                     }
   7912                 }
   7913                 if(endOfSource) {
   7914                     return UCOL_LESS;
   7915                 }
   7916 
   7917                 if(sOrder == tOrder) {
   7918                     sOrder = 0; tOrder = 0;
   7919                     continue;
   7920                 } else {
   7921                     // see primary loop for comments on this
   7922                     if(((sOrder^tOrder)&0xFF000000)!=0) {
   7923                         if(sOrder < tOrder) {
   7924                             return UCOL_LESS;
   7925                         } else if(sOrder > tOrder) {
   7926                             return UCOL_GREATER;
   7927                         }
   7928                     }
   7929                     sOrder<<=8;
   7930                     tOrder<<=8;
   7931                 }
   7932             }
   7933         } else { // French
   7934             if(haveContractions) { // if we have contractions, we have to bail out
   7935                 // since we don't really know how to handle them here
   7936                 return ucol_strcollRegular(coll, source, sLen, target, tLen, status);
   7937             }
   7938             // For French, we go backwards
   7939             sIndex = sLen; tIndex = tLen;
   7940             for(;;) {
   7941                 while(sOrder==0) {
   7942                     if(sIndex==0) {
   7943                         endOfSource = TRUE;
   7944                         break;
   7945                     }
   7946                     sChar=source[--sIndex];
   7947                     sOrder = elements[sChar];
   7948                     // don't even look for contractions
   7949                 }
   7950 
   7951                 while(tOrder==0) {
   7952                     if(tIndex==0) {
   7953                         if(endOfSource) {
   7954                             goto endOfSecLoop;
   7955                         } else {
   7956                             return UCOL_GREATER;
   7957                         }
   7958                     }
   7959                     tChar=target[--tIndex];
   7960                     tOrder = elements[tChar];
   7961                     // don't even look for contractions
   7962                 }
   7963                 if(endOfSource) {
   7964                     return UCOL_LESS;
   7965                 }
   7966 
   7967                 if(sOrder == tOrder) {
   7968                     sOrder = 0; tOrder = 0;
   7969                     continue;
   7970                 } else {
   7971                     // see the primary loop for comments
   7972                     if(((sOrder^tOrder)&0xFF000000)!=0) {
   7973                         if(sOrder < tOrder) {
   7974                             return UCOL_LESS;
   7975                         } else if(sOrder > tOrder) {
   7976                             return UCOL_GREATER;
   7977                         }
   7978                     }
   7979                     sOrder<<=8;
   7980                     tOrder<<=8;
   7981                 }
   7982             }
   7983         }
   7984     }
   7985 
   7986 endOfSecLoop:
   7987     if(strength >= UCOL_TERTIARY) {
   7988         // tertiary loop is the same as secondary (except no French)
   7989         elements += coll->latinOneTableLen;
   7990         sIndex = 0; tIndex = 0;
   7991         endOfSource = FALSE;
   7992         for(;;) {
   7993             while(sOrder==0) {
   7994                 if(sIndex==sLen) {
   7995                     endOfSource = TRUE;
   7996                     break;
   7997                 }
   7998                 sChar=source[sIndex++];
   7999                 sOrder = elements[sChar];
   8000                 if(sOrder > UCOL_NOT_FOUND) {
   8001                     sOrder = ucol_getLatinOneContraction(coll, UCOL_TERTIARY, sOrder, source, &sIndex, sLen);
   8002                 }
   8003             }
   8004             while(tOrder==0) {
   8005                 if(tIndex==tLen) {
   8006                     if(endOfSource) {
   8007                         return UCOL_EQUAL; // if both strings are at the end, they are equal
   8008                     } else {
   8009                         return UCOL_GREATER;
   8010                     }
   8011                 }
   8012                 tChar=target[tIndex++];
   8013                 tOrder = elements[tChar];
   8014                 if(tOrder > UCOL_NOT_FOUND) {
   8015                     tOrder = ucol_getLatinOneContraction(coll, UCOL_TERTIARY, tOrder, target, &tIndex, tLen);
   8016                 }
   8017             }
   8018             if(endOfSource) {
   8019                 return UCOL_LESS;
   8020             }
   8021             if(sOrder == tOrder) {
   8022                 sOrder = 0; tOrder = 0;
   8023                 continue;
   8024             } else {
   8025                 if(((sOrder^tOrder)&0xff000000)!=0) {
   8026                     if(sOrder < tOrder) {
   8027                         return UCOL_LESS;
   8028                     } else if(sOrder > tOrder) {
   8029                         return UCOL_GREATER;
   8030                     }
   8031                 }
   8032                 sOrder<<=8;
   8033                 tOrder<<=8;
   8034             }
   8035         }
   8036     }
   8037     return UCOL_EQUAL;
   8038 }
   8039 
   8040 /*
   8041   Note: ucol_strcollUTF8 supports null terminated input. Calculating length of
   8042   null terminated input string takes extra amount of CPU cycles.
   8043 */
   8044 static UCollationResult
   8045 ucol_strcollRegularUTF8(
   8046                     const UCollator *coll,
   8047                     const char      *source,
   8048                     int32_t         sourceLength,
   8049                     const char      *target,
   8050                     int32_t         targetLength,
   8051                     UErrorCode      *status)
   8052 {
   8053     UCharIterator src;
   8054     UCharIterator tgt;
   8055 
   8056     uiter_setUTF8(&src, source, sourceLength);
   8057     uiter_setUTF8(&tgt, target, targetLength);
   8058 
   8059     // Preparing the context objects for iterating over strings
   8060     collIterate sColl, tColl;
   8061     IInit_collIterate(coll, NULL, -1, &sColl, status);
   8062     IInit_collIterate(coll, NULL, -1, &tColl, status);
   8063     if(U_FAILURE(*status)) {
   8064         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status)
   8065         return UCOL_EQUAL;
   8066     }
   8067     // The division for the array length may truncate the array size to
   8068     // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
   8069     // for all platforms anyway.
   8070     UAlignedMemory stackNormIter1[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
   8071     UAlignedMemory stackNormIter2[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
   8072     UNormIterator *sNormIter = NULL, *tNormIter = NULL;
   8073 
   8074     sColl.iterator = &src;
   8075     sColl.flags |= UCOL_USE_ITERATOR;
   8076     tColl.flags |= UCOL_USE_ITERATOR;
   8077     tColl.iterator = &tgt;
   8078 
   8079     if(ucol_getAttribute(coll, UCOL_NORMALIZATION_MODE, status) == UCOL_ON) {
   8080         sNormIter = unorm_openIter(stackNormIter1, sizeof(stackNormIter1), status);
   8081         sColl.iterator = unorm_setIter(sNormIter, &src, UNORM_FCD, status);
   8082         sColl.flags &= ~UCOL_ITER_NORM;
   8083 
   8084         tNormIter = unorm_openIter(stackNormIter2, sizeof(stackNormIter2), status);
   8085         tColl.iterator = unorm_setIter(tNormIter, &tgt, UNORM_FCD, status);
   8086         tColl.flags &= ~UCOL_ITER_NORM;
   8087     }
   8088 
   8089     return ucol_strcollRegular(&sColl, &tColl, status);
   8090 }
   8091 
   8092 static inline uint32_t
   8093 ucol_getLatinOneContractionUTF8(const UCollator *coll, int32_t strength,
   8094                           uint32_t CE, const char *s, int32_t *index, int32_t len)
   8095 {
   8096     const UChar *UCharOffset = (UChar *)coll->image+getContractOffset(CE&0xFFF);
   8097     int32_t latinOneOffset = (CE & 0x00FFF000) >> 12;
   8098     int32_t offset = 1;
   8099     UChar32 schar = 0, tchar = 0;
   8100 
   8101     for(;;) {
   8102         if (*index == len) {
   8103             return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset]);
   8104         }
   8105         U8_GET_OR_FFFD((const uint8_t*)s, 0, *index, len, schar);
   8106         if (len < 0 && schar == 0) {
   8107             return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset]);
   8108         }
   8109 
   8110         while(schar > (tchar = *(UCharOffset+offset))) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
   8111             offset++;
   8112         }
   8113 
   8114         if (schar == tchar) {
   8115             U8_FWD_1(s, *index, len);
   8116             return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset+offset]);
   8117         }
   8118         else
   8119         {
   8120             if(schar & 0xFF00 /*> UCOL_ENDOFLATIN1RANGE*/) {
   8121                 return UCOL_BAIL_OUT_CE;
   8122             }
   8123             // skip completely ignorables
   8124             uint32_t isZeroCE = UTRIE_GET32_FROM_LEAD(&coll->mapping, schar);
   8125             if(isZeroCE == 0) { // we have to ignore completely ignorables
   8126                 U8_FWD_1(s, *index, len);
   8127                 continue;
   8128             }
   8129 
   8130             return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset]);
   8131         }
   8132     }
   8133 }
   8134 
   8135 static inline UCollationResult
   8136 ucol_strcollUseLatin1UTF8(
   8137                 const UCollator *coll,
   8138                 const char      *source,
   8139                 int32_t         sLen,
   8140                 const char      *target,
   8141                 int32_t         tLen,
   8142                 UErrorCode      *status)
   8143 {
   8144     U_ALIGN_CODE(16);
   8145     int32_t strength = coll->strength;
   8146 
   8147     int32_t sIndex = 0, tIndex = 0;
   8148     UChar32 sChar = 0, tChar = 0;
   8149     uint32_t sOrder=0, tOrder=0;
   8150 
   8151     UBool endOfSource = FALSE;
   8152 
   8153     uint32_t *elements = coll->latinOneCEs;
   8154 
   8155     UBool haveContractions = FALSE; // if we have contractions in our string
   8156                                     // we cannot do French secondary
   8157 
   8158     // Do the primary level
   8159     for(;;) {
   8160         while(sOrder==0) { // this loop skips primary ignorables
   8161             // sOrder=getNextlatinOneCE(source);
   8162             if (sIndex == sLen) {
   8163                 endOfSource = TRUE;
   8164                 break;
   8165             }
   8166             U8_NEXT_OR_FFFD(source, sIndex, sLen ,sChar);
   8167             if (sLen < 0 && sChar == 0) {
   8168                 endOfSource = TRUE;
   8169                 sLen = sIndex;
   8170                 break;
   8171             }
   8172             if(sChar&0xFFFFFF00) { // if we encounter non-latin-1, we bail out (sChar > 0xFF, but this is faster on win32)
   8173                 //fprintf(stderr, "R");
   8174                 return ucol_strcollRegularUTF8(coll, source, sLen, target, tLen, status);
   8175             }
   8176             sOrder = elements[sChar];
   8177             if(sOrder >= UCOL_NOT_FOUND) { // if we got a special
   8178                 // specials can basically be either contractions or bail-out signs. If we get anything
   8179                 // else, we'll bail out anywasy
   8180                 if(getCETag(sOrder) == CONTRACTION_TAG) {
   8181                     sOrder = ucol_getLatinOneContractionUTF8(coll, UCOL_PRIMARY, sOrder, source, &sIndex, sLen);
   8182                     haveContractions = TRUE; // if there are contractions, we cannot do French secondary
   8183                     // However, if there are contractions in the table, but we always use just one char,
   8184                     // we might be able to do French. This should be checked out.
   8185                 }
   8186                 if(sOrder >= UCOL_NOT_FOUND /*== UCOL_BAIL_OUT_CE*/) {
   8187                     //fprintf(stderr, "S");
   8188                     return ucol_strcollRegularUTF8(coll, source, sLen, target, tLen, status);
   8189                 }
   8190             }
   8191         }
   8192 
   8193         while(tOrder==0) {  // this loop skips primary ignorables
   8194             // tOrder=getNextlatinOneCE(target);
   8195             if (tIndex == tLen) {
   8196                 if(endOfSource) {
   8197                     goto endOfPrimLoopU8;
   8198                 } else {
   8199                     return UCOL_GREATER;
   8200                 }
   8201             }
   8202             U8_NEXT_OR_FFFD(target, tIndex, tLen, tChar);
   8203             if (tLen < 0 && tChar == 0) {
   8204                 if(endOfSource) {
   8205                     tLen = tIndex;
   8206                     goto endOfPrimLoopU8;
   8207                 } else {
   8208                     return UCOL_GREATER;
   8209                 }
   8210             }
   8211             if(tChar&0xFFFFFF00) { // if we encounter non-latin-1, we bail out (sChar > 0xFF, but this is faster on win32)
   8212                 //fprintf(stderr, "R");
   8213                 return ucol_strcollRegularUTF8(coll, source, sLen, target, tLen, status);
   8214             }
   8215             tOrder = elements[tChar];
   8216             if(tOrder >= UCOL_NOT_FOUND) {
   8217                 // Handling specials, see the comments for source
   8218                 if(getCETag(tOrder) == CONTRACTION_TAG) {
   8219                     tOrder = ucol_getLatinOneContractionUTF8(coll, UCOL_PRIMARY, tOrder, target, &tIndex, tLen);
   8220                     haveContractions = TRUE;
   8221                 }
   8222                 if(tOrder >= UCOL_NOT_FOUND /*== UCOL_BAIL_OUT_CE*/) {
   8223                     //fprintf(stderr, "S");
   8224                     return ucol_strcollRegularUTF8(coll, source, sLen, target, tLen, status);
   8225                 }
   8226             }
   8227         }
   8228         if(endOfSource) { // source is finished, but target is not, say the result.
   8229             return UCOL_LESS;
   8230         }
   8231 
   8232         if(sOrder == tOrder) { // if we have same CEs, we continue the loop
   8233             sOrder = 0; tOrder = 0;
   8234             continue;
   8235         } else {
   8236             // compare current top bytes
   8237             if(((sOrder^tOrder)&0xFF000000)!=0) {
   8238                 // top bytes differ, return difference
   8239                 if(sOrder < tOrder) {
   8240                     return UCOL_LESS;
   8241                 } else if(sOrder > tOrder) {
   8242                     return UCOL_GREATER;
   8243                 }
   8244                 // instead of return (int32_t)(sOrder>>24)-(int32_t)(tOrder>>24);
   8245                 // since we must return enum value
   8246             }
   8247 
   8248             // top bytes match, continue with following bytes
   8249             sOrder<<=8;
   8250             tOrder<<=8;
   8251         }
   8252     }
   8253 
   8254 endOfPrimLoopU8:
   8255     // after primary loop, we definitely know the sizes of strings,
   8256     // so we set it and use simpler loop for secondaries and tertiaries
   8257     sLen = sIndex; tLen = tIndex;
   8258     if(strength >= UCOL_SECONDARY) {
   8259         // adjust the table beggining
   8260         elements += coll->latinOneTableLen;
   8261         endOfSource = FALSE;
   8262 
   8263         if(coll->frenchCollation == UCOL_OFF) { // non French
   8264             // This loop is a simplified copy of primary loop
   8265             // at this point we know that whole strings are latin-1, so we don't
   8266             // check for that. We also know that we only have contractions as
   8267             // specials.
   8268             sIndex = 0; tIndex = 0;
   8269             for(;;) {
   8270                 while(sOrder==0) {
   8271                     if(sIndex==sLen) {
   8272                         endOfSource = TRUE;
   8273                         break;
   8274                     }
   8275                     U_ASSERT(sLen >= 0);
   8276                     U8_NEXT_OR_FFFD(source, sIndex, sLen, sChar);
   8277                     U_ASSERT(sChar >= 0 && sChar <= 0xFF);
   8278                     sOrder = elements[sChar];
   8279                     if(sOrder > UCOL_NOT_FOUND) {
   8280                         sOrder = ucol_getLatinOneContractionUTF8(coll, UCOL_SECONDARY, sOrder, source, &sIndex, sLen);
   8281                     }
   8282                 }
   8283 
   8284                 while(tOrder==0) {
   8285                     if(tIndex==tLen) {
   8286                         if(endOfSource) {
   8287                             goto endOfSecLoopU8;
   8288                         } else {
   8289                             return UCOL_GREATER;
   8290                         }
   8291                     }
   8292                     U_ASSERT(tLen >= 0);
   8293                     U8_NEXT_OR_FFFD(target, tIndex, tLen, tChar);
   8294                     U_ASSERT(tChar >= 0 && tChar <= 0xFF);
   8295                     tOrder = elements[tChar];
   8296                     if(tOrder > UCOL_NOT_FOUND) {
   8297                         tOrder = ucol_getLatinOneContractionUTF8(coll, UCOL_SECONDARY, tOrder, target, &tIndex, tLen);
   8298                     }
   8299                 }
   8300                 if(endOfSource) {
   8301                     return UCOL_LESS;
   8302                 }
   8303 
   8304                 if(sOrder == tOrder) {
   8305                     sOrder = 0; tOrder = 0;
   8306                     continue;
   8307                 } else {
   8308                     // see primary loop for comments on this
   8309                     if(((sOrder^tOrder)&0xFF000000)!=0) {
   8310                         if(sOrder < tOrder) {
   8311                             return UCOL_LESS;
   8312                         } else if(sOrder > tOrder) {
   8313                             return UCOL_GREATER;
   8314                         }
   8315                     }
   8316                     sOrder<<=8;
   8317                     tOrder<<=8;
   8318                 }
   8319             }
   8320         } else { // French
   8321             if(haveContractions) { // if we have contractions, we have to bail out
   8322                 // since we don't really know how to handle them here
   8323                 return ucol_strcollRegularUTF8(coll, source, sLen, target, tLen, status);
   8324             }
   8325             // For French, we go backwards
   8326             sIndex = sLen; tIndex = tLen;
   8327             for(;;) {
   8328                 while(sOrder==0) {
   8329                     if(sIndex==0) {
   8330                         endOfSource = TRUE;
   8331                         break;
   8332                     }
   8333                     U8_PREV_OR_FFFD(source, 0, sIndex, sChar);
   8334                     U_ASSERT(sChar >= 0 && sChar <= 0xFF);
   8335                     sOrder = elements[sChar];
   8336                     // don't even look for contractions
   8337                 }
   8338 
   8339                 while(tOrder==0) {
   8340                     if(tIndex==0) {
   8341                         if(endOfSource) {
   8342                             goto endOfSecLoopU8;
   8343                         } else {
   8344                             return UCOL_GREATER;
   8345                         }
   8346                     }
   8347                     U8_PREV_OR_FFFD(target, 0, tIndex, tChar);
   8348                     U_ASSERT(tChar >= 0 && tChar <= 0xFF);
   8349                     tOrder = elements[tChar];
   8350                     // don't even look for contractions
   8351                 }
   8352                 if(endOfSource) {
   8353                     return UCOL_LESS;
   8354                 }
   8355 
   8356                 if(sOrder == tOrder) {
   8357                     sOrder = 0; tOrder = 0;
   8358                     continue;
   8359                 } else {
   8360                     // see the primary loop for comments
   8361                     if(((sOrder^tOrder)&0xFF000000)!=0) {
   8362                         if(sOrder < tOrder) {
   8363                             return UCOL_LESS;
   8364                         } else if(sOrder > tOrder) {
   8365                             return UCOL_GREATER;
   8366                         }
   8367                     }
   8368                     sOrder<<=8;
   8369                     tOrder<<=8;
   8370                 }
   8371             }
   8372         }
   8373     }
   8374 
   8375 endOfSecLoopU8:
   8376     if(strength >= UCOL_TERTIARY) {
   8377         // tertiary loop is the same as secondary (except no French)
   8378         elements += coll->latinOneTableLen;
   8379         sIndex = 0; tIndex = 0;
   8380         endOfSource = FALSE;
   8381         for(;;) {
   8382             while(sOrder==0) {
   8383                 if(sIndex==sLen) {
   8384                     endOfSource = TRUE;
   8385                     break;
   8386                 }
   8387                 U_ASSERT(sLen >= 0);
   8388                 U8_NEXT_OR_FFFD(source, sIndex, sLen, sChar);
   8389                 U_ASSERT(sChar >= 0 && sChar <= 0xFF);
   8390                 sOrder = elements[sChar];
   8391                 if(sOrder > UCOL_NOT_FOUND) {
   8392                     sOrder = ucol_getLatinOneContractionUTF8(coll, UCOL_TERTIARY, sOrder, source, &sIndex, sLen);
   8393                 }
   8394             }
   8395             while(tOrder==0) {
   8396                 if(tIndex==tLen) {
   8397                     if(endOfSource) {
   8398                         return UCOL_EQUAL; // if both strings are at the end, they are equal
   8399                     } else {
   8400                         return UCOL_GREATER;
   8401                     }
   8402                 }
   8403                 U_ASSERT(tLen >= 0);
   8404                 U8_NEXT_OR_FFFD(target, tIndex, tLen, tChar);
   8405                 U_ASSERT(tChar >= 0 && tChar <= 0xFF);
   8406                 tOrder = elements[tChar];
   8407                 if(tOrder > UCOL_NOT_FOUND) {
   8408                     tOrder = ucol_getLatinOneContractionUTF8(coll, UCOL_TERTIARY, tOrder, target, &tIndex, tLen);
   8409                 }
   8410             }
   8411             if(endOfSource) {
   8412                 return UCOL_LESS;
   8413             }
   8414             if(sOrder == tOrder) {
   8415                 sOrder = 0; tOrder = 0;
   8416                 continue;
   8417             } else {
   8418                 if(((sOrder^tOrder)&0xff000000)!=0) {
   8419                     if(sOrder < tOrder) {
   8420                         return UCOL_LESS;
   8421                     } else if(sOrder > tOrder) {
   8422                         return UCOL_GREATER;
   8423                     }
   8424                 }
   8425                 sOrder<<=8;
   8426                 tOrder<<=8;
   8427             }
   8428         }
   8429     }
   8430     return UCOL_EQUAL;
   8431 }
   8432 
   8433 U_CAPI UCollationResult U_EXPORT2
   8434 ucol_strcollIter( const UCollator    *coll,
   8435                  UCharIterator *sIter,
   8436                  UCharIterator *tIter,
   8437                  UErrorCode         *status)
   8438 {
   8439     if(!status || U_FAILURE(*status)) {
   8440         return UCOL_EQUAL;
   8441     }
   8442 
   8443     UTRACE_ENTRY(UTRACE_UCOL_STRCOLLITER);
   8444     UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, sIter=%p, tIter=%p", coll, sIter, tIter);
   8445 
   8446     if (sIter == tIter) {
   8447         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status)
   8448         return UCOL_EQUAL;
   8449     }
   8450     if(sIter == NULL || tIter == NULL || coll == NULL) {
   8451         *status = U_ILLEGAL_ARGUMENT_ERROR;
   8452         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status)
   8453         return UCOL_EQUAL;
   8454     }
   8455 
   8456     UCollationResult result = UCOL_EQUAL;
   8457 
   8458     // Preparing the context objects for iterating over strings
   8459     collIterate sColl, tColl;
   8460     IInit_collIterate(coll, NULL, -1, &sColl, status);
   8461     IInit_collIterate(coll, NULL, -1, &tColl, status);
   8462     if(U_FAILURE(*status)) {
   8463         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status)
   8464         return UCOL_EQUAL;
   8465     }
   8466     // The division for the array length may truncate the array size to
   8467     // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
   8468     // for all platforms anyway.
   8469     UAlignedMemory stackNormIter1[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
   8470     UAlignedMemory stackNormIter2[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
   8471     UNormIterator *sNormIter = NULL, *tNormIter = NULL;
   8472 
   8473     sColl.iterator = sIter;
   8474     sColl.flags |= UCOL_USE_ITERATOR;
   8475     tColl.flags |= UCOL_USE_ITERATOR;
   8476     tColl.iterator = tIter;
   8477 
   8478     if(ucol_getAttribute(coll, UCOL_NORMALIZATION_MODE, status) == UCOL_ON) {
   8479         sNormIter = unorm_openIter(stackNormIter1, sizeof(stackNormIter1), status);
   8480         sColl.iterator = unorm_setIter(sNormIter, sIter, UNORM_FCD, status);
   8481         sColl.flags &= ~UCOL_ITER_NORM;
   8482 
   8483         tNormIter = unorm_openIter(stackNormIter2, sizeof(stackNormIter2), status);
   8484         tColl.iterator = unorm_setIter(tNormIter, tIter, UNORM_FCD, status);
   8485         tColl.flags &= ~UCOL_ITER_NORM;
   8486     }
   8487 
   8488     UChar32 sChar = U_SENTINEL, tChar = U_SENTINEL;
   8489 
   8490     while((sChar = sColl.iterator->next(sColl.iterator)) ==
   8491         (tChar = tColl.iterator->next(tColl.iterator))) {
   8492             if(sChar == U_SENTINEL) {
   8493                 result = UCOL_EQUAL;
   8494                 goto end_compare;
   8495             }
   8496     }
   8497 
   8498     if(sChar == U_SENTINEL) {
   8499         tChar = tColl.iterator->previous(tColl.iterator);
   8500     }
   8501 
   8502     if(tChar == U_SENTINEL) {
   8503         sChar = sColl.iterator->previous(sColl.iterator);
   8504     }
   8505 
   8506     sChar = sColl.iterator->previous(sColl.iterator);
   8507     tChar = tColl.iterator->previous(tColl.iterator);
   8508 
   8509     if (ucol_unsafeCP((UChar)sChar, coll) || ucol_unsafeCP((UChar)tChar, coll))
   8510     {
   8511         // We are stopped in the middle of a contraction.
   8512         // Scan backwards through the == part of the string looking for the start of the contraction.
   8513         //   It doesn't matter which string we scan, since they are the same in this region.
   8514         do
   8515         {
   8516             sChar = sColl.iterator->previous(sColl.iterator);
   8517             tChar = tColl.iterator->previous(tColl.iterator);
   8518         }
   8519         while (sChar != U_SENTINEL && ucol_unsafeCP((UChar)sChar, coll));
   8520     }
   8521 
   8522 
   8523     if(U_SUCCESS(*status)) {
   8524         result = ucol_strcollRegular(&sColl, &tColl, status);
   8525     }
   8526 
   8527 end_compare:
   8528     if(sNormIter || tNormIter) {
   8529         unorm_closeIter(sNormIter);
   8530         unorm_closeIter(tNormIter);
   8531     }
   8532 
   8533     UTRACE_EXIT_VALUE_STATUS(result, *status)
   8534     return result;
   8535 }
   8536 
   8537 
   8538 /*                                                                      */
   8539 /* ucol_strcoll     Main public API string comparison function          */
   8540 /*                                                                      */
   8541 U_CAPI UCollationResult U_EXPORT2
   8542 ucol_strcoll( const UCollator    *coll,
   8543               const UChar        *source,
   8544               int32_t            sourceLength,
   8545               const UChar        *target,
   8546               int32_t            targetLength)
   8547 {
   8548     U_ALIGN_CODE(16);
   8549 
   8550     UTRACE_ENTRY(UTRACE_UCOL_STRCOLL);
   8551     if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
   8552         UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source=%p, target=%p", coll, source, target);
   8553         UTRACE_DATA2(UTRACE_VERBOSE, "source string = %vh ", source, sourceLength);
   8554         UTRACE_DATA2(UTRACE_VERBOSE, "target string = %vh ", target, targetLength);
   8555     }
   8556 
   8557     if(source == NULL || target == NULL) {
   8558         // do not crash, but return. Should have
   8559         // status argument to return error.
   8560         UTRACE_EXIT_VALUE(UCOL_EQUAL);
   8561         return UCOL_EQUAL;
   8562     }
   8563 
   8564     /* Quick check if source and target are same strings. */
   8565     /* They should either both be NULL terminated or the explicit length should be set on both. */
   8566     if (source==target && sourceLength==targetLength) {
   8567         UTRACE_EXIT_VALUE(UCOL_EQUAL);
   8568         return UCOL_EQUAL;
   8569     }
   8570 
   8571     if(coll->delegate != NULL) {
   8572       UErrorCode status = U_ZERO_ERROR;
   8573       return ((const Collator*)coll->delegate)->compare(source,sourceLength,target,targetLength, status);
   8574     }
   8575 
   8576     /* Scan the strings.  Find:                                                             */
   8577     /*    The length of any leading portion that is equal                                   */
   8578     /*    Whether they are exactly equal.  (in which case we just return)                   */
   8579     const UChar    *pSrc    = source;
   8580     const UChar    *pTarg   = target;
   8581     int32_t        equalLength;
   8582 
   8583     if (sourceLength == -1 && targetLength == -1) {
   8584         // Both strings are null terminated.
   8585         //    Scan through any leading equal portion.
   8586         while (*pSrc == *pTarg && *pSrc != 0) {
   8587             pSrc++;
   8588             pTarg++;
   8589         }
   8590         if (*pSrc == 0 && *pTarg == 0) {
   8591             UTRACE_EXIT_VALUE(UCOL_EQUAL);
   8592             return UCOL_EQUAL;
   8593         }
   8594         equalLength = (int32_t)(pSrc - source);
   8595     }
   8596     else
   8597     {
   8598         // One or both strings has an explicit length.
   8599         const UChar    *pSrcEnd = source + sourceLength;
   8600         const UChar    *pTargEnd = target + targetLength;
   8601 
   8602         // Scan while the strings are bitwise ==, or until one is exhausted.
   8603         for (;;) {
   8604             if (pSrc == pSrcEnd || pTarg == pTargEnd) {
   8605                 break;
   8606             }
   8607             if ((*pSrc == 0 && sourceLength == -1) || (*pTarg == 0 && targetLength == -1)) {
   8608                 break;
   8609             }
   8610             if (*pSrc != *pTarg) {
   8611                 break;
   8612             }
   8613             pSrc++;
   8614             pTarg++;
   8615         }
   8616         equalLength = (int32_t)(pSrc - source);
   8617 
   8618         // If we made it all the way through both strings, we are done.  They are ==
   8619         if ((pSrc ==pSrcEnd  || (pSrcEnd <pSrc  && *pSrc==0))  &&   /* At end of src string, however it was specified. */
   8620             (pTarg==pTargEnd || (pTargEnd<pTarg && *pTarg==0)))     /* and also at end of dest string                  */
   8621         {
   8622             UTRACE_EXIT_VALUE(UCOL_EQUAL);
   8623             return UCOL_EQUAL;
   8624         }
   8625     }
   8626     if (equalLength > 0) {
   8627         /* There is an identical portion at the beginning of the two strings.        */
   8628         /*   If the identical portion ends within a contraction or a comibining      */
   8629         /*   character sequence, back up to the start of that sequence.              */
   8630 
   8631         // These values should already be set by the code above.
   8632         //pSrc  = source + equalLength;        /* point to the first differing chars   */
   8633         //pTarg = target + equalLength;
   8634         if ((pSrc  != source+sourceLength && ucol_unsafeCP(*pSrc, coll)) ||
   8635             (pTarg != target+targetLength && ucol_unsafeCP(*pTarg, coll)))
   8636         {
   8637             // We are stopped in the middle of a contraction.
   8638             // Scan backwards through the == part of the string looking for the start of the contraction.
   8639             //   It doesn't matter which string we scan, since they are the same in this region.
   8640             do
   8641             {
   8642                 equalLength--;
   8643                 pSrc--;
   8644             }
   8645             while (equalLength>0 && ucol_unsafeCP(*pSrc, coll));
   8646         }
   8647 
   8648         source += equalLength;
   8649         target += equalLength;
   8650         if (sourceLength > 0) {
   8651             sourceLength -= equalLength;
   8652         }
   8653         if (targetLength > 0) {
   8654             targetLength -= equalLength;
   8655         }
   8656     }
   8657 
   8658     UErrorCode status = U_ZERO_ERROR;
   8659     UCollationResult returnVal;
   8660     if(!coll->latinOneUse || (sourceLength > 0 && *source&0xff00) || (targetLength > 0 && *target&0xff00)) {
   8661         returnVal = ucol_strcollRegular(coll, source, sourceLength, target, targetLength, &status);
   8662     } else {
   8663         returnVal = ucol_strcollUseLatin1(coll, source, sourceLength, target, targetLength, &status);
   8664     }
   8665     UTRACE_EXIT_VALUE(returnVal);
   8666     return returnVal;
   8667 }
   8668 
   8669 U_CAPI UCollationResult U_EXPORT2
   8670 ucol_strcollUTF8(
   8671         const UCollator *coll,
   8672         const char      *source,
   8673         int32_t         sourceLength,
   8674         const char      *target,
   8675         int32_t         targetLength,
   8676         UErrorCode      *status)
   8677 {
   8678     U_ALIGN_CODE(16);
   8679 
   8680     UTRACE_ENTRY(UTRACE_UCOL_STRCOLLUTF8);
   8681     if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
   8682         UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source=%p, target=%p", coll, source, target);
   8683         UTRACE_DATA2(UTRACE_VERBOSE, "source string = %vb ", source, sourceLength);
   8684         UTRACE_DATA2(UTRACE_VERBOSE, "target string = %vb ", target, targetLength);
   8685     }
   8686 
   8687     if (U_FAILURE(*status)) {
   8688         /* do nothing */
   8689         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status);
   8690         return UCOL_EQUAL;
   8691     }
   8692 
   8693     if(source == NULL || target == NULL) {
   8694         *status = U_ILLEGAL_ARGUMENT_ERROR;
   8695         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status);
   8696         return UCOL_EQUAL;
   8697     }
   8698 
   8699     /* Quick check if source and target are same strings. */
   8700     /* They should either both be NULL terminated or the explicit length should be set on both. */
   8701     if (source==target && sourceLength==targetLength) {
   8702         UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status);
   8703         return UCOL_EQUAL;
   8704     }
   8705 
   8706     if(coll->delegate != NULL) {
   8707         return ((const Collator*)coll->delegate)->compareUTF8(
   8708             StringPiece(source, (sourceLength < 0) ? uprv_strlen(source) : sourceLength),
   8709             StringPiece(target, (targetLength < 0) ? uprv_strlen(target) : targetLength),
   8710             *status);
   8711     }
   8712 
   8713     /* Scan the strings.  Find:                                                             */
   8714     /*    The length of any leading portion that is equal                                   */
   8715     /*    Whether they are exactly equal.  (in which case we just return)                   */
   8716     const char  *pSrc = source;
   8717     const char  *pTarg = target;
   8718     UBool       bSrcLimit = FALSE;
   8719     UBool       bTargLimit = FALSE;
   8720 
   8721     if (sourceLength == -1 && targetLength == -1) {
   8722         // Both strings are null terminated.
   8723         //    Scan through any leading equal portion.
   8724         while (*pSrc == *pTarg && *pSrc != 0) {
   8725             pSrc++;
   8726             pTarg++;
   8727         }
   8728         if (*pSrc == 0 && *pTarg == 0) {
   8729             UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status);
   8730             return UCOL_EQUAL;
   8731         }
   8732         bSrcLimit = (*pSrc == 0);
   8733         bTargLimit = (*pTarg == 0);
   8734     }
   8735     else
   8736     {
   8737         // One or both strings has an explicit length.
   8738         const char *pSrcEnd = source + sourceLength;
   8739         const char *pTargEnd = target + targetLength;
   8740 
   8741         // Scan while the strings are bitwise ==, or until one is exhausted.
   8742         for (;;) {
   8743             if (pSrc == pSrcEnd || pTarg == pTargEnd) {
   8744                 break;
   8745             }
   8746             if ((*pSrc == 0 && sourceLength == -1) || (*pTarg == 0 && targetLength == -1)) {
   8747                 break;
   8748             }
   8749             if (*pSrc != *pTarg) {
   8750                 break;
   8751             }
   8752             pSrc++;
   8753             pTarg++;
   8754         }
   8755         bSrcLimit = (pSrc ==pSrcEnd  || (pSrcEnd <pSrc  && *pSrc==0));
   8756         bTargLimit = (pTarg==pTargEnd || (pTargEnd<pTarg && *pTarg==0));
   8757 
   8758         // If we made it all the way through both strings, we are done.  They are ==
   8759         if (bSrcLimit &&    /* At end of src string, however it was specified. */
   8760             bTargLimit)     /* and also at end of dest string                  */
   8761         {
   8762             UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status);
   8763             return UCOL_EQUAL;
   8764         }
   8765     }
   8766 
   8767     U_ASSERT(!(bSrcLimit && bTargLimit));
   8768 
   8769     int32_t    equalLength = pSrc - source;
   8770     UBool       bSawNonLatin1 = FALSE;
   8771 
   8772     if (equalLength > 0) {
   8773         // Align position to the start of UTF-8 code point.
   8774         if (bTargLimit) {
   8775             U8_SET_CP_START((const uint8_t*)source, 0, equalLength);
   8776         } else {
   8777             U8_SET_CP_START((const uint8_t*)target, 0, equalLength);
   8778         }
   8779         pSrc = source + equalLength;
   8780         pTarg = target + equalLength;
   8781     }
   8782 
   8783     if (equalLength > 0) {
   8784         /* There is an identical portion at the beginning of the two strings.        */
   8785         /*   If the identical portion ends within a contraction or a comibining      */
   8786         /*   character sequence, back up to the start of that sequence.              */
   8787         UBool bUnsafeCP = FALSE;
   8788         UChar32 uc32 = -1;
   8789 
   8790         if (!bSrcLimit) {
   8791             U8_GET_OR_FFFD((const uint8_t*)source, 0, equalLength, sourceLength, uc32);
   8792             if (uc32 >= 0x10000 || ucol_unsafeCP((UChar)uc32, coll)) {
   8793                 bUnsafeCP = TRUE;
   8794             }
   8795             bSawNonLatin1 |= (uc32 > 0xff);
   8796         }
   8797         if (!bTargLimit) {
   8798             U8_GET_OR_FFFD((const uint8_t*)target, 0, equalLength, targetLength, uc32);
   8799             if (uc32 >= 0x10000 || ucol_unsafeCP((UChar)uc32, coll)) {
   8800                 bUnsafeCP = TRUE;
   8801             }
   8802             bSawNonLatin1 |= (uc32 > 0xff);
   8803         }
   8804 
   8805         if (bUnsafeCP) {
   8806             while (equalLength > 0) {
   8807                 // We are stopped in the middle of a contraction.
   8808                 // Scan backwards through the == part of the string looking for the start of the contraction.
   8809                 //   It doesn't matter which string we scan, since they are the same in this region.
   8810                 U8_PREV_OR_FFFD((uint8_t*)source, 0, equalLength, uc32);
   8811                 bSawNonLatin1 |= (uc32 > 0xff);
   8812                 if (uc32 < 0x10000 && !ucol_unsafeCP((UChar)uc32, coll)) {
   8813                     break;
   8814                 }
   8815             }
   8816         }
   8817         source += equalLength;
   8818         target += equalLength;
   8819         if (sourceLength > 0) {
   8820             sourceLength -= equalLength;
   8821         }
   8822         if (targetLength > 0) {
   8823             targetLength -= equalLength;
   8824         }
   8825     } else {
   8826         // Lead byte of Latin 1 character is 0x00 - 0xC3
   8827         bSawNonLatin1 = (source && (sourceLength != 0) && (uint8_t)*source > 0xc3);
   8828         bSawNonLatin1 |= (target && (targetLength != 0) && (uint8_t)*target > 0xc3);
   8829     }
   8830 
   8831     UCollationResult returnVal;
   8832 
   8833     if(!coll->latinOneUse || bSawNonLatin1) {
   8834         returnVal = ucol_strcollRegularUTF8(coll, source, sourceLength, target, targetLength, status);
   8835     } else {
   8836         returnVal = ucol_strcollUseLatin1UTF8(coll, source, sourceLength, target, targetLength, status);
   8837     }
   8838     UTRACE_EXIT_VALUE_STATUS(returnVal, *status);
   8839     return returnVal;
   8840 }
   8841 
   8842 
   8843 /* convenience function for comparing strings */
   8844 U_CAPI UBool U_EXPORT2
   8845 ucol_greater(    const    UCollator        *coll,
   8846         const    UChar            *source,
   8847         int32_t            sourceLength,
   8848         const    UChar            *target,
   8849         int32_t            targetLength)
   8850 {
   8851     return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
   8852         == UCOL_GREATER);
   8853 }
   8854 
   8855 /* convenience function for comparing strings */
   8856 U_CAPI UBool U_EXPORT2
   8857 ucol_greaterOrEqual(    const    UCollator    *coll,
   8858             const    UChar        *source,
   8859             int32_t        sourceLength,
   8860             const    UChar        *target,
   8861             int32_t        targetLength)
   8862 {
   8863     return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
   8864         != UCOL_LESS);
   8865 }
   8866 
   8867 /* convenience function for comparing strings */
   8868 U_CAPI UBool U_EXPORT2
   8869 ucol_equal(        const    UCollator        *coll,
   8870             const    UChar            *source,
   8871             int32_t            sourceLength,
   8872             const    UChar            *target,
   8873             int32_t            targetLength)
   8874 {
   8875     return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
   8876         == UCOL_EQUAL);
   8877 }
   8878 
   8879 U_CAPI void U_EXPORT2
   8880 ucol_getUCAVersion(const UCollator* coll, UVersionInfo info) {
   8881     if(coll && coll->UCA) {
   8882         uprv_memcpy(info, coll->UCA->image->UCAVersion, sizeof(UVersionInfo));
   8883     }
   8884 }
   8885 
   8886 #endif /* #if !UCONFIG_NO_COLLATION */
   8887