intl/icu/source/i18n/ucol_res.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/i18n/ucol_res.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1384 @@
     1.4 +/*
     1.5 +*******************************************************************************
     1.6 +*   Copyright (C) 1996-2013, International Business Machines
     1.7 +*   Corporation and others.  All Rights Reserved.
     1.8 +*******************************************************************************
     1.9 +*   file name:  ucol_res.cpp
    1.10 +*   encoding:   US-ASCII
    1.11 +*   tab size:   8 (not used)
    1.12 +*   indentation:4
    1.13 +*
    1.14 +* Description:
    1.15 +* This file contains dependencies that the collation run-time doesn't normally
    1.16 +* need. This mainly contains resource bundle usage and collation meta information
    1.17 +*
    1.18 +* Modification history
    1.19 +* Date        Name      Comments
    1.20 +* 1996-1999   various members of ICU team maintained C API for collation framework
    1.21 +* 02/16/2001  synwee    Added internal method getPrevSpecialCE
    1.22 +* 03/01/2001  synwee    Added maxexpansion functionality.
    1.23 +* 03/16/2001  weiv      Collation framework is rewritten in C and made UCA compliant
    1.24 +* 12/08/2004  grhoten   Split part of ucol.cpp into ucol_res.cpp
    1.25 +*/
    1.26 +
    1.27 +#include "unicode/utypes.h"
    1.28 +
    1.29 +#if !UCONFIG_NO_COLLATION
    1.30 +#include "unicode/uloc.h"
    1.31 +#include "unicode/coll.h"
    1.32 +#include "unicode/tblcoll.h"
    1.33 +#include "unicode/caniter.h"
    1.34 +#include "unicode/uscript.h"
    1.35 +#include "unicode/ustring.h"
    1.36 +
    1.37 +#include "ucol_bld.h"
    1.38 +#include "ucol_imp.h"
    1.39 +#include "ucol_tok.h"
    1.40 +#include "ucol_elm.h"
    1.41 +#include "uresimp.h"
    1.42 +#include "ustr_imp.h"
    1.43 +#include "cstring.h"
    1.44 +#include "umutex.h"
    1.45 +#include "ucln_in.h"
    1.46 +#include "ustrenum.h"
    1.47 +#include "putilimp.h"
    1.48 +#include "utracimp.h"
    1.49 +#include "cmemory.h"
    1.50 +#include "uassert.h"
    1.51 +#include "uenumimp.h"
    1.52 +#include "ulist.h"
    1.53 +
    1.54 +U_NAMESPACE_USE
    1.55 +
    1.56 +static void ucol_setReorderCodesFromParser(UCollator *coll, UColTokenParser *parser, UErrorCode *status);
    1.57 +
    1.58 +// static UCA. There is only one. Collators don't use it.
    1.59 +// It is referenced only in ucol_initUCA and ucol_cleanup
    1.60 +static UCollator* _staticUCA = NULL;
    1.61 +static icu::UInitOnce gStaticUCAInitOnce = U_INITONCE_INITIALIZER;
    1.62 +// static pointer to udata memory. Inited in ucol_initUCA
    1.63 +// used for cleanup in ucol_cleanup
    1.64 +static UDataMemory* UCA_DATA_MEM = NULL;
    1.65 +
    1.66 +U_CDECL_BEGIN
    1.67 +static UBool U_CALLCONV
    1.68 +ucol_res_cleanup(void)
    1.69 +{
    1.70 +    if (UCA_DATA_MEM) {
    1.71 +        udata_close(UCA_DATA_MEM);
    1.72 +        UCA_DATA_MEM = NULL;
    1.73 +    }
    1.74 +    if (_staticUCA) {
    1.75 +        ucol_close(_staticUCA);
    1.76 +        _staticUCA = NULL;
    1.77 +    }
    1.78 +    gStaticUCAInitOnce.reset();
    1.79 +    return TRUE;
    1.80 +}
    1.81 +
    1.82 +static UBool U_CALLCONV
    1.83 +isAcceptableUCA(void * /*context*/,
    1.84 +             const char * /*type*/, const char * /*name*/,
    1.85 +             const UDataInfo *pInfo){
    1.86 +  /* context, type & name are intentionally not used */
    1.87 +    if( pInfo->size>=20 &&
    1.88 +        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
    1.89 +        pInfo->charsetFamily==U_CHARSET_FAMILY &&
    1.90 +        pInfo->dataFormat[0]==UCA_DATA_FORMAT_0 &&   /* dataFormat="UCol" */
    1.91 +        pInfo->dataFormat[1]==UCA_DATA_FORMAT_1 &&
    1.92 +        pInfo->dataFormat[2]==UCA_DATA_FORMAT_2 &&
    1.93 +        pInfo->dataFormat[3]==UCA_DATA_FORMAT_3 &&
    1.94 +        pInfo->formatVersion[0]==UCA_FORMAT_VERSION_0
    1.95 +#if UCA_FORMAT_VERSION_1!=0
    1.96 +        && pInfo->formatVersion[1]>=UCA_FORMAT_VERSION_1
    1.97 +#endif
    1.98 +        //pInfo->formatVersion[1]==UCA_FORMAT_VERSION_1 &&
    1.99 +        //pInfo->formatVersion[2]==UCA_FORMAT_VERSION_2 && // Too harsh
   1.100 +        //pInfo->formatVersion[3]==UCA_FORMAT_VERSION_3 && // Too harsh
   1.101 +        ) {
   1.102 +        return TRUE;
   1.103 +        // Note: In ICU 51 and earlier,
   1.104 +        // we used to check that the UCA data version (pInfo->dataVersion)
   1.105 +        // matches the UCD version (u_getUnicodeVersion())
   1.106 +        // but that complicated version updates, and
   1.107 +        // a mismatch is "only" a problem for handling canonical equivalence.
   1.108 +        // It need not be a fatal error.
   1.109 +    } else {
   1.110 +        return FALSE;
   1.111 +    }
   1.112 +}
   1.113 +U_CDECL_END
   1.114 +
   1.115 +static void U_CALLCONV ucol_initStaticUCA(UErrorCode &status) {
   1.116 +    U_ASSERT(_staticUCA == NULL);
   1.117 +    U_ASSERT(UCA_DATA_MEM == NULL);
   1.118 +    ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup);
   1.119 +
   1.120 +    UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, UCA_DATA_TYPE, UCA_DATA_NAME, isAcceptableUCA, NULL, &status);
   1.121 +    if(U_FAILURE(status)){
   1.122 +        udata_close(result);
   1.123 +        return;
   1.124 +    }
   1.125 +
   1.126 +    _staticUCA = ucol_initCollator((const UCATableHeader *)udata_getMemory(result), NULL, NULL, &status);
   1.127 +    if(U_SUCCESS(status)){
   1.128 +        // Initalize variables for implicit generation
   1.129 +        uprv_uca_initImplicitConstants(&status);
   1.130 +        UCA_DATA_MEM = result;
   1.131 +
   1.132 +    }else{
   1.133 +        ucol_close(_staticUCA);
   1.134 +        _staticUCA = NULL;
   1.135 +        udata_close(result);
   1.136 +    }
   1.137 +}
   1.138 +
   1.139 +
   1.140 +/* do not close UCA returned by ucol_initUCA! */
   1.141 +UCollator *
   1.142 +ucol_initUCA(UErrorCode *status) {
   1.143 +    umtx_initOnce(gStaticUCAInitOnce, &ucol_initStaticUCA, *status);
   1.144 +    return _staticUCA;
   1.145 +}
   1.146 +
   1.147 +U_CAPI void U_EXPORT2
   1.148 +ucol_forgetUCA(void)
   1.149 +{
   1.150 +    _staticUCA = NULL;
   1.151 +    UCA_DATA_MEM = NULL;
   1.152 +    gStaticUCAInitOnce.reset();
   1.153 +}
   1.154 +
   1.155 +/****************************************************************************/
   1.156 +/* Following are the open/close functions                                   */
   1.157 +/*                                                                          */
   1.158 +/****************************************************************************/
   1.159 +static UCollator*
   1.160 +tryOpeningFromRules(UResourceBundle *collElem, UErrorCode *status) {
   1.161 +    int32_t rulesLen = 0;
   1.162 +    const UChar *rules = ures_getStringByKey(collElem, "Sequence", &rulesLen, status);
   1.163 +    return ucol_openRules(rules, rulesLen, UCOL_DEFAULT, UCOL_DEFAULT, NULL, status);
   1.164 +}
   1.165 +
   1.166 +
   1.167 +// API in ucol_imp.h
   1.168 +
   1.169 +U_CFUNC UCollator*
   1.170 +ucol_open_internal(const char *loc,
   1.171 +                   UErrorCode *status)
   1.172 +{
   1.173 +    UErrorCode intStatus = U_ZERO_ERROR;
   1.174 +    const UCollator* UCA = ucol_initUCA(status);
   1.175 +
   1.176 +    /* New version */
   1.177 +    if(U_FAILURE(*status)) return 0;
   1.178 +
   1.179 +
   1.180 +
   1.181 +    UCollator *result = NULL;
   1.182 +    UResourceBundle *b = ures_open(U_ICUDATA_COLL, loc, status);
   1.183 +
   1.184 +    /* we try to find stuff from keyword */
   1.185 +    UResourceBundle *collations = ures_getByKey(b, "collations", NULL, status);
   1.186 +    UResourceBundle *collElem = NULL;
   1.187 +    char keyBuffer[256];
   1.188 +    // if there is a keyword, we pick it up and try to get elements
   1.189 +    if(!uloc_getKeywordValue(loc, "collation", keyBuffer, 256, status) ||
   1.190 +        !uprv_strcmp(keyBuffer,"default")) { /* Treat 'zz@collation=default' as 'zz'. */
   1.191 +        // no keyword. we try to find the default setting, which will give us the keyword value
   1.192 +        intStatus = U_ZERO_ERROR;
   1.193 +        // finding default value does not affect collation fallback status
   1.194 +        UResourceBundle *defaultColl = ures_getByKeyWithFallback(collations, "default", NULL, &intStatus);
   1.195 +        if(U_SUCCESS(intStatus)) {
   1.196 +            int32_t defaultKeyLen = 0;
   1.197 +            const UChar *defaultKey = ures_getString(defaultColl, &defaultKeyLen, &intStatus);
   1.198 +            u_UCharsToChars(defaultKey, keyBuffer, defaultKeyLen);
   1.199 +            keyBuffer[defaultKeyLen] = 0;
   1.200 +        } else {
   1.201 +            *status = U_INTERNAL_PROGRAM_ERROR;
   1.202 +            return NULL;
   1.203 +        }
   1.204 +        ures_close(defaultColl);
   1.205 +    }
   1.206 +    collElem = ures_getByKeyWithFallback(collations, keyBuffer, collations, status);
   1.207 +    collations = NULL; // We just reused the collations object as collElem.
   1.208 +
   1.209 +    UResourceBundle *binary = NULL;
   1.210 +    UResourceBundle *reorderRes = NULL;
   1.211 +    
   1.212 +    if(*status == U_MISSING_RESOURCE_ERROR) { /* We didn't find the tailoring data, we fallback to the UCA */
   1.213 +        *status = U_USING_DEFAULT_WARNING;
   1.214 +        result = ucol_initCollator(UCA->image, result, UCA, status);
   1.215 +        if (U_FAILURE(*status)) {
   1.216 +            goto clean;
   1.217 +        }
   1.218 +        // if we use UCA, real locale is root
   1.219 +        ures_close(b);
   1.220 +        b = ures_open(U_ICUDATA_COLL, "", status);
   1.221 +        ures_close(collElem);
   1.222 +        collElem = ures_open(U_ICUDATA_COLL, "", status);
   1.223 +        if(U_FAILURE(*status)) {
   1.224 +            goto clean;
   1.225 +        }
   1.226 +        result->hasRealData = FALSE;
   1.227 +    } else if(U_SUCCESS(*status)) {
   1.228 +        intStatus = U_ZERO_ERROR;
   1.229 +
   1.230 +        binary = ures_getByKey(collElem, "%%CollationBin", NULL, &intStatus);
   1.231 +
   1.232 +        if(intStatus == U_MISSING_RESOURCE_ERROR) { /* we didn't find the binary image, we should use the rules */
   1.233 +            binary = NULL;
   1.234 +            result = tryOpeningFromRules(collElem, status);
   1.235 +            if(U_FAILURE(*status)) {
   1.236 +                goto clean;
   1.237 +            }
   1.238 +        } else if(U_SUCCESS(intStatus)) { /* otherwise, we'll pick a collation data that exists */
   1.239 +            int32_t len = 0;
   1.240 +            const uint8_t *inData = ures_getBinary(binary, &len, status);
   1.241 +            if(U_FAILURE(*status)) {
   1.242 +                goto clean;
   1.243 +            }
   1.244 +            UCATableHeader *colData = (UCATableHeader *)inData;
   1.245 +            if(uprv_memcmp(colData->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0 ||
   1.246 +                uprv_memcmp(colData->UCDVersion, UCA->image->UCDVersion, sizeof(UVersionInfo)) != 0 ||
   1.247 +                colData->version[0] != UCOL_BUILDER_VERSION)
   1.248 +            {
   1.249 +                *status = U_DIFFERENT_UCA_VERSION;
   1.250 +                result = tryOpeningFromRules(collElem, status);
   1.251 +            } else {
   1.252 +                if(U_FAILURE(*status)){
   1.253 +                    goto clean;
   1.254 +                }
   1.255 +                if((uint32_t)len > (paddedsize(sizeof(UCATableHeader)) + paddedsize(sizeof(UColOptionSet)))) {
   1.256 +                    result = ucol_initCollator((const UCATableHeader *)inData, result, UCA, status);
   1.257 +                    if(U_FAILURE(*status)){
   1.258 +                        goto clean;
   1.259 +                    }
   1.260 +                    result->hasRealData = TRUE;
   1.261 +                } else {
   1.262 +                    result = ucol_initCollator(UCA->image, result, UCA, status);
   1.263 +                    ucol_setOptionsFromHeader(result, (UColOptionSet *)(inData+((const UCATableHeader *)inData)->options), status);
   1.264 +                    if(U_FAILURE(*status)){
   1.265 +                        goto clean;
   1.266 +                    }
   1.267 +                    result->hasRealData = FALSE;
   1.268 +                }
   1.269 +                result->freeImageOnClose = FALSE;
   1.270 +                
   1.271 +                reorderRes = ures_getByKey(collElem, "%%ReorderCodes", NULL, &intStatus);
   1.272 +                if (U_SUCCESS(intStatus)) {
   1.273 +                    int32_t reorderCodesLen = 0;
   1.274 +                    const int32_t* reorderCodes = ures_getIntVector(reorderRes, &reorderCodesLen, status);
   1.275 +                    if (reorderCodesLen > 0) {
   1.276 +                        ucol_setReorderCodes(result, reorderCodes, reorderCodesLen, status);
   1.277 +                        // copy the reorder codes into the default reorder codes
   1.278 +                        result->defaultReorderCodesLength = result->reorderCodesLength;
   1.279 +                        result->defaultReorderCodes =  (int32_t*) uprv_malloc(result->defaultReorderCodesLength * sizeof(int32_t));
   1.280 +                        uprv_memcpy(result->defaultReorderCodes, result->reorderCodes, result->defaultReorderCodesLength * sizeof(int32_t));
   1.281 +                        result->freeDefaultReorderCodesOnClose = TRUE;
   1.282 +                    }
   1.283 +                    if (U_FAILURE(*status)) {
   1.284 +                        goto clean;
   1.285 +                    }
   1.286 +                }
   1.287 +            }
   1.288 +
   1.289 +        } else { // !U_SUCCESS(binaryStatus)
   1.290 +            if(U_SUCCESS(*status)) {
   1.291 +                *status = intStatus; // propagate underlying error
   1.292 +            }
   1.293 +            goto clean;
   1.294 +        }
   1.295 +        intStatus = U_ZERO_ERROR;
   1.296 +        result->rules = ures_getStringByKey(collElem, "Sequence", &result->rulesLength, &intStatus);
   1.297 +        result->freeRulesOnClose = FALSE;
   1.298 +    } else { /* There is another error, and we're just gonna clean up */
   1.299 +        goto clean;
   1.300 +    }
   1.301 +
   1.302 +    intStatus = U_ZERO_ERROR;
   1.303 +    result->ucaRules = ures_getStringByKey(b,"UCARules",NULL,&intStatus);
   1.304 +
   1.305 +    if(loc == NULL) {
   1.306 +        loc = ures_getLocaleByType(b, ULOC_ACTUAL_LOCALE, status);
   1.307 +    }
   1.308 +    result->requestedLocale = uprv_strdup(loc);
   1.309 +    /* test for NULL */
   1.310 +    if (result->requestedLocale == NULL) {
   1.311 +        *status = U_MEMORY_ALLOCATION_ERROR;
   1.312 +        goto clean;
   1.313 +    }
   1.314 +    loc = ures_getLocaleByType(collElem, ULOC_ACTUAL_LOCALE, status);
   1.315 +    result->actualLocale = uprv_strdup(loc);
   1.316 +    /* test for NULL */
   1.317 +    if (result->actualLocale == NULL) {
   1.318 +        *status = U_MEMORY_ALLOCATION_ERROR;
   1.319 +        goto clean;
   1.320 +    }
   1.321 +    loc = ures_getLocaleByType(b, ULOC_ACTUAL_LOCALE, status);
   1.322 +    result->validLocale = uprv_strdup(loc);
   1.323 +    /* test for NULL */
   1.324 +    if (result->validLocale == NULL) {
   1.325 +        *status = U_MEMORY_ALLOCATION_ERROR;
   1.326 +        goto clean;
   1.327 +    }
   1.328 +
   1.329 +    ures_close(b);
   1.330 +    ures_close(collElem);
   1.331 +    ures_close(binary);
   1.332 +    ures_close(reorderRes);
   1.333 +    return result;
   1.334 +
   1.335 +clean:
   1.336 +    ures_close(b);
   1.337 +    ures_close(collElem);
   1.338 +    ures_close(binary);
   1.339 +    ures_close(reorderRes);
   1.340 +    ucol_close(result);
   1.341 +    return NULL;
   1.342 +}
   1.343 +
   1.344 +U_CAPI UCollator*
   1.345 +ucol_open(const char *loc,
   1.346 +          UErrorCode *status)
   1.347 +{
   1.348 +    U_NAMESPACE_USE
   1.349 +
   1.350 +    UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN);
   1.351 +    UTRACE_DATA1(UTRACE_INFO, "locale = \"%s\"", loc);
   1.352 +    UCollator *result = NULL;
   1.353 +
   1.354 +#if !UCONFIG_NO_SERVICE
   1.355 +    result = Collator::createUCollator(loc, status);
   1.356 +    if (result == NULL)
   1.357 +#endif
   1.358 +    {
   1.359 +        result = ucol_open_internal(loc, status);
   1.360 +    }
   1.361 +    UTRACE_EXIT_PTR_STATUS(result, *status);
   1.362 +    return result;
   1.363 +}
   1.364 +
   1.365 +
   1.366 +UCollator*
   1.367 +ucol_openRulesForImport( const UChar        *rules,
   1.368 +                         int32_t            rulesLength,
   1.369 +                         UColAttributeValue normalizationMode,
   1.370 +                         UCollationStrength strength,
   1.371 +                         UParseError        *parseError,
   1.372 +                         GetCollationRulesFunction  importFunc,
   1.373 +                         void* context,
   1.374 +                         UErrorCode         *status)
   1.375 +{
   1.376 +    UColTokenParser src;
   1.377 +    UColAttributeValue norm;
   1.378 +    UParseError tErr;
   1.379 +
   1.380 +    if(status == NULL || U_FAILURE(*status)){
   1.381 +        return 0;
   1.382 +    }
   1.383 +
   1.384 +    if(rules == NULL || rulesLength < -1) {
   1.385 +        *status = U_ILLEGAL_ARGUMENT_ERROR;
   1.386 +        return 0;
   1.387 +    }
   1.388 +
   1.389 +    if(rulesLength == -1) {
   1.390 +        rulesLength = u_strlen(rules);
   1.391 +    }
   1.392 +
   1.393 +    if(parseError == NULL){
   1.394 +        parseError = &tErr;
   1.395 +    }
   1.396 +
   1.397 +    switch(normalizationMode) {
   1.398 +    case UCOL_OFF:
   1.399 +    case UCOL_ON:
   1.400 +    case UCOL_DEFAULT:
   1.401 +        norm = normalizationMode;
   1.402 +        break;
   1.403 +    default:
   1.404 +        *status = U_ILLEGAL_ARGUMENT_ERROR;
   1.405 +        return 0;
   1.406 +    }
   1.407 +
   1.408 +    UCollator *result = NULL;
   1.409 +    UCATableHeader *table = NULL;
   1.410 +    UCollator *UCA = ucol_initUCA(status);
   1.411 +
   1.412 +    if(U_FAILURE(*status)){
   1.413 +        return NULL;
   1.414 +    }
   1.415 +
   1.416 +    ucol_tok_initTokenList(&src, rules, rulesLength, UCA, importFunc, context, status);
   1.417 +    ucol_tok_assembleTokenList(&src,parseError, status);
   1.418 +
   1.419 +    if(U_FAILURE(*status)) {
   1.420 +        /* if status is U_ILLEGAL_ARGUMENT_ERROR, src->current points at the offending option */
   1.421 +        /* if status is U_INVALID_FORMAT_ERROR, src->current points after the problematic part of the rules */
   1.422 +        /* so something might be done here... or on lower level */
   1.423 +#ifdef UCOL_DEBUG
   1.424 +        if(*status == U_ILLEGAL_ARGUMENT_ERROR) {
   1.425 +            fprintf(stderr, "bad option starting at offset %i\n", (int)(src.current-src.source));
   1.426 +        } else {
   1.427 +            fprintf(stderr, "invalid rule just before offset %i\n", (int)(src.current-src.source));
   1.428 +        }
   1.429 +#endif
   1.430 +        goto cleanup;
   1.431 +    }
   1.432 +
   1.433 +     /* if we have a set of rules, let's make something of it */
   1.434 +    if(src.resultLen > 0 || src.removeSet != NULL) {
   1.435 +        /* also, if we wanted to remove some contractions, we should make a tailoring */
   1.436 +        table = ucol_assembleTailoringTable(&src, status);
   1.437 +        if(U_SUCCESS(*status)) {
   1.438 +            // builder version
   1.439 +            table->version[0] = UCOL_BUILDER_VERSION;
   1.440 +            // no tailoring information on this level
   1.441 +            table->version[1] = table->version[2] = table->version[3] = 0;
   1.442 +            // set UCD version
   1.443 +            u_getUnicodeVersion(table->UCDVersion);
   1.444 +            // set UCA version
   1.445 +            uprv_memcpy(table->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo));
   1.446 +            result = ucol_initCollator(table, 0, UCA, status);
   1.447 +            if (U_FAILURE(*status)) {
   1.448 +                goto cleanup;
   1.449 +            }
   1.450 +            result->hasRealData = TRUE;
   1.451 +            result->freeImageOnClose = TRUE;
   1.452 +        } else {
   1.453 +            goto cleanup;
   1.454 +        }
   1.455 +    } else { /* no rules, but no error either */
   1.456 +        // must be only options
   1.457 +        // We will init the collator from UCA
   1.458 +        result = ucol_initCollator(UCA->image, 0, UCA, status);
   1.459 +        // Check for null result
   1.460 +        if (U_FAILURE(*status)) {
   1.461 +            goto cleanup;
   1.462 +        }
   1.463 +        // And set only the options
   1.464 +        UColOptionSet *opts = (UColOptionSet *)uprv_malloc(sizeof(UColOptionSet));
   1.465 +        /* test for NULL */
   1.466 +        if (opts == NULL) {
   1.467 +            *status = U_MEMORY_ALLOCATION_ERROR;
   1.468 +            goto cleanup;
   1.469 +        }
   1.470 +        uprv_memcpy(opts, src.opts, sizeof(UColOptionSet));
   1.471 +        ucol_setOptionsFromHeader(result, opts, status);
   1.472 +        result->freeOptionsOnClose = TRUE;
   1.473 +        result->hasRealData = FALSE;
   1.474 +        result->freeImageOnClose = FALSE;
   1.475 +    }
   1.476 +
   1.477 +    ucol_setReorderCodesFromParser(result, &src, status);
   1.478 +
   1.479 +    if(U_SUCCESS(*status)) {
   1.480 +        UChar *newRules;
   1.481 +        result->dataVersion[0] = UCOL_BUILDER_VERSION;
   1.482 +        if(rulesLength > 0) {
   1.483 +            newRules = (UChar *)uprv_malloc((rulesLength+1)*U_SIZEOF_UCHAR);
   1.484 +            /* test for NULL */
   1.485 +            if (newRules == NULL) {
   1.486 +                *status = U_MEMORY_ALLOCATION_ERROR;
   1.487 +                goto cleanup;
   1.488 +            }
   1.489 +            uprv_memcpy(newRules, rules, rulesLength*U_SIZEOF_UCHAR);
   1.490 +            newRules[rulesLength]=0;
   1.491 +            result->rules = newRules;
   1.492 +            result->rulesLength = rulesLength;
   1.493 +            result->freeRulesOnClose = TRUE;
   1.494 +        }
   1.495 +        result->ucaRules = NULL;
   1.496 +        result->actualLocale = NULL;
   1.497 +        result->validLocale = NULL;
   1.498 +        result->requestedLocale = NULL;
   1.499 +        ucol_buildPermutationTable(result, status);
   1.500 +        ucol_setAttribute(result, UCOL_STRENGTH, strength, status);
   1.501 +        ucol_setAttribute(result, UCOL_NORMALIZATION_MODE, norm, status);
   1.502 +    } else {
   1.503 +cleanup:
   1.504 +        if(result != NULL) {
   1.505 +            ucol_close(result);
   1.506 +        } else {
   1.507 +            if(table != NULL) {
   1.508 +                uprv_free(table);
   1.509 +            }
   1.510 +        }
   1.511 +        result = NULL;
   1.512 +    }
   1.513 +
   1.514 +    ucol_tok_closeTokenList(&src);
   1.515 +
   1.516 +    return result;
   1.517 +}
   1.518 +
   1.519 +U_CAPI UCollator* U_EXPORT2
   1.520 +ucol_openRules( const UChar        *rules,
   1.521 +               int32_t            rulesLength,
   1.522 +               UColAttributeValue normalizationMode,
   1.523 +               UCollationStrength strength,
   1.524 +               UParseError        *parseError,
   1.525 +               UErrorCode         *status)
   1.526 +{
   1.527 +    return ucol_openRulesForImport(rules,
   1.528 +                                   rulesLength,
   1.529 +                                   normalizationMode,
   1.530 +                                   strength,
   1.531 +                                   parseError,
   1.532 +                                   ucol_tok_getRulesFromBundle,
   1.533 +                                   NULL,
   1.534 +                                   status);
   1.535 +}
   1.536 +
   1.537 +U_CAPI int32_t U_EXPORT2
   1.538 +ucol_getRulesEx(const UCollator *coll, UColRuleOption delta, UChar *buffer, int32_t bufferLen) {
   1.539 +    UErrorCode status = U_ZERO_ERROR;
   1.540 +    int32_t len = 0;
   1.541 +    int32_t UCAlen = 0;
   1.542 +    const UChar* ucaRules = 0;
   1.543 +    const UChar *rules = ucol_getRules(coll, &len);
   1.544 +    if(delta == UCOL_FULL_RULES) {
   1.545 +        /* take the UCA rules and append real rules at the end */
   1.546 +        /* UCA rules will be probably coming from the root RB */
   1.547 +        ucaRules = coll->ucaRules;
   1.548 +        if (ucaRules) {
   1.549 +            UCAlen = u_strlen(ucaRules);
   1.550 +        }
   1.551 +        /*
   1.552 +        ucaRules = ures_getStringByKey(coll->rb,"UCARules",&UCAlen,&status);
   1.553 +        UResourceBundle* cresb = ures_getByKeyWithFallback(coll->rb, "collations", NULL, &status);
   1.554 +        UResourceBundle*  uca = ures_getByKeyWithFallback(cresb, "UCA", NULL, &status);
   1.555 +        ucaRules = ures_getStringByKey(uca,"Sequence",&UCAlen,&status);
   1.556 +        ures_close(uca);
   1.557 +        ures_close(cresb);
   1.558 +        */
   1.559 +    }
   1.560 +    if(U_FAILURE(status)) {
   1.561 +        return 0;
   1.562 +    }
   1.563 +    if(buffer!=0 && bufferLen>0){
   1.564 +        *buffer=0;
   1.565 +        if(UCAlen > 0) {
   1.566 +            u_memcpy(buffer, ucaRules, uprv_min(UCAlen, bufferLen));
   1.567 +        }
   1.568 +        if(len > 0 && bufferLen > UCAlen) {
   1.569 +            u_memcpy(buffer+UCAlen, rules, uprv_min(len, bufferLen-UCAlen));
   1.570 +        }
   1.571 +    }
   1.572 +    return u_terminateUChars(buffer, bufferLen, len+UCAlen, &status);
   1.573 +}
   1.574 +
   1.575 +static const UChar _NUL = 0;
   1.576 +
   1.577 +U_CAPI const UChar* U_EXPORT2
   1.578 +ucol_getRules(    const    UCollator       *coll,
   1.579 +              int32_t            *length)
   1.580 +{
   1.581 +    if(coll->rules != NULL) {
   1.582 +        *length = coll->rulesLength;
   1.583 +        return coll->rules;
   1.584 +    }
   1.585 +    else {
   1.586 +        *length = 0;
   1.587 +        return &_NUL;
   1.588 +    }
   1.589 +}
   1.590 +
   1.591 +U_CAPI UBool U_EXPORT2
   1.592 +ucol_equals(const UCollator *source, const UCollator *target) {
   1.593 +    UErrorCode status = U_ZERO_ERROR;
   1.594 +    // if pointers are equal, collators are equal
   1.595 +    if(source == target) {
   1.596 +        return TRUE;
   1.597 +    }
   1.598 +    int32_t i = 0, j = 0;
   1.599 +    // if any of attributes are different, collators are not equal
   1.600 +    for(i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) {
   1.601 +        if(ucol_getAttribute(source, (UColAttribute)i, &status) != ucol_getAttribute(target, (UColAttribute)i, &status) || U_FAILURE(status)) {
   1.602 +            return FALSE;
   1.603 +        }
   1.604 +    }
   1.605 +    if (source->reorderCodesLength != target->reorderCodesLength){
   1.606 +        return FALSE;
   1.607 +    }
   1.608 +    for (i = 0; i < source->reorderCodesLength; i++) {
   1.609 +        if(source->reorderCodes[i] != target->reorderCodes[i]) {
   1.610 +            return FALSE;
   1.611 +        }
   1.612 +    }
   1.613 +
   1.614 +    int32_t sourceRulesLen = 0, targetRulesLen = 0;
   1.615 +    const UChar *sourceRules = ucol_getRules(source, &sourceRulesLen);
   1.616 +    const UChar *targetRules = ucol_getRules(target, &targetRulesLen);
   1.617 +
   1.618 +    if(sourceRulesLen == targetRulesLen && u_strncmp(sourceRules, targetRules, sourceRulesLen) == 0) {
   1.619 +        // all the attributes are equal and the rules are equal - collators are equal
   1.620 +        return(TRUE);
   1.621 +    }
   1.622 +    // hard part, need to construct tree from rules and see if they yield the same tailoring
   1.623 +    UBool result = TRUE;
   1.624 +    UParseError parseError;
   1.625 +    UColTokenParser sourceParser, targetParser;
   1.626 +    int32_t sourceListLen = 0, targetListLen = 0;
   1.627 +    ucol_tok_initTokenList(&sourceParser, sourceRules, sourceRulesLen, source->UCA, ucol_tok_getRulesFromBundle, NULL, &status);
   1.628 +    ucol_tok_initTokenList(&targetParser, targetRules, targetRulesLen, target->UCA, ucol_tok_getRulesFromBundle, NULL, &status);
   1.629 +    sourceListLen = ucol_tok_assembleTokenList(&sourceParser, &parseError, &status);
   1.630 +    targetListLen = ucol_tok_assembleTokenList(&targetParser, &parseError, &status);
   1.631 +
   1.632 +    if(sourceListLen != targetListLen) {
   1.633 +        // different number of resets
   1.634 +        result = FALSE;
   1.635 +    } else {
   1.636 +        UColToken *sourceReset = NULL, *targetReset = NULL;
   1.637 +        UChar *sourceResetString = NULL, *targetResetString = NULL;
   1.638 +        int32_t sourceStringLen = 0, targetStringLen = 0;
   1.639 +        for(i = 0; i < sourceListLen; i++) {
   1.640 +            sourceReset = sourceParser.lh[i].reset;
   1.641 +            sourceResetString = sourceParser.source+(sourceReset->source & 0xFFFFFF);
   1.642 +            sourceStringLen = sourceReset->source >> 24;
   1.643 +            for(j = 0; j < sourceListLen; j++) {
   1.644 +                targetReset = targetParser.lh[j].reset;
   1.645 +                targetResetString = targetParser.source+(targetReset->source & 0xFFFFFF);
   1.646 +                targetStringLen = targetReset->source >> 24;
   1.647 +                if(sourceStringLen == targetStringLen && (u_strncmp(sourceResetString, targetResetString, sourceStringLen) == 0)) {
   1.648 +                    sourceReset = sourceParser.lh[i].first;
   1.649 +                    targetReset = targetParser.lh[j].first;
   1.650 +                    while(sourceReset != NULL && targetReset != NULL) {
   1.651 +                        sourceResetString = sourceParser.source+(sourceReset->source & 0xFFFFFF);
   1.652 +                        sourceStringLen = sourceReset->source >> 24;
   1.653 +                        targetResetString = targetParser.source+(targetReset->source & 0xFFFFFF);
   1.654 +                        targetStringLen = targetReset->source >> 24;
   1.655 +                        if(sourceStringLen != targetStringLen || (u_strncmp(sourceResetString, targetResetString, sourceStringLen) != 0)) {
   1.656 +                            result = FALSE;
   1.657 +                            goto returnResult;
   1.658 +                        }
   1.659 +                        // probably also need to check the expansions
   1.660 +                        if(sourceReset->expansion) {
   1.661 +                            if(!targetReset->expansion) {
   1.662 +                                result = FALSE;
   1.663 +                                goto returnResult;
   1.664 +                            } else {
   1.665 +                                // compare expansions
   1.666 +                                sourceResetString = sourceParser.source+(sourceReset->expansion& 0xFFFFFF);
   1.667 +                                sourceStringLen = sourceReset->expansion >> 24;
   1.668 +                                targetResetString = targetParser.source+(targetReset->expansion & 0xFFFFFF);
   1.669 +                                targetStringLen = targetReset->expansion >> 24;
   1.670 +                                if(sourceStringLen != targetStringLen || (u_strncmp(sourceResetString, targetResetString, sourceStringLen) != 0)) {
   1.671 +                                    result = FALSE;
   1.672 +                                    goto returnResult;
   1.673 +                                }
   1.674 +                            }
   1.675 +                        } else {
   1.676 +                            if(targetReset->expansion) {
   1.677 +                                result = FALSE;
   1.678 +                                goto returnResult;
   1.679 +                            }
   1.680 +                        }
   1.681 +                        sourceReset = sourceReset->next;
   1.682 +                        targetReset = targetReset->next;
   1.683 +                    }
   1.684 +                    if(sourceReset != targetReset) { // at least one is not NULL
   1.685 +                        // there are more tailored elements in one list
   1.686 +                        result = FALSE;
   1.687 +                        goto returnResult;
   1.688 +                    }
   1.689 +
   1.690 +
   1.691 +                    break;
   1.692 +                }
   1.693 +            }
   1.694 +            // couldn't find the reset anchor, so the collators are not equal
   1.695 +            if(j == sourceListLen) {
   1.696 +                result = FALSE;
   1.697 +                goto returnResult;
   1.698 +            }
   1.699 +        }
   1.700 +    }
   1.701 +
   1.702 +returnResult:
   1.703 +    ucol_tok_closeTokenList(&sourceParser);
   1.704 +    ucol_tok_closeTokenList(&targetParser);
   1.705 +    return result;
   1.706 +
   1.707 +}
   1.708 +
   1.709 +U_CAPI int32_t U_EXPORT2
   1.710 +ucol_getDisplayName(    const    char        *objLoc,
   1.711 +                    const    char        *dispLoc,
   1.712 +                    UChar             *result,
   1.713 +                    int32_t         resultLength,
   1.714 +                    UErrorCode        *status)
   1.715 +{
   1.716 +    U_NAMESPACE_USE
   1.717 +
   1.718 +    if(U_FAILURE(*status)) return -1;
   1.719 +    UnicodeString dst;
   1.720 +    if(!(result==NULL && resultLength==0)) {
   1.721 +        // NULL destination for pure preflighting: empty dummy string
   1.722 +        // otherwise, alias the destination buffer
   1.723 +        dst.setTo(result, 0, resultLength);
   1.724 +    }
   1.725 +    Collator::getDisplayName(Locale(objLoc), Locale(dispLoc), dst);
   1.726 +    return dst.extract(result, resultLength, *status);
   1.727 +}
   1.728 +
   1.729 +U_CAPI const char* U_EXPORT2
   1.730 +ucol_getAvailable(int32_t index)
   1.731 +{
   1.732 +    int32_t count = 0;
   1.733 +    const Locale *loc = Collator::getAvailableLocales(count);
   1.734 +    if (loc != NULL && index < count) {
   1.735 +        return loc[index].getName();
   1.736 +    }
   1.737 +    return NULL;
   1.738 +}
   1.739 +
   1.740 +U_CAPI int32_t U_EXPORT2
   1.741 +ucol_countAvailable()
   1.742 +{
   1.743 +    int32_t count = 0;
   1.744 +    Collator::getAvailableLocales(count);
   1.745 +    return count;
   1.746 +}
   1.747 +
   1.748 +#if !UCONFIG_NO_SERVICE
   1.749 +U_CAPI UEnumeration* U_EXPORT2
   1.750 +ucol_openAvailableLocales(UErrorCode *status) {
   1.751 +    U_NAMESPACE_USE
   1.752 +
   1.753 +    // This is a wrapper over Collator::getAvailableLocales()
   1.754 +    if (U_FAILURE(*status)) {
   1.755 +        return NULL;
   1.756 +    }
   1.757 +    StringEnumeration *s = icu::Collator::getAvailableLocales();
   1.758 +    if (s == NULL) {
   1.759 +        *status = U_MEMORY_ALLOCATION_ERROR;
   1.760 +        return NULL;
   1.761 +    }
   1.762 +    return uenum_openFromStringEnumeration(s, status);
   1.763 +}
   1.764 +#endif
   1.765 +
   1.766 +// Note: KEYWORDS[0] != RESOURCE_NAME - alan
   1.767 +
   1.768 +static const char RESOURCE_NAME[] = "collations";
   1.769 +
   1.770 +static const char* const KEYWORDS[] = { "collation" };
   1.771 +
   1.772 +#define KEYWORD_COUNT (sizeof(KEYWORDS)/sizeof(KEYWORDS[0]))
   1.773 +
   1.774 +U_CAPI UEnumeration* U_EXPORT2
   1.775 +ucol_getKeywords(UErrorCode *status) {
   1.776 +    UEnumeration *result = NULL;
   1.777 +    if (U_SUCCESS(*status)) {
   1.778 +        return uenum_openCharStringsEnumeration(KEYWORDS, KEYWORD_COUNT, status);
   1.779 +    }
   1.780 +    return result;
   1.781 +}
   1.782 +
   1.783 +U_CAPI UEnumeration* U_EXPORT2
   1.784 +ucol_getKeywordValues(const char *keyword, UErrorCode *status) {
   1.785 +    if (U_FAILURE(*status)) {
   1.786 +        return NULL;
   1.787 +    }
   1.788 +    // hard-coded to accept exactly one collation keyword
   1.789 +    // modify if additional collation keyword is added later
   1.790 +    if (keyword==NULL || uprv_strcmp(keyword, KEYWORDS[0])!=0)
   1.791 +    {
   1.792 +        *status = U_ILLEGAL_ARGUMENT_ERROR;
   1.793 +        return NULL;
   1.794 +    }
   1.795 +    return ures_getKeywordValues(U_ICUDATA_COLL, RESOURCE_NAME, status);
   1.796 +}
   1.797 +
   1.798 +static const UEnumeration defaultKeywordValues = {
   1.799 +    NULL,
   1.800 +    NULL,
   1.801 +    ulist_close_keyword_values_iterator,
   1.802 +    ulist_count_keyword_values,
   1.803 +    uenum_unextDefault,
   1.804 +    ulist_next_keyword_value,
   1.805 +    ulist_reset_keyword_values_iterator
   1.806 +};
   1.807 +
   1.808 +#include <stdio.h>
   1.809 +
   1.810 +U_CAPI UEnumeration* U_EXPORT2
   1.811 +ucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale,
   1.812 +                               UBool /*commonlyUsed*/, UErrorCode* status) {
   1.813 +    /* Get the locale base name. */
   1.814 +    char localeBuffer[ULOC_FULLNAME_CAPACITY] = "";
   1.815 +    uloc_getBaseName(locale, localeBuffer, sizeof(localeBuffer), status);
   1.816 +
   1.817 +    /* Create the 2 lists
   1.818 +     * -values is the temp location for the keyword values
   1.819 +     * -results hold the actual list used by the UEnumeration object
   1.820 +     */
   1.821 +    UList *values = ulist_createEmptyList(status);
   1.822 +    UList *results = ulist_createEmptyList(status);
   1.823 +    UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
   1.824 +    if (U_FAILURE(*status) || en == NULL) {
   1.825 +        if (en == NULL) {
   1.826 +            *status = U_MEMORY_ALLOCATION_ERROR;
   1.827 +        } else {
   1.828 +            uprv_free(en);
   1.829 +        }
   1.830 +        ulist_deleteList(values);
   1.831 +        ulist_deleteList(results);
   1.832 +        return NULL;
   1.833 +    }
   1.834 +
   1.835 +    memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
   1.836 +    en->context = results;
   1.837 +
   1.838 +    /* Open the resource bundle for collation with the given locale. */
   1.839 +    UResourceBundle bundle, collations, collres, defres;
   1.840 +    ures_initStackObject(&bundle);
   1.841 +    ures_initStackObject(&collations);
   1.842 +    ures_initStackObject(&collres);
   1.843 +    ures_initStackObject(&defres);
   1.844 +
   1.845 +    ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
   1.846 +
   1.847 +    while (U_SUCCESS(*status)) {
   1.848 +        ures_getByKey(&bundle, RESOURCE_NAME, &collations, status);
   1.849 +        ures_resetIterator(&collations);
   1.850 +        while (U_SUCCESS(*status) && ures_hasNext(&collations)) {
   1.851 +            ures_getNextResource(&collations, &collres, status);
   1.852 +            const char *key = ures_getKey(&collres);
   1.853 +            /* If the key is default, get the string and store it in results list only
   1.854 +             * if results list is empty.
   1.855 +             */
   1.856 +            if (uprv_strcmp(key, "default") == 0) {
   1.857 +                if (ulist_getListSize(results) == 0) {
   1.858 +                    char *defcoll = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
   1.859 +                    int32_t defcollLength = ULOC_KEYWORDS_CAPACITY;
   1.860 +
   1.861 +                    ures_getNextResource(&collres, &defres, status);
   1.862 +#if U_CHARSET_FAMILY==U_ASCII_FAMILY
   1.863 +			/* optimize - use the utf-8 string */
   1.864 +                    ures_getUTF8String(&defres, defcoll, &defcollLength, TRUE, status);
   1.865 +#else
   1.866 +                    {
   1.867 +                       const UChar* defString = ures_getString(&defres, &defcollLength, status);
   1.868 +                       if(U_SUCCESS(*status)) {
   1.869 +			   if(defcollLength+1 > ULOC_KEYWORDS_CAPACITY) {
   1.870 +				*status = U_BUFFER_OVERFLOW_ERROR;
   1.871 +			   } else {
   1.872 +                           	u_UCharsToChars(defString, defcoll, defcollLength+1);
   1.873 +			   }
   1.874 +                       }
   1.875 +                    }
   1.876 +#endif	
   1.877 +
   1.878 +                    ulist_addItemBeginList(results, defcoll, TRUE, status);
   1.879 +                }
   1.880 +            } else {
   1.881 +                ulist_addItemEndList(values, key, FALSE, status);
   1.882 +            }
   1.883 +        }
   1.884 +
   1.885 +        /* If the locale is "" this is root so exit. */
   1.886 +        if (uprv_strlen(localeBuffer) == 0) {
   1.887 +            break;
   1.888 +        }
   1.889 +        /* Get the parent locale and open a new resource bundle. */
   1.890 +        uloc_getParent(localeBuffer, localeBuffer, sizeof(localeBuffer), status);
   1.891 +        ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
   1.892 +    }
   1.893 +
   1.894 +    ures_close(&defres);
   1.895 +    ures_close(&collres);
   1.896 +    ures_close(&collations);
   1.897 +    ures_close(&bundle);
   1.898 +
   1.899 +    if (U_SUCCESS(*status)) {
   1.900 +        char *value = NULL;
   1.901 +        ulist_resetList(values);
   1.902 +        while ((value = (char *)ulist_getNext(values)) != NULL) {
   1.903 +            if (!ulist_containsString(results, value, (int32_t)uprv_strlen(value))) {
   1.904 +                ulist_addItemEndList(results, value, FALSE, status);
   1.905 +                if (U_FAILURE(*status)) {
   1.906 +                    break;
   1.907 +                }
   1.908 +            }
   1.909 +        }
   1.910 +    }
   1.911 +
   1.912 +    ulist_deleteList(values);
   1.913 +
   1.914 +    if (U_FAILURE(*status)){
   1.915 +        uenum_close(en);
   1.916 +        en = NULL;
   1.917 +    } else {
   1.918 +        ulist_resetList(results);
   1.919 +    }
   1.920 +
   1.921 +    return en;
   1.922 +}
   1.923 +
   1.924 +U_CAPI int32_t U_EXPORT2
   1.925 +ucol_getFunctionalEquivalent(char* result, int32_t resultCapacity,
   1.926 +                             const char* keyword, const char* locale,
   1.927 +                             UBool* isAvailable, UErrorCode* status)
   1.928 +{
   1.929 +    // N.B.: Resource name is "collations" but keyword is "collation"
   1.930 +    return ures_getFunctionalEquivalent(result, resultCapacity, U_ICUDATA_COLL,
   1.931 +        "collations", keyword, locale,
   1.932 +        isAvailable, TRUE, status);
   1.933 +}
   1.934 +
   1.935 +/* returns the locale name the collation data comes from */
   1.936 +U_CAPI const char * U_EXPORT2
   1.937 +ucol_getLocale(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status) {
   1.938 +    return ucol_getLocaleByType(coll, type, status);
   1.939 +}
   1.940 +
   1.941 +U_CAPI const char * U_EXPORT2
   1.942 +ucol_getLocaleByType(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status) {
   1.943 +    const char *result = NULL;
   1.944 +    if(status == NULL || U_FAILURE(*status)) {
   1.945 +        return NULL;
   1.946 +    }
   1.947 +    UTRACE_ENTRY(UTRACE_UCOL_GETLOCALE);
   1.948 +    UTRACE_DATA1(UTRACE_INFO, "coll=%p", coll);
   1.949 +
   1.950 +    if(coll->delegate!=NULL) {
   1.951 +      return ((const Collator*)coll->delegate)->getLocale(type, *status).getName();
   1.952 +    }
   1.953 +    switch(type) {
   1.954 +    case ULOC_ACTUAL_LOCALE:
   1.955 +        result = coll->actualLocale;
   1.956 +        break;
   1.957 +    case ULOC_VALID_LOCALE:
   1.958 +        result = coll->validLocale;
   1.959 +        break;
   1.960 +    case ULOC_REQUESTED_LOCALE:
   1.961 +        result = coll->requestedLocale;
   1.962 +        break;
   1.963 +    default:
   1.964 +        *status = U_ILLEGAL_ARGUMENT_ERROR;
   1.965 +    }
   1.966 +    UTRACE_DATA1(UTRACE_INFO, "result = %s", result);
   1.967 +    UTRACE_EXIT_STATUS(*status);
   1.968 +    return result;
   1.969 +}
   1.970 +
   1.971 +U_CFUNC void U_EXPORT2
   1.972 +ucol_setReqValidLocales(UCollator *coll, char *requestedLocaleToAdopt, char *validLocaleToAdopt, char *actualLocaleToAdopt)
   1.973 +{
   1.974 +    if (coll) {
   1.975 +        if (coll->validLocale) {
   1.976 +            uprv_free(coll->validLocale);
   1.977 +        }
   1.978 +        coll->validLocale = validLocaleToAdopt;
   1.979 +        if (coll->requestedLocale) { // should always have
   1.980 +            uprv_free(coll->requestedLocale);
   1.981 +        }
   1.982 +        coll->requestedLocale = requestedLocaleToAdopt;
   1.983 +        if (coll->actualLocale) {
   1.984 +            uprv_free(coll->actualLocale);
   1.985 +        }
   1.986 +        coll->actualLocale = actualLocaleToAdopt;
   1.987 +    }
   1.988 +}
   1.989 +
   1.990 +U_CAPI USet * U_EXPORT2
   1.991 +ucol_getTailoredSet(const UCollator *coll, UErrorCode *status)
   1.992 +{
   1.993 +    U_NAMESPACE_USE
   1.994 +
   1.995 +    if(status == NULL || U_FAILURE(*status)) {
   1.996 +        return NULL;
   1.997 +    }
   1.998 +    if(coll == NULL || coll->UCA == NULL) {
   1.999 +        *status = U_ILLEGAL_ARGUMENT_ERROR;
  1.1000 +        return NULL;
  1.1001 +    }
  1.1002 +    UParseError parseError;
  1.1003 +    UColTokenParser src;
  1.1004 +    int32_t rulesLen = 0;
  1.1005 +    const UChar *rules = ucol_getRules(coll, &rulesLen);
  1.1006 +    UBool startOfRules = TRUE;
  1.1007 +    // we internally use the C++ class, for the following reasons:
  1.1008 +    // 1. we need to utilize canonical iterator, which is a C++ only class
  1.1009 +    // 2. canonical iterator returns UnicodeStrings - USet cannot take them
  1.1010 +    // 3. USet is internally really UnicodeSet, C is just a wrapper
  1.1011 +    UnicodeSet *tailored = new UnicodeSet();
  1.1012 +    UnicodeString pattern;
  1.1013 +    UnicodeString empty;
  1.1014 +    CanonicalIterator it(empty, *status);
  1.1015 +
  1.1016 +
  1.1017 +    // The idea is to tokenize the rule set. For each non-reset token,
  1.1018 +    // we add all the canonicaly equivalent FCD sequences
  1.1019 +    ucol_tok_initTokenList(&src, rules, rulesLen, coll->UCA, ucol_tok_getRulesFromBundle, NULL, status);
  1.1020 +    while (ucol_tok_parseNextToken(&src, startOfRules, &parseError, status) != NULL) {
  1.1021 +        startOfRules = FALSE;
  1.1022 +        if(src.parsedToken.strength != UCOL_TOK_RESET) {
  1.1023 +            const UChar *stuff = src.source+(src.parsedToken.charsOffset);
  1.1024 +            it.setSource(UnicodeString(stuff, src.parsedToken.charsLen), *status);
  1.1025 +            pattern = it.next();
  1.1026 +            while(!pattern.isBogus()) {
  1.1027 +                if(Normalizer::quickCheck(pattern, UNORM_FCD, *status) != UNORM_NO) {
  1.1028 +                    tailored->add(pattern);
  1.1029 +                }
  1.1030 +                pattern = it.next();
  1.1031 +            }
  1.1032 +        }
  1.1033 +    }
  1.1034 +    ucol_tok_closeTokenList(&src);
  1.1035 +    return (USet *)tailored;
  1.1036 +}
  1.1037 +
  1.1038 +/*
  1.1039 + * Collation Reordering
  1.1040 + */
  1.1041 + 
  1.1042 +void ucol_setReorderCodesFromParser(UCollator *coll, UColTokenParser *parser, UErrorCode *status) {
  1.1043 +    if (U_FAILURE(*status)) {
  1.1044 +        return;
  1.1045 +    }
  1.1046 +    
  1.1047 +    if (parser->reorderCodesLength == 0 || parser->reorderCodes == NULL) {
  1.1048 +        return;
  1.1049 +    }
  1.1050 +    
  1.1051 +    coll->reorderCodesLength = 0;
  1.1052 +    if (coll->reorderCodes != NULL && coll->freeReorderCodesOnClose == TRUE) {
  1.1053 +        uprv_free(coll->reorderCodes);
  1.1054 +    }
  1.1055 +    coll->reorderCodes = NULL;
  1.1056 +    coll->freeReorderCodesOnClose = FALSE;
  1.1057 +
  1.1058 +    if (coll->defaultReorderCodes != NULL && coll->freeDefaultReorderCodesOnClose == TRUE) {
  1.1059 +        uprv_free(coll->defaultReorderCodes);
  1.1060 +    }
  1.1061 +    coll->freeDefaultReorderCodesOnClose = FALSE;
  1.1062 +    coll->defaultReorderCodesLength = parser->reorderCodesLength;
  1.1063 +    coll->defaultReorderCodes =  (int32_t*) uprv_malloc(coll->defaultReorderCodesLength * sizeof(int32_t));
  1.1064 +    if (coll->defaultReorderCodes == NULL) {
  1.1065 +        *status = U_MEMORY_ALLOCATION_ERROR;
  1.1066 +        return;
  1.1067 +    }
  1.1068 +    uprv_memcpy(coll->defaultReorderCodes, parser->reorderCodes, coll->defaultReorderCodesLength * sizeof(int32_t));
  1.1069 +    coll->freeDefaultReorderCodesOnClose = TRUE;
  1.1070 +    
  1.1071 +    coll->reorderCodesLength = parser->reorderCodesLength;
  1.1072 +    coll->reorderCodes = (int32_t*) uprv_malloc(coll->reorderCodesLength * sizeof(int32_t));
  1.1073 +    if (coll->reorderCodes == NULL) {
  1.1074 +        *status = U_MEMORY_ALLOCATION_ERROR;
  1.1075 +        return;
  1.1076 +    }
  1.1077 +    uprv_memcpy(coll->reorderCodes, parser->reorderCodes, coll->reorderCodesLength * sizeof(int32_t));
  1.1078 +    coll->freeReorderCodesOnClose = TRUE;
  1.1079 +}
  1.1080 +
  1.1081 +/*
  1.1082 + * Data is stored in the reorder code to lead byte table as:
  1.1083 + *  index count - unsigned short (2 bytes) - number of index entries
  1.1084 + *  data size - unsigned short (2 bytes) - number of unsigned short data elements
  1.1085 + *  index[index count] - array of 2 unsigned shorts (4 bytes each entry)
  1.1086 + *      - reorder code, offset
  1.1087 + *      - index is sorted by reorder code
  1.1088 + *      - if an offset has the high bit set then it is not an offset but a single data entry
  1.1089 + *        once the high bit is stripped off
  1.1090 + *  data[data size] - array of unsigned short (2 bytes each entry)
  1.1091 + *      - the data is an usigned short count followed by count number 
  1.1092 + *        of lead bytes stored in an unsigned short
  1.1093 + */
  1.1094 +U_CFUNC int U_EXPORT2
  1.1095 +ucol_getLeadBytesForReorderCode(const UCollator *uca, int reorderCode, uint16_t* returnLeadBytes, int returnCapacity) {
  1.1096 +    uint16_t reorderCodeIndexLength = *((uint16_t*) ((uint8_t *)uca->image + uca->image->scriptToLeadByte));
  1.1097 +    uint16_t* reorderCodeIndex = (uint16_t*) ((uint8_t *)uca->image + uca->image->scriptToLeadByte + 2 *sizeof(uint16_t));
  1.1098 +    
  1.1099 +    // reorder code index is 2 uint16_t's - reorder code + offset
  1.1100 +    for (int i = 0; i < reorderCodeIndexLength; i++) {
  1.1101 +        if (reorderCode == reorderCodeIndex[i*2]) {
  1.1102 +            uint16_t dataOffset = reorderCodeIndex[(i*2) + 1];
  1.1103 +            if ((dataOffset & 0x8000) == 0x8000) {
  1.1104 +                // offset isn't offset but instead is a single data element
  1.1105 +                if (returnCapacity >= 1) {
  1.1106 +                    returnLeadBytes[0] = dataOffset & ~0x8000;
  1.1107 +                    return 1;
  1.1108 +                }
  1.1109 +                return 0;
  1.1110 +            }
  1.1111 +            uint16_t* dataOffsetBase = (uint16_t*) ((uint8_t *)reorderCodeIndex + reorderCodeIndexLength * (2 * sizeof(uint16_t)));
  1.1112 +            uint16_t leadByteCount = *(dataOffsetBase + dataOffset);
  1.1113 +            leadByteCount = leadByteCount > returnCapacity ? returnCapacity : leadByteCount;
  1.1114 +            uprv_memcpy(returnLeadBytes, dataOffsetBase + dataOffset + 1, leadByteCount * sizeof(uint16_t));
  1.1115 +            return leadByteCount;
  1.1116 +        }
  1.1117 +    }
  1.1118 +    return 0;
  1.1119 +}
  1.1120 +
  1.1121 +/*
  1.1122 + * Data is stored in the lead byte to reorder code table as:
  1.1123 + *  index count - unsigned short (2 bytes) - number of index entries
  1.1124 + *  data size - unsigned short (2 bytes) - number of unsigned short data elements
  1.1125 + *  index[index count] - array of unsigned short (2 bytes each entry)
  1.1126 + *      - index is sorted by lead byte
  1.1127 + *      - if an index has the high bit set then it is not an index but a single data entry
  1.1128 + *        once the high bit is stripped off
  1.1129 + *  data[data size] - array of unsigned short (2 bytes each entry)
  1.1130 + *      - the data is an usigned short count followed by count number of reorder codes
  1.1131 + */
  1.1132 +U_CFUNC int U_EXPORT2
  1.1133 +ucol_getReorderCodesForLeadByte(const UCollator *uca, int leadByte, int16_t* returnReorderCodes, int returnCapacity) {
  1.1134 +    uint16_t* leadByteTable = ((uint16_t*) ((uint8_t *)uca->image + uca->image->leadByteToScript));
  1.1135 +    uint16_t leadByteIndexLength = *leadByteTable;
  1.1136 +    if (leadByte >= leadByteIndexLength) {
  1.1137 +        return 0;
  1.1138 +    }
  1.1139 +    uint16_t leadByteIndex = *(leadByteTable + (2 + leadByte));
  1.1140 +
  1.1141 +    if ((leadByteIndex & 0x8000) == 0x8000) {
  1.1142 +        // offset isn't offset but instead is a single data element
  1.1143 +        if (returnCapacity >= 1) {
  1.1144 +            returnReorderCodes[0] = leadByteIndex & ~0x8000;
  1.1145 +            return 1;
  1.1146 +        }
  1.1147 +        return 0;
  1.1148 +    }
  1.1149 +    //uint16_t* dataOffsetBase = leadByteTable + (2 + leadByteIndexLength);
  1.1150 +    uint16_t* reorderCodeData = leadByteTable + (2 + leadByteIndexLength) + leadByteIndex;
  1.1151 +    uint16_t reorderCodeCount = *reorderCodeData > returnCapacity ? returnCapacity : *reorderCodeData;
  1.1152 +    uprv_memcpy(returnReorderCodes, reorderCodeData + 1, reorderCodeCount * sizeof(uint16_t));
  1.1153 +    return reorderCodeCount;
  1.1154 +}
  1.1155 +
  1.1156 +// used to mark ignorable reorder code slots
  1.1157 +static const int32_t UCOL_REORDER_CODE_IGNORE = UCOL_REORDER_CODE_LIMIT + 1;
  1.1158 +
  1.1159 +U_CFUNC void U_EXPORT2
  1.1160 +ucol_buildPermutationTable(UCollator *coll, UErrorCode *status) {
  1.1161 +    uint16_t leadBytesSize = 256;
  1.1162 +    uint16_t leadBytes[256];
  1.1163 +
  1.1164 +    // The lowest byte that hasn't been assigned a mapping
  1.1165 +    int toBottom = 0x03;
  1.1166 +    // The highest byte that hasn't been assigned a mapping - don't include the special or trailing
  1.1167 +    int toTop = 0xe4;
  1.1168 +
  1.1169 +    // are we filling from the bottom?
  1.1170 +    bool fromTheBottom = true;
  1.1171 +    int32_t reorderCodesIndex = -1;
  1.1172 +    
  1.1173 +    // lead bytes that have alread been assigned to the permutation table
  1.1174 +    bool newLeadByteUsed[256];
  1.1175 +    // permutation table slots that have already been filled
  1.1176 +    bool permutationSlotFilled[256];
  1.1177 +
  1.1178 +    // nothing to do
  1.1179 +    if(U_FAILURE(*status) || coll == NULL) {
  1.1180 +        return;
  1.1181 +    }
  1.1182 +    
  1.1183 +    // clear the reordering
  1.1184 +    if (coll->reorderCodes == NULL || coll->reorderCodesLength == 0 
  1.1185 +            || (coll->reorderCodesLength == 1 && coll->reorderCodes[0] == UCOL_REORDER_CODE_NONE)) {
  1.1186 +        if (coll->leadBytePermutationTable != NULL) {
  1.1187 +            if (coll->freeLeadBytePermutationTableOnClose) {
  1.1188 +                uprv_free(coll->leadBytePermutationTable);
  1.1189 +            }
  1.1190 +            coll->leadBytePermutationTable = NULL;
  1.1191 +            coll->freeLeadBytePermutationTableOnClose = FALSE;
  1.1192 +            coll->reorderCodesLength = 0;
  1.1193 +        }
  1.1194 +        return;
  1.1195 +    }
  1.1196 +
  1.1197 +    // set reordering to the default reordering
  1.1198 +    if (coll->reorderCodes[0] == UCOL_REORDER_CODE_DEFAULT) {
  1.1199 +        if (coll->reorderCodesLength != 1) {
  1.1200 +            *status = U_ILLEGAL_ARGUMENT_ERROR;
  1.1201 +            return;
  1.1202 +        }
  1.1203 +        if (coll->freeReorderCodesOnClose == TRUE) {
  1.1204 +            uprv_free(coll->reorderCodes);
  1.1205 +        }
  1.1206 +        coll->reorderCodes = NULL;
  1.1207 +        coll->freeReorderCodesOnClose = FALSE;
  1.1208 +
  1.1209 +        if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
  1.1210 +            uprv_free(coll->leadBytePermutationTable);
  1.1211 +        }
  1.1212 +        coll->leadBytePermutationTable = NULL;
  1.1213 +        coll->freeLeadBytePermutationTableOnClose = FALSE;
  1.1214 +
  1.1215 +        if (coll->defaultReorderCodesLength == 0) {
  1.1216 +            return;
  1.1217 +        }
  1.1218 +        
  1.1219 +        coll->reorderCodes = (int32_t*)uprv_malloc(coll->defaultReorderCodesLength * sizeof(int32_t));
  1.1220 +        if (coll->reorderCodes == NULL) {
  1.1221 +            *status = U_MEMORY_ALLOCATION_ERROR;
  1.1222 +            return;
  1.1223 +        }
  1.1224 +        coll->freeReorderCodesOnClose = TRUE;
  1.1225 +        coll->reorderCodesLength = coll->defaultReorderCodesLength;
  1.1226 +        uprv_memcpy(coll->reorderCodes, coll->defaultReorderCodes, coll->reorderCodesLength * sizeof(int32_t));
  1.1227 +    }
  1.1228 +
  1.1229 +    if (coll->leadBytePermutationTable == NULL) {
  1.1230 +        coll->leadBytePermutationTable = (uint8_t*)uprv_malloc(256*sizeof(uint8_t));
  1.1231 +        if (coll->leadBytePermutationTable == NULL) {
  1.1232 +            *status = U_MEMORY_ALLOCATION_ERROR;
  1.1233 +            return;
  1.1234 +        }
  1.1235 +        coll->freeLeadBytePermutationTableOnClose = TRUE;
  1.1236 +    }
  1.1237 +
  1.1238 +    int32_t internalReorderCodesLength = coll->reorderCodesLength + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST);
  1.1239 +    LocalMemory<int32_t> internalReorderCodes((int32_t*)uprv_malloc(internalReorderCodesLength * sizeof(int32_t)));
  1.1240 +    if (internalReorderCodes.isNull()) {
  1.1241 +        *status = U_MEMORY_ALLOCATION_ERROR;
  1.1242 +        if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
  1.1243 +            uprv_free(coll->leadBytePermutationTable);
  1.1244 +        }
  1.1245 +        coll->leadBytePermutationTable = NULL;
  1.1246 +        coll->freeLeadBytePermutationTableOnClose = FALSE;
  1.1247 +        return;
  1.1248 +    }
  1.1249 +
  1.1250 +    // prefill the reordering codes with the leading entries
  1.1251 +    for (uint32_t codeIndex = 0; codeIndex < (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST); codeIndex++) {
  1.1252 +        internalReorderCodes[codeIndex] = UCOL_REORDER_CODE_FIRST + codeIndex;
  1.1253 +    }
  1.1254 +    for (int32_t codeIndex = 0; codeIndex < coll->reorderCodesLength; codeIndex++) {
  1.1255 +        uint32_t reorderCodesCode = coll->reorderCodes[codeIndex];
  1.1256 +        internalReorderCodes[codeIndex + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST)] = reorderCodesCode;
  1.1257 +        if (reorderCodesCode >= UCOL_REORDER_CODE_FIRST && reorderCodesCode < UCOL_REORDER_CODE_LIMIT) {
  1.1258 +            internalReorderCodes[reorderCodesCode - UCOL_REORDER_CODE_FIRST] = UCOL_REORDER_CODE_IGNORE;
  1.1259 +        }
  1.1260 +    }
  1.1261 +
  1.1262 +    for (int i = 0; i < 256; i++) {
  1.1263 +        if (i < toBottom || i > toTop) {
  1.1264 +            permutationSlotFilled[i] = true;
  1.1265 +            newLeadByteUsed[i] = true;
  1.1266 +            coll->leadBytePermutationTable[i] = i;
  1.1267 +        } else {
  1.1268 +            permutationSlotFilled[i] = false;
  1.1269 +            newLeadByteUsed[i] = false;
  1.1270 +            coll->leadBytePermutationTable[i] = 0;
  1.1271 +        }
  1.1272 +    }
  1.1273 +    
  1.1274 +    /* Start from the front of the list and place each script we encounter at the
  1.1275 +     * earliest possible locatation in the permutation table. If we encounter
  1.1276 +     * UNKNOWN, start processing from the back, and place each script in the last
  1.1277 +     * possible location. At each step, we also need to make sure that any scripts
  1.1278 +     * that need to not be moved are copied to their same location in the final table.
  1.1279 +     */
  1.1280 +    for (int reorderCodesCount = 0; reorderCodesCount < internalReorderCodesLength; reorderCodesCount++) {
  1.1281 +        reorderCodesIndex += fromTheBottom ? 1 : -1;
  1.1282 +        int32_t next = internalReorderCodes[reorderCodesIndex];
  1.1283 +        if (next == UCOL_REORDER_CODE_IGNORE) {
  1.1284 +            continue;
  1.1285 +        }
  1.1286 +        if (next == USCRIPT_UNKNOWN) {
  1.1287 +            if (fromTheBottom == false) {
  1.1288 +                // double turnaround
  1.1289 +                *status = U_ILLEGAL_ARGUMENT_ERROR;
  1.1290 +                if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
  1.1291 +                    uprv_free(coll->leadBytePermutationTable);
  1.1292 +                }
  1.1293 +                coll->leadBytePermutationTable = NULL;
  1.1294 +                coll->freeLeadBytePermutationTableOnClose = FALSE;
  1.1295 +                coll->reorderCodesLength = 0;
  1.1296 +                return;
  1.1297 +            }
  1.1298 +            fromTheBottom = false;
  1.1299 +            reorderCodesIndex = internalReorderCodesLength;
  1.1300 +            continue;
  1.1301 +        }
  1.1302 +        
  1.1303 +        uint16_t leadByteCount = ucol_getLeadBytesForReorderCode(coll->UCA, next, leadBytes, leadBytesSize);
  1.1304 +        if (fromTheBottom) {
  1.1305 +            for (int leadByteIndex = 0; leadByteIndex < leadByteCount; leadByteIndex++) {
  1.1306 +                // don't place a lead byte twice in the permutation table
  1.1307 +                if (permutationSlotFilled[leadBytes[leadByteIndex]]) {
  1.1308 +                    // lead byte already used
  1.1309 +                    *status = U_ILLEGAL_ARGUMENT_ERROR;
  1.1310 +                    if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
  1.1311 +                        uprv_free(coll->leadBytePermutationTable);
  1.1312 +                    }
  1.1313 +                    coll->leadBytePermutationTable = NULL;
  1.1314 +                    coll->freeLeadBytePermutationTableOnClose = FALSE;
  1.1315 +                    coll->reorderCodesLength = 0;
  1.1316 +                    return;
  1.1317 +                }
  1.1318 +   
  1.1319 +                coll->leadBytePermutationTable[leadBytes[leadByteIndex]] = toBottom;
  1.1320 +                newLeadByteUsed[toBottom] = true;
  1.1321 +                permutationSlotFilled[leadBytes[leadByteIndex]] = true;
  1.1322 +                toBottom++;
  1.1323 +            }
  1.1324 +        } else {
  1.1325 +            for (int leadByteIndex = leadByteCount - 1; leadByteIndex >= 0; leadByteIndex--) {
  1.1326 +                // don't place a lead byte twice in the permutation table
  1.1327 +                if (permutationSlotFilled[leadBytes[leadByteIndex]]) {
  1.1328 +                    // lead byte already used
  1.1329 +                    *status = U_ILLEGAL_ARGUMENT_ERROR;
  1.1330 +                    if (coll->leadBytePermutationTable != NULL && coll->freeLeadBytePermutationTableOnClose == TRUE) {
  1.1331 +                        uprv_free(coll->leadBytePermutationTable);
  1.1332 +                    }
  1.1333 +                    coll->leadBytePermutationTable = NULL;
  1.1334 +                    coll->freeLeadBytePermutationTableOnClose = FALSE;
  1.1335 +                    coll->reorderCodesLength = 0;
  1.1336 +                    return;
  1.1337 +                }
  1.1338 +
  1.1339 +                coll->leadBytePermutationTable[leadBytes[leadByteIndex]] = toTop;
  1.1340 +                newLeadByteUsed[toTop] = true;
  1.1341 +                permutationSlotFilled[leadBytes[leadByteIndex]] = true;
  1.1342 +                toTop--;
  1.1343 +            }
  1.1344 +        }
  1.1345 +    }
  1.1346 +    
  1.1347 +#ifdef REORDER_DEBUG
  1.1348 +    fprintf(stdout, "\n@@@@ Partial Script Reordering Table\n");
  1.1349 +    for (int i = 0; i < 256; i++) {
  1.1350 +        fprintf(stdout, "\t%02x = %02x\n", i, coll->leadBytePermutationTable[i]);
  1.1351 +    }
  1.1352 +    fprintf(stdout, "\n@@@@ Lead Byte Used Table\n");
  1.1353 +    for (int i = 0; i < 256; i++) {
  1.1354 +        fprintf(stdout, "\t%02x = %02x\n", i, newLeadByteUsed[i]);
  1.1355 +    }
  1.1356 +    fprintf(stdout, "\n@@@@ Permutation Slot Filled Table\n");
  1.1357 +    for (int i = 0; i < 256; i++) {
  1.1358 +        fprintf(stdout, "\t%02x = %02x\n", i, permutationSlotFilled[i]);
  1.1359 +    }
  1.1360 +#endif
  1.1361 +
  1.1362 +    /* Copy everything that's left over */
  1.1363 +    int reorderCode = 0;
  1.1364 +    for (int i = 0; i < 256; i++) {
  1.1365 +        if (!permutationSlotFilled[i]) {
  1.1366 +            while (reorderCode < 256 && newLeadByteUsed[reorderCode]) {
  1.1367 +                reorderCode++;
  1.1368 +            }
  1.1369 +            coll->leadBytePermutationTable[i] = reorderCode;
  1.1370 +            permutationSlotFilled[i] = true;
  1.1371 +            newLeadByteUsed[reorderCode] = true;
  1.1372 +        }
  1.1373 +    } 
  1.1374 +    
  1.1375 +#ifdef REORDER_DEBUG
  1.1376 +    fprintf(stdout, "\n@@@@ Script Reordering Table\n");
  1.1377 +    for (int i = 0; i < 256; i++) {
  1.1378 +        fprintf(stdout, "\t%02x = %02x\n", i, coll->leadBytePermutationTable[i]);
  1.1379 +    } 
  1.1380 +#endif
  1.1381 +
  1.1382 +    // force a regen of the latin one table since it is affected by the script reordering
  1.1383 +    coll->latinOneRegenTable = TRUE;
  1.1384 +    ucol_updateInternalState(coll, status);
  1.1385 +}
  1.1386 +
  1.1387 +#endif /* #if !UCONFIG_NO_COLLATION */

mercurial