1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*******************************************************************************
3fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*   Copyright (C) 1996-2014, International Business Machines
4b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   Corporation and others.  All Rights Reserved.
5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*******************************************************************************
6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   file name:  ucol_res.cpp
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   encoding:   US-ASCII
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   tab size:   8 (not used)
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   indentation:4
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Description:
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* This file contains dependencies that the collation run-time doesn't normally
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* need. This mainly contains resource bundle usage and collation meta information
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Modification history
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Date        Name      Comments
17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* 1996-1999   various members of ICU team maintained C API for collation framework
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* 02/16/2001  synwee    Added internal method getPrevSpecialCE
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* 03/01/2001  synwee    Added maxexpansion functionality.
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* 03/16/2001  weiv      Collation framework is rewritten in C and made UCA compliant
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* 12/08/2004  grhoten   Split part of ucol.cpp into ucol_res.cpp
22fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* 2012-2014   markus    Rewritten in C++ again.
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/utypes.h"
26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if !UCONFIG_NO_COLLATION
28fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/coll.h"
30fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/localpointer.h"
31fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/locid.h"
32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/tblcoll.h"
33fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/ucol.h"
34fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/uloc.h"
35fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/unistr.h"
36fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/ures.h"
37fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "cmemory.h"
38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cstring.h"
39fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationdatareader.h"
40fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationroot.h"
41fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationtailoring.h"
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "putilimp.h"
4359d709d503bab6e2b61931737e662dd293b40578ccornelius#include "uassert.h"
44fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "ucln_in.h"
45fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "ucol_imp.h"
46b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "uenumimp.h"
47b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "ulist.h"
48fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "umutex.h"
49fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "uresimp.h"
50fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "ustrenum.h"
51fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "utracimp.h"
52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
53fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
54b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
55fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_BEGIN
5627f654740f2a26ad62a5c155af9199af9e69b889claireho
57fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusnamespace {
58fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
59fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic const UChar *rootRules = NULL;
60fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic int32_t rootRulesLength = 0;
61fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UResourceBundle *rootBundle = NULL;
62fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UInitOnce gInitOnce = U_INITONCE_INITIALIZER;
63fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
64fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}  // namespace
65c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_BEGIN
67fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
68c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic UBool U_CALLCONV
69fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusucol_res_cleanup() {
70fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    rootRules = NULL;
71fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    rootRulesLength = 0;
72fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    ures_close(rootBundle);
73fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    rootBundle = NULL;
74fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    gInitOnce.reset();
75c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return TRUE;
76c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
77c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_END
79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
80fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
81fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationLoader::loadRootRules(UErrorCode &errorCode) {
82fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return; }
83fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    rootBundle = ures_open(U_ICUDATA_COLL, kRootLocaleName, &errorCode);
84fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return; }
85fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    rootRules = ures_getStringByKey(rootBundle, "UCARules", &rootRulesLength, &errorCode);
86fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) {
87fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        ures_close(rootBundle);
88fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        rootBundle = NULL;
8959d709d503bab6e2b61931737e662dd293b40578ccornelius        return;
90c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
91fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup);
92c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
93c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
94fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
95fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationLoader::appendRootRules(UnicodeString &s) {
96fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UErrorCode errorCode = U_ZERO_ERROR;
97fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    umtx_initOnce(gInitOnce, CollationLoader::loadRootRules, errorCode);
98fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_SUCCESS(errorCode)) {
99fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        s.append(rootRules, rootRulesLength);
100fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
101c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
102c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
103fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUnicodeString *
104fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationLoader::loadRules(const char *localeID, const char *collationType, UErrorCode &errorCode) {
105fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return NULL; }
106fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    U_ASSERT(collationType != NULL && *collationType != 0);
107dbc22bd174be483711cea006f3189d8289835830ccornelius    // Copy the type for lowercasing.
108dbc22bd174be483711cea006f3189d8289835830ccornelius    char type[16];
109dbc22bd174be483711cea006f3189d8289835830ccornelius    int32_t typeLength = uprv_strlen(collationType);
110dbc22bd174be483711cea006f3189d8289835830ccornelius    if(typeLength >= LENGTHOF(type)) {
111dbc22bd174be483711cea006f3189d8289835830ccornelius        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
112dbc22bd174be483711cea006f3189d8289835830ccornelius        return NULL;
113dbc22bd174be483711cea006f3189d8289835830ccornelius    }
114dbc22bd174be483711cea006f3189d8289835830ccornelius    uprv_memcpy(type, collationType, typeLength + 1);
115dbc22bd174be483711cea006f3189d8289835830ccornelius    T_CString_toLowerCase(type);
116fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
117fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer bundle(ures_open(U_ICUDATA_COLL, localeID, &errorCode));
118fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer collations(
119fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKey(bundle.getAlias(), "collations", NULL, &errorCode));
120fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer data(
121dbc22bd174be483711cea006f3189d8289835830ccornelius            ures_getByKeyWithFallback(collations.getAlias(), type, NULL, &errorCode));
122fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t length;
123fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const UChar *s =  ures_getStringByKey(data.getAlias(), "Sequence", &length, &errorCode);
124fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return NULL; }
125fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
126fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // No string pointer aliasing so that we need not hold onto the resource bundle.
127fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UnicodeString *rules = new UnicodeString(s, length);
128fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(rules == NULL) {
129fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_MEMORY_ALLOCATION_ERROR;
130fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
131fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
132fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return rules;
133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
135fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusconst CollationTailoring *
136fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationLoader::loadTailoring(const Locale &locale, Locale &validLocale, UErrorCode &errorCode) {
137fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const CollationTailoring *root = CollationRoot::getRoot(errorCode);
138fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return NULL; }
139fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const char *name = locale.getName();
140fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(*name == 0 || uprv_strcmp(name, "root") == 0) {
141fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        validLocale = Locale::getRoot();
142fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return root;
143fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
144fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
145fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer bundle(ures_open(U_ICUDATA_COLL, name, &errorCode));
146fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(errorCode == U_MISSING_RESOURCE_ERROR) {
147fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_USING_DEFAULT_WARNING;
148fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        validLocale = Locale::getRoot();
149fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return root;
150fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
151fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const char *vLocale = ures_getLocaleByType(bundle.getAlias(), ULOC_ACTUAL_LOCALE, &errorCode);
152fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return NULL; }
153fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    validLocale = Locale(vLocale);
154fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
155fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // There are zero or more tailorings in the collations table.
156fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer collations(
157fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKey(bundle.getAlias(), "collations", NULL, &errorCode));
158fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(errorCode == U_MISSING_RESOURCE_ERROR) {
159fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_USING_DEFAULT_WARNING;
160fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return root;
161fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
162fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return NULL; }
163fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
164fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Fetch the collation type from the locale ID and the default type from the data.
165fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    char type[16];
166fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t typeLength = locale.getKeywordValue("collation", type, LENGTHOF(type) - 1, errorCode);
167fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) {
168fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
169fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
170fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
171fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    type[typeLength] = 0;  // in case of U_NOT_TERMINATED_WARNING
172fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    char defaultType[16];
173fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    {
174fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode internalErrorCode = U_ZERO_ERROR;
175fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        LocalUResourceBundlePointer def(
176fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                ures_getByKeyWithFallback(collations.getAlias(), "default", NULL,
177fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                          &internalErrorCode));
178fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        int32_t length;
179fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UChar *s = ures_getString(def.getAlias(), &length, &internalErrorCode);
180fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(U_SUCCESS(internalErrorCode) && length < LENGTHOF(defaultType)) {
181fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            u_UCharsToChars(s, defaultType, length + 1);
182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
183fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uprv_strcpy(defaultType, "standard");
184fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
185fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
186fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(typeLength == 0 || uprv_strcmp(type, "default") == 0) {
187fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uprv_strcpy(type, defaultType);
188dbc22bd174be483711cea006f3189d8289835830ccornelius    } else {
189dbc22bd174be483711cea006f3189d8289835830ccornelius        T_CString_toLowerCase(type);
190fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
191fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
192fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Load the collations/type tailoring, with type fallback.
193fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UBool typeFallback = FALSE;
194fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer data(
195fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKeyWithFallback(collations.getAlias(), type, NULL, &errorCode));
196fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(errorCode == U_MISSING_RESOURCE_ERROR &&
197fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            typeLength > 6 && uprv_strncmp(type, "search", 6) == 0) {
198fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // fall back from something like "searchjl" to "search"
199fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        typeFallback = TRUE;
200fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        type[6] = 0;
201fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_ZERO_ERROR;
202fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data.adoptInstead(
203fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKeyWithFallback(collations.getAlias(), type, NULL, &errorCode));
204fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
205fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(errorCode == U_MISSING_RESOURCE_ERROR && uprv_strcmp(type, defaultType) != 0) {
206fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // fall back to the default type
207fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        typeFallback = TRUE;
208fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uprv_strcpy(type, defaultType);
209fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_ZERO_ERROR;
210fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data.adoptInstead(
211fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKeyWithFallback(collations.getAlias(), type, NULL, &errorCode));
212fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
213fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(errorCode == U_MISSING_RESOURCE_ERROR && uprv_strcmp(type, "standard") != 0) {
214fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // fall back to the "standard" type
215fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        typeFallback = TRUE;
216fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uprv_strcpy(type, "standard");
217fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_ZERO_ERROR;
218fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data.adoptInstead(
219fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKeyWithFallback(collations.getAlias(), type, NULL, &errorCode));
220fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
221fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(errorCode == U_MISSING_RESOURCE_ERROR) {
222fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_USING_DEFAULT_WARNING;
223fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return root;
224fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
225fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return NULL; }
226fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
227fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalPointer<CollationTailoring> t(new CollationTailoring(root->settings));
228fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(t.isNull() || t->isBogus()) {
229fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_MEMORY_ALLOCATION_ERROR;
230fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
231b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
233fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Is this the same as the root collator? If so, then use that instead.
234fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const char *actualLocale = ures_getLocaleByType(data.getAlias(), ULOC_ACTUAL_LOCALE, &errorCode);
235fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return NULL; }
236fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((*actualLocale == 0 || uprv_strcmp(actualLocale, "root") == 0) &&
237fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uprv_strcmp(type, "standard") == 0) {
238fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(typeFallback) {
239fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_USING_DEFAULT_WARNING;
240fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
241fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return root;
242fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
243fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    t->actualLocale = Locale(actualLocale);
244fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
245fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // deserialize
246fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer binary(
247fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKey(data.getAlias(), "%%CollationBin", NULL, &errorCode));
248fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Note: U_MISSING_RESOURCE_ERROR --> The old code built from rules if available
249fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // but that created undesirable dependencies.
250fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t length;
251fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const uint8_t *inBytes = ures_getBinary(binary.getAlias(), &length, &errorCode);
252fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return NULL; }
253fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    CollationDataReader::read(root, inBytes, length, *t, errorCode);
254fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Note: U_COLLATOR_VERSION_MISMATCH --> The old code built from rules if available
255fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // but that created undesirable dependencies.
256fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return NULL; }
257fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
258fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Try to fetch the optional rules string.
259fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    {
260fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode internalErrorCode = U_ZERO_ERROR;
261fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        int32_t length;
262fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UChar *s = ures_getStringByKey(data.getAlias(), "Sequence", &length,
263fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                             &internalErrorCode);
264fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(U_SUCCESS(errorCode)) {
265fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            t->rules.setTo(TRUE, s, length);
266fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
267fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
268fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
269fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Set the collation types on the informational locales,
270fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // except when they match the default types (for brevity and backwards compatibility).
271fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // For the valid locale, suppress the default type.
272fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(uprv_strcmp(type, defaultType) != 0) {
273fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        validLocale.setKeywordValue("collation", type, errorCode);
274fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(U_FAILURE(errorCode)) { return NULL; }
275fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
276fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
277fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // For the actual locale, suppress the default type *according to the actual locale*.
278fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // For example, zh has default=pinyin and contains all of the Chinese tailorings.
279fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // zh_Hant has default=stroke but has no other data.
280fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // For the valid locale "zh_Hant" we need to suppress stroke.
281fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // For the actual locale "zh" we need to suppress pinyin instead.
282fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(uprv_strcmp(actualLocale, vLocale) != 0) {
283fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Opening a bundle for the actual locale should always succeed.
284fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        LocalUResourceBundlePointer actualBundle(
285fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                ures_open(U_ICUDATA_COLL, actualLocale, &errorCode));
286fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(U_FAILURE(errorCode)) { return NULL; }
287fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode internalErrorCode = U_ZERO_ERROR;
288fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        LocalUResourceBundlePointer def(
289fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                ures_getByKeyWithFallback(actualBundle.getAlias(), "collations/default", NULL,
290fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                          &internalErrorCode));
291fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        int32_t length;
292fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UChar *s = ures_getString(def.getAlias(), &length, &internalErrorCode);
293fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(U_SUCCESS(internalErrorCode) && length < LENGTHOF(defaultType)) {
294fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            u_UCharsToChars(s, defaultType, length + 1);
295fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else {
296fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uprv_strcpy(defaultType, "standard");
297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
299fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(uprv_strcmp(type, defaultType) != 0) {
300fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        t->actualLocale.setKeywordValue("collation", type, errorCode);
301fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(U_FAILURE(errorCode)) { return NULL; }
302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
303fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
304fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(typeFallback) {
305fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_USING_DEFAULT_WARNING;
306c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
307fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    t->bundle = bundle.orphan();
308fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return t.orphan();
309fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
311fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_END
312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
313fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_USE
314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI UCollator*
316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruucol_open(const char *loc,
317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru          UErrorCode *status)
318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    U_NAMESPACE_USE
320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN);
322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UTRACE_DATA1(UTRACE_INFO, "locale = \"%s\"", loc);
323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UCollator *result = NULL;
324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
325fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    Collator *coll = Collator::createInstance(loc, *status);
326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(U_SUCCESS(*status)) {
327fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        result = coll->toUCollator();
328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
329fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UTRACE_EXIT_PTR_STATUS(result, *status);
330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return result;
331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t U_EXPORT2
335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruucol_getDisplayName(    const    char        *objLoc,
336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    const    char        *dispLoc,
337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    UChar             *result,
338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    int32_t         resultLength,
339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    UErrorCode        *status)
340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    U_NAMESPACE_USE
342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(U_FAILURE(*status)) return -1;
344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString dst;
345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(!(result==NULL && resultLength==0)) {
346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // NULL destination for pure preflighting: empty dummy string
347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // otherwise, alias the destination buffer
348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        dst.setTo(result, 0, resultLength);
349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    Collator::getDisplayName(Locale(objLoc), Locale(dispLoc), dst);
351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return dst.extract(result, resultLength, *status);
352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI const char* U_EXPORT2
355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruucol_getAvailable(int32_t index)
356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t count = 0;
358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const Locale *loc = Collator::getAvailableLocales(count);
359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (loc != NULL && index < count) {
360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return loc[index].getName();
361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return NULL;
363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
365b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t U_EXPORT2
366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruucol_countAvailable()
367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t count = 0;
369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    Collator::getAvailableLocales(count);
370b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return count;
371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
373b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if !UCONFIG_NO_SERVICE
374b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI UEnumeration* U_EXPORT2
375b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruucol_openAvailableLocales(UErrorCode *status) {
376b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    U_NAMESPACE_USE
377b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
378b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // This is a wrapper over Collator::getAvailableLocales()
379b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(*status)) {
380b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
381b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
382103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    StringEnumeration *s = icu::Collator::getAvailableLocales();
383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (s == NULL) {
384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *status = U_MEMORY_ALLOCATION_ERROR;
385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
387b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return uenum_openFromStringEnumeration(s, status);
388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
389b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
390b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
391b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Note: KEYWORDS[0] != RESOURCE_NAME - alan
392b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
393c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const char RESOURCE_NAME[] = "collations";
394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
395c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const char* const KEYWORDS[] = { "collation" };
396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
397fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#define KEYWORD_COUNT LENGTHOF(KEYWORDS)
398b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
399b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI UEnumeration* U_EXPORT2
400b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruucol_getKeywords(UErrorCode *status) {
401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UEnumeration *result = NULL;
402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_SUCCESS(*status)) {
403b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return uenum_openCharStringsEnumeration(KEYWORDS, KEYWORD_COUNT, status);
404b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
405b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return result;
406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI UEnumeration* U_EXPORT2
409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruucol_getKeywordValues(const char *keyword, UErrorCode *status) {
410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(*status)) {
411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // hard-coded to accept exactly one collation keyword
414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // modify if additional collation keyword is added later
415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (keyword==NULL || uprv_strcmp(keyword, KEYWORDS[0])!=0)
416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    {
417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return ures_getKeywordValues(U_ICUDATA_COLL, RESOURCE_NAME, status);
421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
423b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const UEnumeration defaultKeywordValues = {
424b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    NULL,
425b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    NULL,
426b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ulist_close_keyword_values_iterator,
427b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ulist_count_keyword_values,
428b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uenum_unextDefault,
429b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ulist_next_keyword_value,
430b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ulist_reset_keyword_values_iterator
431b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
432b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
43350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include <stdio.h>
43450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
435b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruU_CAPI UEnumeration* U_EXPORT2
436b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale,
437b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                               UBool /*commonlyUsed*/, UErrorCode* status) {
438b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* Get the locale base name. */
439b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char localeBuffer[ULOC_FULLNAME_CAPACITY] = "";
440b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uloc_getBaseName(locale, localeBuffer, sizeof(localeBuffer), status);
441b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
442b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* Create the 2 lists
443b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * -values is the temp location for the keyword values
444b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * -results hold the actual list used by the UEnumeration object
445b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
446b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UList *values = ulist_createEmptyList(status);
447b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UList *results = ulist_createEmptyList(status);
448b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
449b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status) || en == NULL) {
450b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (en == NULL) {
451b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_MEMORY_ALLOCATION_ERROR;
452b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
453b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(en);
454b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
455b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ulist_deleteList(values);
456b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ulist_deleteList(results);
457b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
458b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
459b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
460b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
461b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    en->context = results;
462b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
463b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* Open the resource bundle for collation with the given locale. */
464b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UResourceBundle bundle, collations, collres, defres;
465b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_initStackObject(&bundle);
466b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_initStackObject(&collations);
467b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_initStackObject(&collres);
468b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_initStackObject(&defres);
469b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
470b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
471b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
472b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (U_SUCCESS(*status)) {
473b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_getByKey(&bundle, RESOURCE_NAME, &collations, status);
474b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_resetIterator(&collations);
475b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (U_SUCCESS(*status) && ures_hasNext(&collations)) {
476b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ures_getNextResource(&collations, &collres, status);
477b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            const char *key = ures_getKey(&collres);
478b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* If the key is default, get the string and store it in results list only
479b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru             * if results list is empty.
480b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru             */
481b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (uprv_strcmp(key, "default") == 0) {
482b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (ulist_getListSize(results) == 0) {
483b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    char *defcoll = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
484b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    int32_t defcollLength = ULOC_KEYWORDS_CAPACITY;
485b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
486b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    ures_getNextResource(&collres, &defres, status);
48750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#if U_CHARSET_FAMILY==U_ASCII_FAMILY
48850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			/* optimize - use the utf-8 string */
489b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    ures_getUTF8String(&defres, defcoll, &defcollLength, TRUE, status);
49050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#else
49150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    {
49250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                       const UChar* defString = ures_getString(&defres, &defcollLength, status);
49350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                       if(U_SUCCESS(*status)) {
49450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   if(defcollLength+1 > ULOC_KEYWORDS_CAPACITY) {
49550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				*status = U_BUFFER_OVERFLOW_ERROR;
49650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   } else {
49750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                           	u_UCharsToChars(defString, defcoll, defcollLength+1);
49850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   }
49950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                       }
50050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    }
50150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#endif
502b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
503b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    ulist_addItemBeginList(results, defcoll, TRUE, status);
504b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
505b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else {
506b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                ulist_addItemEndList(values, key, FALSE, status);
507b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
508b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
509b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
510b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* If the locale is "" this is root so exit. */
511b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (uprv_strlen(localeBuffer) == 0) {
512b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
513b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
514b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* Get the parent locale and open a new resource bundle. */
515b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uloc_getParent(localeBuffer, localeBuffer, sizeof(localeBuffer), status);
516b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
517b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
518b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
519b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(&defres);
520b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(&collres);
521b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(&collations);
522b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(&bundle);
523b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
524b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_SUCCESS(*status)) {
525b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char *value = NULL;
526b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ulist_resetList(values);
527b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while ((value = (char *)ulist_getNext(values)) != NULL) {
52850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (!ulist_containsString(results, value, (int32_t)uprv_strlen(value))) {
529b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                ulist_addItemEndList(results, value, FALSE, status);
530b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (U_FAILURE(*status)) {
531b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
532b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
533b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
534b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
535b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
536b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
537b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ulist_deleteList(values);
538b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
539b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)){
540b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uenum_close(en);
541b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        en = NULL;
542b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
543b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ulist_resetList(results);
544b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
545b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
546b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return en;
547b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
548b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
549b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t U_EXPORT2
550b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruucol_getFunctionalEquivalent(char* result, int32_t resultCapacity,
551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             const char* keyword, const char* locale,
552b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             UBool* isAvailable, UErrorCode* status)
553b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // N.B.: Resource name is "collations" but keyword is "collation"
555b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return ures_getFunctionalEquivalent(result, resultCapacity, U_ICUDATA_COLL,
556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        "collations", keyword, locale,
557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        isAvailable, TRUE, status);
558b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
559b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
560b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif /* #if !UCONFIG_NO_COLLATION */
561