1f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/*
2f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*******************************************************************************
3f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   Copyright (C) 1996-2010, International Business Machines
4f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   Corporation and others.  All Rights Reserved.
5f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*******************************************************************************
6f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   file name:  ucol_res.cpp
7f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   encoding:   US-ASCII
8f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   tab size:   8 (not used)
9f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   indentation:4
10f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*
11f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)* Description:
12f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)* This file contains dependencies that the collation run-time doesn't normally
13f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)* need. This mainly contains resource bundle usage and collation meta information
14f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*
15f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)* Modification history
16f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)* Date        Name      Comments
17f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)* 1996-1999   various members of ICU team maintained C API for collation framework
18f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)* 02/16/2001  synwee    Added internal method getPrevSpecialCE
19f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)* 03/01/2001  synwee    Added maxexpansion functionality.
20f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)* 03/16/2001  weiv      Collation framework is rewritten in C and made UCA compliant
21f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)* 12/08/2004  grhoten   Split part of ucol.cpp into ucol_res.cpp
22f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*/
23f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
24f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/utypes.h"
25f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
26f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#if !UCONFIG_NO_COLLATION
27f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/uloc.h"
28f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/coll.h"
29f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/tblcoll.h"
30f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/caniter.h"
31f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/uscript.h"
32f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/ustring.h"
33f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
34f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "ucol_bld.h"
35f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "ucol_imp.h"
36f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "ucol_tok.h"
37f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "ucol_elm.h"
38f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "uresimp.h"
39f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "ustr_imp.h"
40f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "cstring.h"
41f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "umutex.h"
42f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "ucln_in.h"
43f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "ustrenum.h"
44f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "putilimp.h"
45f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "utracimp.h"
46f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "cmemory.h"
47f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "uenumimp.h"
48f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "ulist.h"
49f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
50f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_NAMESPACE_USE
51f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
52f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static void ucol_setReorderCodesFromParser(UCollator *coll, UColTokenParser *parser, UErrorCode *status);
53f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
54f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// static UCA. There is only one. Collators don't use it.
55f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// It is referenced only in ucol_initUCA and ucol_cleanup
56f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static UCollator* _staticUCA = NULL;
57f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// static pointer to udata memory. Inited in ucol_initUCA
58f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// used for cleanup in ucol_cleanup
59f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static UDataMemory* UCA_DATA_MEM = NULL;
60f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
61f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CDECL_BEGIN
62f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static UBool U_CALLCONV
63f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_res_cleanup(void)
64f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
65f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (UCA_DATA_MEM) {
66f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        udata_close(UCA_DATA_MEM);
67f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UCA_DATA_MEM = NULL;
68f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
69f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (_staticUCA) {
70f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ucol_close(_staticUCA);
71f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        _staticUCA = NULL;
72f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
73f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return TRUE;
74f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
75f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
76f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static UBool U_CALLCONV
77f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)isAcceptableUCA(void * /*context*/,
78f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)             const char * /*type*/, const char * /*name*/,
79f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)             const UDataInfo *pInfo){
80f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)  /* context, type & name are intentionally not used */
81f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if( pInfo->size>=20 &&
82f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
83f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->charsetFamily==U_CHARSET_FAMILY &&
84f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[0]==UCA_DATA_FORMAT_0 &&   /* dataFormat="UCol" */
85f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[1]==UCA_DATA_FORMAT_1 &&
86f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[2]==UCA_DATA_FORMAT_2 &&
87f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[3]==UCA_DATA_FORMAT_3 &&
88f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->formatVersion[0]==UCA_FORMAT_VERSION_0 &&
89f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->formatVersion[1]>=UCA_FORMAT_VERSION_1// &&
90f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        //pInfo->formatVersion[1]==UCA_FORMAT_VERSION_1 &&
91f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        //pInfo->formatVersion[2]==UCA_FORMAT_VERSION_2 && // Too harsh
92f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        //pInfo->formatVersion[3]==UCA_FORMAT_VERSION_3 && // Too harsh
93f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ) {
94f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UVersionInfo UCDVersion;
95f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        u_getUnicodeVersion(UCDVersion);
96f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return (UBool)(pInfo->dataVersion[0]==UCDVersion[0]
97f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            && pInfo->dataVersion[1]==UCDVersion[1]);
98f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            //&& pInfo->dataVersion[2]==ucaDataInfo.dataVersion[2]
99f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            //&& pInfo->dataVersion[3]==ucaDataInfo.dataVersion[3]);
100f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else {
101f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return FALSE;
102f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
103f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
104f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CDECL_END
105f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
106f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/* do not close UCA returned by ucol_initUCA! */
107f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)UCollator *
108f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_initUCA(UErrorCode *status) {
109f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(U_FAILURE(*status)) {
110f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
111f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
112f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UBool needsInit;
113f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UMTX_CHECK(NULL, (_staticUCA == NULL), needsInit);
114f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
115f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(needsInit) {
116f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, UCA_DATA_TYPE, UCA_DATA_NAME, isAcceptableUCA, NULL, status);
117f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
118f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(U_SUCCESS(*status)){
119f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            UCollator *newUCA = ucol_initCollator((const UCATableHeader *)udata_getMemory(result), NULL, NULL, status);
120f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(U_SUCCESS(*status)){
121f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                // Initalize variables for implicit generation
122f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                uprv_uca_initImplicitConstants(status);
123f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
124f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                umtx_lock(NULL);
125f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if(_staticUCA == NULL) {
126f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    UCA_DATA_MEM = result;
127f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    _staticUCA = newUCA;
128f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    newUCA = NULL;
129f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    result = NULL;
130f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
131f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                umtx_unlock(NULL);
132f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
133f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup);
134f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if(newUCA != NULL) {
135f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    ucol_close(newUCA);
136f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    udata_close(result);
137f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
138f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }else{
139f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                ucol_close(newUCA);
140f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                udata_close(result);
141f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
142f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
143f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        else {
144f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            udata_close(result);
145f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
146f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
147f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return _staticUCA;
148f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
149f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
150f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI void U_EXPORT2
151f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_forgetUCA(void)
152f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
153f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    _staticUCA = NULL;
154f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UCA_DATA_MEM = NULL;
155f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
156f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
157f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/****************************************************************************/
158f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/* Following are the open/close functions                                   */
159f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/*                                                                          */
160f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/****************************************************************************/
161f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static UCollator*
162f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)tryOpeningFromRules(UResourceBundle *collElem, UErrorCode *status) {
163f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t rulesLen = 0;
164f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UChar *rules = ures_getStringByKey(collElem, "Sequence", &rulesLen, status);
165f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return ucol_openRules(rules, rulesLen, UCOL_DEFAULT, UCOL_DEFAULT, NULL, status);
166f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
167f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
168f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
169f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// API in ucol_imp.h
170f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
171f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CFUNC UCollator*
172f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_open_internal(const char *loc,
173f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                   UErrorCode *status)
174f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
175f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UErrorCode intStatus = U_ZERO_ERROR;
176f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UCollator* UCA = ucol_initUCA(status);
177f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
178f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* New version */
179f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(U_FAILURE(*status)) return 0;
180f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
181f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
182f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
183f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UCollator *result = NULL;
184f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UResourceBundle *b = ures_open(U_ICUDATA_COLL, loc, status);
185f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
186f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* we try to find stuff from keyword */
187f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UResourceBundle *collations = ures_getByKey(b, "collations", NULL, status);
188f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UResourceBundle *collElem = NULL;
189f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    char keyBuffer[256];
190f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // if there is a keyword, we pick it up and try to get elements
191f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(!uloc_getKeywordValue(loc, "collation", keyBuffer, 256, status) ||
192f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        !uprv_strcmp(keyBuffer,"default")) { /* Treat 'zz@collation=default' as 'zz'. */
193f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // no keyword. we try to find the default setting, which will give us the keyword value
194f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        intStatus = U_ZERO_ERROR;
195f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // finding default value does not affect collation fallback status
196f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UResourceBundle *defaultColl = ures_getByKeyWithFallback(collations, "default", NULL, &intStatus);
197f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(U_SUCCESS(intStatus)) {
198f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            int32_t defaultKeyLen = 0;
199f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            const UChar *defaultKey = ures_getString(defaultColl, &defaultKeyLen, &intStatus);
200f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            u_UCharsToChars(defaultKey, keyBuffer, defaultKeyLen);
201f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            keyBuffer[defaultKeyLen] = 0;
202f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        } else {
203f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            *status = U_INTERNAL_PROGRAM_ERROR;
204f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            return NULL;
205f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
206f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ures_close(defaultColl);
207f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
208f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    collElem = ures_getByKeyWithFallback(collations, keyBuffer, collations, status);
209f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    collations = NULL; // We just reused the collations object as collElem.
210f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
211f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UResourceBundle *binary = NULL;
212f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UResourceBundle *reorderRes = NULL;
213f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
214f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(*status == U_MISSING_RESOURCE_ERROR) { /* We didn't find the tailoring data, we fallback to the UCA */
215f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_USING_DEFAULT_WARNING;
216f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result = ucol_initCollator(UCA->image, result, UCA, status);
217f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (U_FAILURE(*status)) {
218f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            goto clean;
219f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
220f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // if we use UCA, real locale is root
221f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ures_close(b);
222f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        b = ures_open(U_ICUDATA_COLL, "", status);
223f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ures_close(collElem);
224f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        collElem = ures_open(U_ICUDATA_COLL, "", status);
225f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(U_FAILURE(*status)) {
226f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            goto clean;
227f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
228f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->hasRealData = FALSE;
229f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else if(U_SUCCESS(*status)) {
230f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        intStatus = U_ZERO_ERROR;
231f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
232f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        binary = ures_getByKey(collElem, "%%CollationBin", NULL, &intStatus);
233f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
234f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(intStatus == U_MISSING_RESOURCE_ERROR) { /* we didn't find the binary image, we should use the rules */
235f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            binary = NULL;
236f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            result = tryOpeningFromRules(collElem, status);
237f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(U_FAILURE(*status)) {
238f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                goto clean;
239f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
240f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        } else if(U_SUCCESS(intStatus)) { /* otherwise, we'll pick a collation data that exists */
241f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            int32_t len = 0;
242f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            const uint8_t *inData = ures_getBinary(binary, &len, status);
243f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(U_FAILURE(*status)) {
244f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                goto clean;
245f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
246f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            UCATableHeader *colData = (UCATableHeader *)inData;
247f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(uprv_memcmp(colData->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0 ||
248f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                uprv_memcmp(colData->UCDVersion, UCA->image->UCDVersion, sizeof(UVersionInfo)) != 0 ||
249f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                colData->version[0] != UCOL_BUILDER_VERSION)
250f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            {
251f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                *status = U_DIFFERENT_UCA_VERSION;
252f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                result = tryOpeningFromRules(collElem, status);
253f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            } else {
254f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if(U_FAILURE(*status)){
255f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    goto clean;
256f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
257f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if((uint32_t)len > (paddedsize(sizeof(UCATableHeader)) + paddedsize(sizeof(UColOptionSet)))) {
258f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    result = ucol_initCollator((const UCATableHeader *)inData, result, UCA, status);
259f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    if(U_FAILURE(*status)){
260f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        goto clean;
261f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
262f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    result->hasRealData = TRUE;
263f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                } else {
264f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    result = ucol_initCollator(UCA->image, result, UCA, status);
265f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    ucol_setOptionsFromHeader(result, (UColOptionSet *)(inData+((const UCATableHeader *)inData)->options), status);
266f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    if(U_FAILURE(*status)){
267f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        goto clean;
268f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
269f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    result->hasRealData = FALSE;
270f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
271f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                result->freeImageOnClose = FALSE;
272f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
273f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                reorderRes = ures_getByKey(collElem, "%%ReorderCodes", NULL, &intStatus);
274f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if (U_SUCCESS(intStatus)) {
275f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    int32_t reorderCodesLen = 0;
276f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    const int32_t* reorderCodes = ures_getIntVector(reorderRes, &reorderCodesLen, status);
277f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    ucol_setReorderCodes(result, reorderCodes, reorderCodesLen, status);
278f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    if (U_FAILURE(*status)) {
279f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        goto clean;
280f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
281f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
282f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
283f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
284f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        } else { // !U_SUCCESS(binaryStatus)
285f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(U_SUCCESS(*status)) {
286f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                *status = intStatus; // propagate underlying error
287f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
288f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            goto clean;
289f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
290f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        intStatus = U_ZERO_ERROR;
291f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->rules = ures_getStringByKey(collElem, "Sequence", &result->rulesLength, &intStatus);
292f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->freeRulesOnClose = FALSE;
293f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else { /* There is another error, and we're just gonna clean up */
294f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        goto clean;
295f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
296f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
297f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    intStatus = U_ZERO_ERROR;
298f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    result->ucaRules = ures_getStringByKey(b,"UCARules",NULL,&intStatus);
299f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
300f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(loc == NULL) {
301f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        loc = ures_getLocaleByType(b, ULOC_ACTUAL_LOCALE, status);
302f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
303f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    result->requestedLocale = uprv_strdup(loc);
304f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* test for NULL */
305f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (result->requestedLocale == NULL) {
306f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_MEMORY_ALLOCATION_ERROR;
307f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        goto clean;
308f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
309f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    loc = ures_getLocaleByType(collElem, ULOC_ACTUAL_LOCALE, status);
310f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    result->actualLocale = uprv_strdup(loc);
311f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* test for NULL */
312f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (result->actualLocale == NULL) {
313f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_MEMORY_ALLOCATION_ERROR;
314f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        goto clean;
315f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
316f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    loc = ures_getLocaleByType(b, ULOC_ACTUAL_LOCALE, status);
317f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    result->validLocale = uprv_strdup(loc);
318f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* test for NULL */
319f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (result->validLocale == NULL) {
320f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_MEMORY_ALLOCATION_ERROR;
321f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        goto clean;
322f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
323f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
324f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(b);
325f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(collElem);
326f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(binary);
327f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(reorderRes);
328f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return result;
329f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
330f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)clean:
331f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(b);
332f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(collElem);
333f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(binary);
334f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(reorderRes);
335f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_close(result);
336f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return NULL;
337f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
338f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
339f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI UCollator*
340f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_open(const char *loc,
341f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)          UErrorCode *status)
342f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
343f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    U_NAMESPACE_USE
344f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
345f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN);
346f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UTRACE_DATA1(UTRACE_INFO, "locale = \"%s\"", loc);
347f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UCollator *result = NULL;
348f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
349f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#if !UCONFIG_NO_SERVICE
350f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    result = Collator::createUCollator(loc, status);
351f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (result == NULL)
352f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#endif
353f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    {
354f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result = ucol_open_internal(loc, status);
355f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
356f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UTRACE_EXIT_PTR_STATUS(result, *status);
357f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return result;
358f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
359f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
360f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
361f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)UCollator*
362f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_openRulesForImport( const UChar        *rules,
363f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         int32_t            rulesLength,
364f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         UColAttributeValue normalizationMode,
365f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         UCollationStrength strength,
366f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         UParseError        *parseError,
367f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         GetCollationRulesFunction  importFunc,
368f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         void* context,
369f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         UErrorCode         *status)
370f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
371f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UColTokenParser src;
372f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UColAttributeValue norm;
373f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UParseError tErr;
374f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
375f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(status == NULL || U_FAILURE(*status)){
376f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
377f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
378f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
379f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(rules == NULL || rulesLength < -1) {
380f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_ILLEGAL_ARGUMENT_ERROR;
381f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
382f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
383f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
384f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(rulesLength == -1) {
385f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        rulesLength = u_strlen(rules);
386f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
387f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
388f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(parseError == NULL){
389f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        parseError = &tErr;
390f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
391f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
392f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    switch(normalizationMode) {
393f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    case UCOL_OFF:
394f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    case UCOL_ON:
395f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    case UCOL_DEFAULT:
396f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        norm = normalizationMode;
397f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        break;
398f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    default:
399f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_ILLEGAL_ARGUMENT_ERROR;
400f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
401f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
402f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
403f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UCollator *result = NULL;
404f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UCATableHeader *table = NULL;
405f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UCollator *UCA = ucol_initUCA(status);
406f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
407f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(U_FAILURE(*status)){
408f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
409f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
410f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
411f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_tok_initTokenList(&src, rules, rulesLength, UCA, importFunc, context, status);
412f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_tok_assembleTokenList(&src,parseError, status);
413f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
414f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(U_FAILURE(*status)) {
415f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* if status is U_ILLEGAL_ARGUMENT_ERROR, src->current points at the offending option */
416f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* if status is U_INVALID_FORMAT_ERROR, src->current points after the problematic part of the rules */
417f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* so something might be done here... or on lower level */
418f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#ifdef UCOL_DEBUG
419f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(*status == U_ILLEGAL_ARGUMENT_ERROR) {
420f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "bad option starting at offset %i\n", (int)(src.current-src.source));
421f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        } else {
422f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "invalid rule just before offset %i\n", (int)(src.current-src.source));
423f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
424f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#endif
425f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        goto cleanup;
426f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
427f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
428f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(src.resultLen > 0 || src.removeSet != NULL) { /* we have a set of rules, let's make something of it */
429f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* also, if we wanted to remove some contractions, we should make a tailoring */
430f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        table = ucol_assembleTailoringTable(&src, status);
431f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(U_SUCCESS(*status)) {
432f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            // builder version
433f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            table->version[0] = UCOL_BUILDER_VERSION;
434f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            // no tailoring information on this level
435f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            table->version[1] = table->version[2] = table->version[3] = 0;
436f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            // set UCD version
437f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            u_getUnicodeVersion(table->UCDVersion);
438f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            // set UCA version
439f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uprv_memcpy(table->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo));
440f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            result = ucol_initCollator(table, 0, UCA, status);
441f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if (U_FAILURE(*status)) {
442f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                goto cleanup;
443f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
444f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            result->hasRealData = TRUE;
445f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            result->freeImageOnClose = TRUE;
446f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
447f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else { /* no rules, but no error either */
448f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // must be only options
449f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // We will init the collator from UCA
450f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result = ucol_initCollator(UCA->image, 0, UCA, status);
451f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // Check for null result
452f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (U_FAILURE(*status)) {
453f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            goto cleanup;
454f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
455f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // And set only the options
456f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UColOptionSet *opts = (UColOptionSet *)uprv_malloc(sizeof(UColOptionSet));
457f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* test for NULL */
458f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (opts == NULL) {
459f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            *status = U_MEMORY_ALLOCATION_ERROR;
460f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            goto cleanup;
461f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
462f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        uprv_memcpy(opts, src.opts, sizeof(UColOptionSet));
463f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ucol_setOptionsFromHeader(result, opts, status);
464f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ucol_setReorderCodesFromParser(result, &src, status);
465f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->freeOptionsOnClose = TRUE;
466f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->hasRealData = FALSE;
467f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->freeImageOnClose = FALSE;
468f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
469f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
470f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(U_SUCCESS(*status)) {
471f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar *newRules;
472f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->dataVersion[0] = UCOL_BUILDER_VERSION;
473f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(rulesLength > 0) {
474f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            newRules = (UChar *)uprv_malloc((rulesLength+1)*U_SIZEOF_UCHAR);
475f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            /* test for NULL */
476f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if (newRules == NULL) {
477f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                *status = U_MEMORY_ALLOCATION_ERROR;
478f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                goto cleanup;
479f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
480f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uprv_memcpy(newRules, rules, rulesLength*U_SIZEOF_UCHAR);
481f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            newRules[rulesLength]=0;
482f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            result->rules = newRules;
483f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            result->rulesLength = rulesLength;
484f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            result->freeRulesOnClose = TRUE;
485f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
486f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->ucaRules = NULL;
487f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->actualLocale = NULL;
488f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->validLocale = NULL;
489f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result->requestedLocale = NULL;
490f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ucol_buildPermutationTable(result, status);
491f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ucol_setAttribute(result, UCOL_STRENGTH, strength, status);
492f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ucol_setAttribute(result, UCOL_NORMALIZATION_MODE, norm, status);
493f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else {
494f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)cleanup:
495f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(result != NULL) {
496f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ucol_close(result);
497f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        } else {
498f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(table != NULL) {
499f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                uprv_free(table);
500f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
501f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
502f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result = NULL;
503f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
504f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
505f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_tok_closeTokenList(&src);
506f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
507f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return result;
508f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
509f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
510f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI UCollator* U_EXPORT2
511f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_openRules( const UChar        *rules,
512f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)               int32_t            rulesLength,
513f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)               UColAttributeValue normalizationMode,
514f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)               UCollationStrength strength,
515f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)               UParseError        *parseError,
516f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)               UErrorCode         *status)
517f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
518f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return ucol_openRulesForImport(rules,
519f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                   rulesLength,
520f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                   normalizationMode,
521f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                   strength,
522f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                   parseError,
523f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                   ucol_tok_getRulesFromBundle,
524f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                   NULL,
525f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                   status);
526f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
527f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
528f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI int32_t U_EXPORT2
529f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getRulesEx(const UCollator *coll, UColRuleOption delta, UChar *buffer, int32_t bufferLen) {
530f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UErrorCode status = U_ZERO_ERROR;
531f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t len = 0;
532f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t UCAlen = 0;
533f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UChar* ucaRules = 0;
534f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UChar *rules = ucol_getRules(coll, &len);
535f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(delta == UCOL_FULL_RULES) {
536f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* take the UCA rules and append real rules at the end */
537f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* UCA rules will be probably coming from the root RB */
538f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ucaRules = coll->ucaRules;
539f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (ucaRules) {
540f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            UCAlen = u_strlen(ucaRules);
541f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
542f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /*
543f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ucaRules = ures_getStringByKey(coll->rb,"UCARules",&UCAlen,&status);
544f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UResourceBundle* cresb = ures_getByKeyWithFallback(coll->rb, "collations", NULL, &status);
545f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UResourceBundle*  uca = ures_getByKeyWithFallback(cresb, "UCA", NULL, &status);
546f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ucaRules = ures_getStringByKey(uca,"Sequence",&UCAlen,&status);
547f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ures_close(uca);
548f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ures_close(cresb);
549f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        */
550f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
551f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(U_FAILURE(status)) {
552f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
553f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
554f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(buffer!=0 && bufferLen>0){
555f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *buffer=0;
556f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(UCAlen > 0) {
557f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            u_memcpy(buffer, ucaRules, uprv_min(UCAlen, bufferLen));
558f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
559f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(len > 0 && bufferLen > UCAlen) {
560f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            u_memcpy(buffer+UCAlen, rules, uprv_min(len, bufferLen-UCAlen));
561f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
562f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
563f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return u_terminateUChars(buffer, bufferLen, len+UCAlen, &status);
564f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
565f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
566f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static const UChar _NUL = 0;
567f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
568f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI const UChar* U_EXPORT2
569f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getRules(    const    UCollator       *coll,
570f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)              int32_t            *length)
571f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
572f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(coll->rules != NULL) {
573f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *length = coll->rulesLength;
574f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return coll->rules;
575f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
576f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    else {
577f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *length = 0;
578f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return &_NUL;
579f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
580f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
581f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
582f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI UBool U_EXPORT2
583f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_equals(const UCollator *source, const UCollator *target) {
584f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UErrorCode status = U_ZERO_ERROR;
585f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // if pointers are equal, collators are equal
586f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(source == target) {
587f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return TRUE;
588f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
589f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t i = 0, j = 0;
590f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // if any of attributes are different, collators are not equal
591f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for(i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) {
592f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(ucol_getAttribute(source, (UColAttribute)i, &status) != ucol_getAttribute(target, (UColAttribute)i, &status) || U_FAILURE(status)) {
593f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            return FALSE;
594f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
595f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
596f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (source->reorderCodesLength != target->reorderCodesLength){
597f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return FALSE;
598f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
599f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (i = 0; i < source->reorderCodesLength; i++) {
600f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(source->reorderCodes[i] != target->reorderCodes[i]) {
601f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            return FALSE;
602f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
603f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
604f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
605f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t sourceRulesLen = 0, targetRulesLen = 0;
606f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UChar *sourceRules = ucol_getRules(source, &sourceRulesLen);
607f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UChar *targetRules = ucol_getRules(target, &targetRulesLen);
608f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
609f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(sourceRulesLen == targetRulesLen && u_strncmp(sourceRules, targetRules, sourceRulesLen) == 0) {
610f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // all the attributes are equal and the rules are equal - collators are equal
611f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return(TRUE);
612f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
613f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // hard part, need to construct tree from rules and see if they yield the same tailoring
614f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UBool result = TRUE;
615f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UParseError parseError;
616f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UColTokenParser sourceParser, targetParser;
617f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t sourceListLen = 0, targetListLen = 0;
618f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_tok_initTokenList(&sourceParser, sourceRules, sourceRulesLen, source->UCA, ucol_tok_getRulesFromBundle, NULL, &status);
619f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_tok_initTokenList(&targetParser, targetRules, targetRulesLen, target->UCA, ucol_tok_getRulesFromBundle, NULL, &status);
620f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    sourceListLen = ucol_tok_assembleTokenList(&sourceParser, &parseError, &status);
621f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    targetListLen = ucol_tok_assembleTokenList(&targetParser, &parseError, &status);
622f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
623f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(sourceListLen != targetListLen) {
624f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // different number of resets
625f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result = FALSE;
626f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else {
627f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UColToken *sourceReset = NULL, *targetReset = NULL;
628f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar *sourceResetString = NULL, *targetResetString = NULL;
629f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t sourceStringLen = 0, targetStringLen = 0;
630f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        for(i = 0; i < sourceListLen; i++) {
631f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            sourceReset = sourceParser.lh[i].reset;
632f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            sourceResetString = sourceParser.source+(sourceReset->source & 0xFFFFFF);
633f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            sourceStringLen = sourceReset->source >> 24;
634f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            for(j = 0; j < sourceListLen; j++) {
635f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                targetReset = targetParser.lh[j].reset;
636f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                targetResetString = targetParser.source+(targetReset->source & 0xFFFFFF);
637f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                targetStringLen = targetReset->source >> 24;
638f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if(sourceStringLen == targetStringLen && (u_strncmp(sourceResetString, targetResetString, sourceStringLen) == 0)) {
639f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    sourceReset = sourceParser.lh[i].first;
640f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    targetReset = targetParser.lh[j].first;
641f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    while(sourceReset != NULL && targetReset != NULL) {
642f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        sourceResetString = sourceParser.source+(sourceReset->source & 0xFFFFFF);
643f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        sourceStringLen = sourceReset->source >> 24;
644f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        targetResetString = targetParser.source+(targetReset->source & 0xFFFFFF);
645f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        targetStringLen = targetReset->source >> 24;
646f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        if(sourceStringLen != targetStringLen || (u_strncmp(sourceResetString, targetResetString, sourceStringLen) != 0)) {
647f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                            result = FALSE;
648f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                            goto returnResult;
649f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        }
650f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        // probably also need to check the expansions
651f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        if(sourceReset->expansion) {
652f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                            if(!targetReset->expansion) {
653f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                result = FALSE;
654f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                goto returnResult;
655f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                            } else {
656f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                // compare expansions
657f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                sourceResetString = sourceParser.source+(sourceReset->expansion& 0xFFFFFF);
658f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                sourceStringLen = sourceReset->expansion >> 24;
659f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                targetResetString = targetParser.source+(targetReset->expansion & 0xFFFFFF);
660f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                targetStringLen = targetReset->expansion >> 24;
661f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                if(sourceStringLen != targetStringLen || (u_strncmp(sourceResetString, targetResetString, sourceStringLen) != 0)) {
662f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                    result = FALSE;
663f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                    goto returnResult;
664f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                }
665f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                            }
666f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        } else {
667f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                            if(targetReset->expansion) {
668f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                result = FALSE;
669f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                goto returnResult;
670f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                            }
671f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        }
672f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        sourceReset = sourceReset->next;
673f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        targetReset = targetReset->next;
674f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
675f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    if(sourceReset != targetReset) { // at least one is not NULL
676f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        // there are more tailored elements in one list
677f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        result = FALSE;
678f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        goto returnResult;
679f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
680f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
681f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
682f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    break;
683f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
684f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
685f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            // couldn't find the reset anchor, so the collators are not equal
686f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(j == sourceListLen) {
687f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                result = FALSE;
688f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                goto returnResult;
689f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
690f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
691f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
692f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
693f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)returnResult:
694f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_tok_closeTokenList(&sourceParser);
695f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_tok_closeTokenList(&targetParser);
696f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return result;
697f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
698f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
699f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
700f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI int32_t U_EXPORT2
701f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getDisplayName(    const    char        *objLoc,
702f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    const    char        *dispLoc,
703f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    UChar             *result,
704f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    int32_t         resultLength,
705f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    UErrorCode        *status)
706f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
707f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    U_NAMESPACE_USE
708f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
709f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(U_FAILURE(*status)) return -1;
710f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UnicodeString dst;
711f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(!(result==NULL && resultLength==0)) {
712f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // NULL destination for pure preflighting: empty dummy string
713f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // otherwise, alias the destination buffer
714f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        dst.setTo(result, 0, resultLength);
715f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
716f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    Collator::getDisplayName(Locale(objLoc), Locale(dispLoc), dst);
717f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return dst.extract(result, resultLength, *status);
718f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
719f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
720f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI const char* U_EXPORT2
721f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getAvailable(int32_t index)
722f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
723f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t count = 0;
724f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const Locale *loc = Collator::getAvailableLocales(count);
725f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (loc != NULL && index < count) {
726f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return loc[index].getName();
727f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
728f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return NULL;
729f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
730f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
731f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI int32_t U_EXPORT2
732f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_countAvailable()
733f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
734f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t count = 0;
735f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    Collator::getAvailableLocales(count);
736f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return count;
737f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
738f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
739f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#if !UCONFIG_NO_SERVICE
740f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI UEnumeration* U_EXPORT2
741f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_openAvailableLocales(UErrorCode *status) {
742f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    U_NAMESPACE_USE
743f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
744f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // This is a wrapper over Collator::getAvailableLocales()
745f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (U_FAILURE(*status)) {
746f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
747f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
748f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    StringEnumeration *s = Collator::getAvailableLocales();
749f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (s == NULL) {
750f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_MEMORY_ALLOCATION_ERROR;
751f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
752f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
753f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return uenum_openFromStringEnumeration(s, status);
754f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
755f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#endif
756f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
757f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Note: KEYWORDS[0] != RESOURCE_NAME - alan
758f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
759f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static const char RESOURCE_NAME[] = "collations";
760f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
761f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static const char* const KEYWORDS[] = { "collation" };
762f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
763f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#define KEYWORD_COUNT (sizeof(KEYWORDS)/sizeof(KEYWORDS[0]))
764f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
765f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI UEnumeration* U_EXPORT2
766f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getKeywords(UErrorCode *status) {
767f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UEnumeration *result = NULL;
768f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (U_SUCCESS(*status)) {
769f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return uenum_openCharStringsEnumeration(KEYWORDS, KEYWORD_COUNT, status);
770f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
771f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return result;
772f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
773f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
774f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI UEnumeration* U_EXPORT2
775f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getKeywordValues(const char *keyword, UErrorCode *status) {
776f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (U_FAILURE(*status)) {
777f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
778f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
779f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // hard-coded to accept exactly one collation keyword
780f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // modify if additional collation keyword is added later
781f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (keyword==NULL || uprv_strcmp(keyword, KEYWORDS[0])!=0)
782f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    {
783f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_ILLEGAL_ARGUMENT_ERROR;
784f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
785f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
786f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return ures_getKeywordValues(U_ICUDATA_COLL, RESOURCE_NAME, status);
787f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
788f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
789f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static const UEnumeration defaultKeywordValues = {
790f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    NULL,
791f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    NULL,
792f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ulist_close_keyword_values_iterator,
793f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ulist_count_keyword_values,
794f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uenum_unextDefault,
795f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ulist_next_keyword_value,
796f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ulist_reset_keyword_values_iterator
797f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)};
798f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
799f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include <stdio.h>
800f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
801f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI UEnumeration* U_EXPORT2
802f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale,
803f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                               UBool /*commonlyUsed*/, UErrorCode* status) {
804f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* Get the locale base name. */
805f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    char localeBuffer[ULOC_FULLNAME_CAPACITY] = "";
806f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uloc_getBaseName(locale, localeBuffer, sizeof(localeBuffer), status);
807f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
808f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* Create the 2 lists
809f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * -values is the temp location for the keyword values
810f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * -results hold the actual list used by the UEnumeration object
811f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     */
812f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UList *values = ulist_createEmptyList(status);
813f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UList *results = ulist_createEmptyList(status);
814f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
815f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (U_FAILURE(*status) || en == NULL) {
816f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (en == NULL) {
817f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            *status = U_MEMORY_ALLOCATION_ERROR;
818f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        } else {
819f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uprv_free(en);
820f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
821f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ulist_deleteList(values);
822f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ulist_deleteList(results);
823f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
824f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
825f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
826f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
827f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    en->context = results;
828f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
829f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* Open the resource bundle for collation with the given locale. */
830f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UResourceBundle bundle, collations, collres, defres;
831f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_initStackObject(&bundle);
832f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_initStackObject(&collations);
833f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_initStackObject(&collres);
834f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_initStackObject(&defres);
835f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
836f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
837f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
838f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    while (U_SUCCESS(*status)) {
839f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ures_getByKey(&bundle, RESOURCE_NAME, &collations, status);
840f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ures_resetIterator(&collations);
841f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        while (U_SUCCESS(*status) && ures_hasNext(&collations)) {
842f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ures_getNextResource(&collations, &collres, status);
843f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            const char *key = ures_getKey(&collres);
844f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            /* If the key is default, get the string and store it in results list only
845f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)             * if results list is empty.
846f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)             */
847f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if (uprv_strcmp(key, "default") == 0) {
848f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if (ulist_getListSize(results) == 0) {
849f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    char *defcoll = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
850f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    int32_t defcollLength = ULOC_KEYWORDS_CAPACITY;
851f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
852f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    ures_getNextResource(&collres, &defres, status);
853f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#if U_CHARSET_FAMILY==U_ASCII_FAMILY
854f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)			/* optimize - use the utf-8 string */
855f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    ures_getUTF8String(&defres, defcoll, &defcollLength, TRUE, status);
856f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#else
857f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    {
858f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                       const UChar* defString = ures_getString(&defres, &defcollLength, status);
859f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                       if(U_SUCCESS(*status)) {
860f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)			   if(defcollLength+1 > ULOC_KEYWORDS_CAPACITY) {
861f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)				*status = U_BUFFER_OVERFLOW_ERROR;
862f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)			   } else {
863f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                           	u_UCharsToChars(defString, defcoll, defcollLength+1);
864f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)			   }
865f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                       }
866f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
867f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#endif
868f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
869f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    ulist_addItemBeginList(results, defcoll, TRUE, status);
870f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
871f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            } else {
872f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                ulist_addItemEndList(values, key, FALSE, status);
873f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
874f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
875f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
876f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* If the locale is "" this is root so exit. */
877f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (uprv_strlen(localeBuffer) == 0) {
878f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            break;
879f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
880f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* Get the parent locale and open a new resource bundle. */
881f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        uloc_getParent(localeBuffer, localeBuffer, sizeof(localeBuffer), status);
882f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
883f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
884f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
885f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(&defres);
886f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(&collres);
887f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(&collations);
888f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ures_close(&bundle);
889f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
890f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (U_SUCCESS(*status)) {
891f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        char *value = NULL;
892f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ulist_resetList(values);
893f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        while ((value = (char *)ulist_getNext(values)) != NULL) {
894f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if (!ulist_containsString(results, value, (int32_t)uprv_strlen(value))) {
895f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                ulist_addItemEndList(results, value, FALSE, status);
896f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if (U_FAILURE(*status)) {
897f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    break;
898f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
899f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
900f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
901f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
902f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
903f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ulist_deleteList(values);
904f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
905f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (U_FAILURE(*status)){
906f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        uenum_close(en);
907f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        en = NULL;
908f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else {
909f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ulist_resetList(results);
910f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
911f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
912f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return en;
913f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
914f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
915f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI int32_t U_EXPORT2
916f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getFunctionalEquivalent(char* result, int32_t resultCapacity,
917f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                             const char* keyword, const char* locale,
918f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                             UBool* isAvailable, UErrorCode* status)
919f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
920f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // N.B.: Resource name is "collations" but keyword is "collation"
921f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return ures_getFunctionalEquivalent(result, resultCapacity, U_ICUDATA_COLL,
922f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        "collations", keyword, locale,
923f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        isAvailable, TRUE, status);
924f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
925f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
926f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/* returns the locale name the collation data comes from */
927f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI const char * U_EXPORT2
928f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getLocale(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status) {
929f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return ucol_getLocaleByType(coll, type, status);
930f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
931f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
932f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI const char * U_EXPORT2
933f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getLocaleByType(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status) {
934f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const char *result = NULL;
935f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(status == NULL || U_FAILURE(*status)) {
936f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
937f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
938f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UTRACE_ENTRY(UTRACE_UCOL_GETLOCALE);
939f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UTRACE_DATA1(UTRACE_INFO, "coll=%p", coll);
940f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
941f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    switch(type) {
942f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    case ULOC_ACTUAL_LOCALE:
943f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result = coll->actualLocale;
944f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        break;
945f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    case ULOC_VALID_LOCALE:
946f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result = coll->validLocale;
947f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        break;
948f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    case ULOC_REQUESTED_LOCALE:
949f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result = coll->requestedLocale;
950f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        break;
951f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    default:
952f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_ILLEGAL_ARGUMENT_ERROR;
953f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
954f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UTRACE_DATA1(UTRACE_INFO, "result = %s", result);
955f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UTRACE_EXIT_STATUS(*status);
956f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return result;
957f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
958f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
959f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CFUNC void U_EXPORT2
960f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_setReqValidLocales(UCollator *coll, char *requestedLocaleToAdopt, char *validLocaleToAdopt, char *actualLocaleToAdopt)
961f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
962f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (coll) {
963f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (coll->validLocale) {
964f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uprv_free(coll->validLocale);
965f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
966f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        coll->validLocale = validLocaleToAdopt;
967f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (coll->requestedLocale) { // should always have
968f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uprv_free(coll->requestedLocale);
969f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
970f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        coll->requestedLocale = requestedLocaleToAdopt;
971f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (coll->actualLocale) {
972f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uprv_free(coll->actualLocale);
973f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
974f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        coll->actualLocale = actualLocaleToAdopt;
975f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
976f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
977f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
978f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI USet * U_EXPORT2
979f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_getTailoredSet(const UCollator *coll, UErrorCode *status)
980f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
981f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    U_NAMESPACE_USE
982f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
983f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(status == NULL || U_FAILURE(*status)) {
984f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
985f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
986f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(coll == NULL || coll->UCA == NULL) {
987f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_ILLEGAL_ARGUMENT_ERROR;
988f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
989f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
990f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UParseError parseError;
991f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UColTokenParser src;
992f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t rulesLen = 0;
993f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UChar *rules = ucol_getRules(coll, &rulesLen);
994f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UBool startOfRules = TRUE;
995f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // we internally use the C++ class, for the following reasons:
996f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // 1. we need to utilize canonical iterator, which is a C++ only class
997f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // 2. canonical iterator returns UnicodeStrings - USet cannot take them
998f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // 3. USet is internally really UnicodeSet, C is just a wrapper
999f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UnicodeSet *tailored = new UnicodeSet();
1000f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UnicodeString pattern;
1001f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UnicodeString empty;
1002f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    CanonicalIterator it(empty, *status);
1003f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1004f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1005f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // The idea is to tokenize the rule set. For each non-reset token,
1006f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // we add all the canonicaly equivalent FCD sequences
1007f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_tok_initTokenList(&src, rules, rulesLen, coll->UCA, ucol_tok_getRulesFromBundle, NULL, status);
1008f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    while (ucol_tok_parseNextToken(&src, startOfRules, &parseError, status) != NULL) {
1009f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        startOfRules = FALSE;
1010f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(src.parsedToken.strength != UCOL_TOK_RESET) {
1011f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            const UChar *stuff = src.source+(src.parsedToken.charsOffset);
1012f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            it.setSource(UnicodeString(stuff, src.parsedToken.charsLen), *status);
1013f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            pattern = it.next();
1014f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            while(!pattern.isBogus()) {
1015f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if(Normalizer::quickCheck(pattern, UNORM_FCD, *status) != UNORM_NO) {
1016f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    tailored->add(pattern);
1017f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
1018f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                pattern = it.next();
1019f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
1020f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1021f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1022f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_tok_closeTokenList(&src);
1023f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return (USet *)tailored;
1024f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
1025f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1026f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/*
1027f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * Collation Reordering
1028f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) */
1029f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1030f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static void ucol_setReorderCodesFromParser(UCollator *coll, UColTokenParser *parser, UErrorCode *status) {
1031f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (U_FAILURE(*status)) {
1032f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return;
1033f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1034f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1035f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    coll->reorderCodesLength = 0;
1036f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (coll->reorderCodes != NULL) {
1037f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        uprv_free(coll->reorderCodes);
1038f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1039f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1040f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (parser->reorderCodesLength == 0 || parser->reorderCodes == NULL) {
1041f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return;
1042f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1043f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1044f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    coll->reorderCodesLength = parser->reorderCodesLength;
1045f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    coll->reorderCodes = (int32_t*) uprv_malloc(coll->reorderCodesLength * sizeof(int32_t));
1046f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uprv_memcpy(coll->reorderCodes, parser->reorderCodes, coll->reorderCodesLength * sizeof(int32_t));
1047f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
1048f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1049f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static int ucol_getLeadBytesForReorderCode(UCollator *coll, int reorderCode, uint16_t* returnLeadBytes, int returnCapacity) {
1050f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uint16_t reorderCodeIndexLength = *((uint16_t*) ((uint8_t *)coll->UCA->image + coll->UCA->image->scriptToLeadByte));
1051f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uint16_t* reorderCodeIndex = (uint16_t*) ((uint8_t *)coll->UCA->image + coll->UCA->image->scriptToLeadByte + 2 *sizeof(uint16_t));
1052f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1053f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // TODO - replace with a binary search
1054f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // reorder code index is 2 uint16_t's - reorder code + offset
1055f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (int i = 0; i < reorderCodeIndexLength; i++) {
1056f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (reorderCode == reorderCodeIndex[i*2]) {
1057f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uint16_t dataOffset = reorderCodeIndex[(i*2) + 1];
1058f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if ((dataOffset & 0x8000) == 0x8000) {
1059f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                // offset isn't offset but instead is a single data element
1060f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if (returnCapacity >= 1) {
1061f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    returnLeadBytes[0] = dataOffset & ~0x8000;
1062f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    return 1;
1063f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
1064f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                return 0;
1065f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
1066f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uint16_t* dataOffsetBase = (uint16_t*) ((uint8_t *)reorderCodeIndex + reorderCodeIndexLength * (2 * sizeof(uint16_t)));
1067f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uint16_t leadByteCount = *(dataOffsetBase + dataOffset);
1068f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            leadByteCount = leadByteCount > returnCapacity ? returnCapacity : leadByteCount;
1069f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uprv_memcpy(returnLeadBytes, dataOffsetBase + dataOffset + 1, leadByteCount * sizeof(uint16_t));
1070f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            return leadByteCount;
1071f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1072f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1073f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return 0;
1074f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
1075f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1076f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static int ucol_getReorderCodesForLeadByte(UCollator *coll, int leadByte, int16_t* returnReorderCodes, int returnCapacity) {
1077f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int leadByteIndexLength = *((uint16_t*) ((uint8_t *)coll->UCA->image + coll->UCA->image->leadByteToScript));
1078f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uint16_t* leadByteIndex = (uint16_t*) ((uint8_t *)coll->UCA->image + coll->UCA->image->leadByteToScript + 2 *sizeof(uint16_t));
1079f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (leadByte >= leadByteIndexLength) {
1080f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
1081f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1082f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1083f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if ((leadByteIndex[leadByte] & 0x8000) == 0x8000) {
1084f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // offset isn't offset but instead is a single data element
1085f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (returnCapacity >= 1) {
1086f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            returnReorderCodes[0] = leadByteIndex[leadByte] & ~0x8000;
1087f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            return 1;
1088f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1089f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
1090f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1091f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uint16_t* dataOffsetBase = (uint16_t*) ((uint8_t *)leadByteIndex + leadByteIndexLength * (2 * sizeof(uint16_t)));
1092f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uint16_t reorderCodeCount = *(dataOffsetBase + leadByteIndex[leadByte]);
1093f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    reorderCodeCount = reorderCodeCount > returnCapacity ? returnCapacity : reorderCodeCount;
1094f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uprv_memcpy(returnReorderCodes, dataOffsetBase + leadByteIndex[leadByte] + 1, reorderCodeCount * sizeof(uint16_t));
1095f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return reorderCodeCount;
1096f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
1097f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1098f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// used to mark ignorable reorder code slots
1099f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static const int32_t UCOL_REORDER_CODE_IGNORE = UCOL_REORDER_CODE_LIMIT + 1;
1100f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1101f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)void ucol_buildPermutationTable(UCollator *coll, UErrorCode *status) {
1102f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uint16_t leadBytesSize = 256;
1103f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uint16_t leadBytes[256];
1104f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t internalReorderCodesLength = coll->reorderCodesLength + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST);
1105f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t* internalReorderCodes;
1106f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1107f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // The lowest byte that hasn't been assigned a mapping
1108f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int toBottom = 0x03;
1109f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // The highest byte that hasn't been assigned a mapping - don't include the special or trailing
1110f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int toTop = 0xe4;
1111f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1112f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // are we filling from the bottom?
1113f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    bool fromTheBottom = true;
1114f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1115f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // lead bytes that have alread been assigned to the permutation table
1116f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    bool newLeadByteUsed[256];
1117f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // permutation table slots that have already been filled
1118f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    bool permutationSlotFilled[256];
1119f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1120f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // nothing to do
1121f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(U_FAILURE(*status) || coll == NULL || coll->reorderCodesLength == 0) {
1122f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (coll != NULL) {
1123f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if (coll->leadBytePermutationTable != NULL) {
1124f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                uprv_free(coll->leadBytePermutationTable);
1125f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                coll->leadBytePermutationTable = NULL;
1126f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
1127f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            coll->reorderCodesLength = 0;
1128f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1129f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return;
1130f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1131f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1132f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (coll->leadBytePermutationTable == NULL) {
1133f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        coll->leadBytePermutationTable = (uint8_t*)uprv_malloc(256*sizeof(uint8_t));
1134f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (coll->leadBytePermutationTable == NULL) {
1135f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            *status = U_MEMORY_ALLOCATION_ERROR;
1136f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            return;
1137f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1138f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1139f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1140f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // prefill the reordering codes with the leading entries
1141f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    internalReorderCodes = (int32_t*)uprv_malloc(internalReorderCodesLength * sizeof(int32_t));
1142f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (internalReorderCodes == NULL) {
1143f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *status = U_MEMORY_ALLOCATION_ERROR;
1144f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (coll->leadBytePermutationTable != NULL) {
1145f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uprv_free(coll->leadBytePermutationTable);
1146f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            coll->leadBytePermutationTable = NULL;
1147f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1148f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return;
1149f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1150f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1151f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (uint32_t codeIndex = 0; codeIndex < (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST); codeIndex++) {
1152f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        internalReorderCodes[codeIndex] = UCOL_REORDER_CODE_FIRST + codeIndex;
1153f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1154f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (int32_t codeIndex = 0; codeIndex < coll->reorderCodesLength; codeIndex++) {
1155f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        uint32_t reorderCodesCode = coll->reorderCodes[codeIndex];
1156f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        internalReorderCodes[codeIndex + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST)] = reorderCodesCode;
1157f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (reorderCodesCode >= UCOL_REORDER_CODE_FIRST && reorderCodesCode < UCOL_REORDER_CODE_LIMIT) {
1158f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            internalReorderCodes[reorderCodesCode - UCOL_REORDER_CODE_FIRST] = UCOL_REORDER_CODE_IGNORE;
1159f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1160f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1161f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1162f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (int i = 0; i < 256; i++) {
1163f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (i < toBottom || i > toTop) {
1164f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            permutationSlotFilled[i] = true;
1165f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            newLeadByteUsed[i] = true;
1166f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            coll->leadBytePermutationTable[i] = i;
1167f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        } else {
1168f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            permutationSlotFilled[i] = false;
1169f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            newLeadByteUsed[i] = false;
1170f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            coll->leadBytePermutationTable[i] = 0;
1171f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1172f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1173f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1174f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* Start from the front of the list and place each script we encounter at the
1175f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * earliest possible locatation in the permutation table. If we encounter
1176f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * UNKNOWN, start processing from the back, and place each script in the last
1177f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * possible location. At each step, we also need to make sure that any scripts
1178f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * that need to not be moved are copied to their same location in the final table.
1179f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     */
1180f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (int reorderCodesIndex = 0; reorderCodesIndex < internalReorderCodesLength; reorderCodesIndex++) {
1181f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t next = internalReorderCodes[reorderCodesIndex];
1182f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (next == UCOL_REORDER_CODE_IGNORE) {
1183f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            continue;
1184f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1185f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (next == USCRIPT_UNKNOWN) {
1186f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if (fromTheBottom == false) {
1187f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                // double turnaround
1188f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                *status = U_ILLEGAL_ARGUMENT_ERROR;
1189f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if (coll->leadBytePermutationTable != NULL) {
1190f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    uprv_free(coll->leadBytePermutationTable);
1191f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    coll->leadBytePermutationTable = NULL;
1192f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
1193f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                coll->reorderCodesLength = 0;
1194f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if (internalReorderCodes != NULL) {
1195f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    uprv_free(internalReorderCodes);
1196f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
1197f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                return;
1198f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
1199f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fromTheBottom = false;
1200f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            continue;
1201f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1202f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1203f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        uint16_t leadByteCount = ucol_getLeadBytesForReorderCode(coll, next, leadBytes, leadBytesSize);
1204f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (fromTheBottom) {
1205f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            for (int leadByteIndex = 0; leadByteIndex < leadByteCount; leadByteIndex++) {
1206f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                // don't place a lead byte twice in the permutation table
1207f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if (permutationSlotFilled[leadBytes[leadByteIndex]]) {
1208f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    // lead byte already used
1209f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    *status = U_ILLEGAL_ARGUMENT_ERROR;
1210f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    if (coll->leadBytePermutationTable != NULL) {
1211f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        uprv_free(coll->leadBytePermutationTable);
1212f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        coll->leadBytePermutationTable = NULL;
1213f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
1214f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    coll->reorderCodesLength = 0;
1215f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    if (internalReorderCodes != NULL) {
1216f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        uprv_free(internalReorderCodes);
1217f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
1218f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    return;
1219f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
1220f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1221f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                coll->leadBytePermutationTable[leadBytes[leadByteIndex]] = toBottom;
1222f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                newLeadByteUsed[toBottom] = true;
1223f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                permutationSlotFilled[leadBytes[leadByteIndex]] = true;
1224f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                toBottom++;
1225f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
1226f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        } else {
1227f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            for (int leadByteIndex = leadByteCount - 1; leadByteIndex >= 0; leadByteIndex--) {
1228f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                // don't place a lead byte twice in the permutation table
1229f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if (permutationSlotFilled[leadBytes[leadByteIndex]]) {
1230f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    // lead byte already used
1231f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    *status = U_ILLEGAL_ARGUMENT_ERROR;
1232f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    if (coll->leadBytePermutationTable != NULL) {
1233f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        uprv_free(coll->leadBytePermutationTable);
1234f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        coll->leadBytePermutationTable = NULL;
1235f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
1236f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    coll->reorderCodesLength = 0;
1237f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    if (internalReorderCodes != NULL) {
1238f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        uprv_free(internalReorderCodes);
1239f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
1240f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    return;
1241f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
1242f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1243f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                coll->leadBytePermutationTable[leadBytes[leadByteIndex]] = toTop;
1244f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                newLeadByteUsed[toTop] = true;
1245f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                permutationSlotFilled[leadBytes[leadByteIndex]] = true;
1246f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                toTop--;
1247f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
1248f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1249f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1250f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1251f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#ifdef REORDER_DEBUG
1252f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    fprintf(stdout, "\n@@@@ Partial Script Reordering Table\n");
1253f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (int i = 0; i < 256; i++) {
1254f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        fprintf(stdout, "\t%02x = %02x\n", i, coll->leadBytePermutationTable[i]);
1255f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1256f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    fprintf(stdout, "\n@@@@ Lead Byte Used Table\n");
1257f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (int i = 0; i < 256; i++) {
1258f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        fprintf(stdout, "\t%02x = %02x\n", i, newLeadByteUsed[i]);
1259f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1260f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    fprintf(stdout, "\n@@@@ Permutation Slot Filled Table\n");
1261f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (int i = 0; i < 256; i++) {
1262f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        fprintf(stdout, "\t%02x = %02x\n", i, permutationSlotFilled[i]);
1263f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1264f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#endif
1265f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1266f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* Copy everything that's left over */
1267f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int reorderCode = 0;
1268f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (int i = 0; i < 256; i++) {
1269f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (!permutationSlotFilled[i]) {
1270f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            while (reorderCode < 256 && newLeadByteUsed[reorderCode]) {
1271f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                reorderCode++;
1272f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
1273f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            coll->leadBytePermutationTable[i] = reorderCode;
1274f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            permutationSlotFilled[i] = true;
1275f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            newLeadByteUsed[reorderCode] = true;
1276f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
1277f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1278f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1279f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#ifdef REORDER_DEBUG
1280f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    fprintf(stdout, "\n@@@@ Script Reordering Table\n");
1281f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    for (int i = 0; i < 256; i++) {
1282f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        fprintf(stdout, "\t%02x = %02x\n", i, coll->leadBytePermutationTable[i]);
1283f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1284f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#endif
1285f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1286f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (internalReorderCodes != NULL) {
1287f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        uprv_free(internalReorderCodes);
1288f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
1289f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1290f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // force a regen of the latin one table since it is affected by the script reordering
1291f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    coll->latinOneRegenTable = TRUE;
1292f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ucol_updateInternalState(coll, status);
1293f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
1294f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
1295f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#endif /* #if !UCONFIG_NO_COLLATION */
1296