Home | History | Annotate | Download | only in coll
      1 /* GENERATED SOURCE. DO NOT MODIFY. */
      2 //  2016 and later: Unicode, Inc. and others.
      3 // License & terms of use: http://www.unicode.org/copyright.html#License
      4 /*
      5 *******************************************************************************
      6 *
      7 *   Copyright (C) 1996-2016, International Business Machines
      8 *   Corporation and others.  All Rights Reserved.
      9 *
     10 *******************************************************************************
     11 *
     12 * CollationLoader.java, ported from ucol_res.cpp
     13 *
     14 * created by: Markus W. Scherer
     15 */
     16 
     17 package android.icu.impl.coll;
     18 
     19 import java.io.IOException;
     20 import java.nio.ByteBuffer;
     21 import java.util.MissingResourceException;
     22 
     23 import android.icu.impl.ICUData;
     24 import android.icu.impl.ICUResourceBundle;
     25 import android.icu.util.ICUUncheckedIOException;
     26 import android.icu.util.Output;
     27 import android.icu.util.ULocale;
     28 import android.icu.util.UResourceBundle;
     29 
     30 /**
     31  * Convenience string denoting the Collation data tree
     32  * @hide Only a subset of ICU is exposed in Android
     33  */
     34 public final class CollationLoader {
     35 
     36     // not implemented, all methods are static
     37     private CollationLoader() {
     38     }
     39 
     40     private static volatile String rootRules = null;
     41 
     42     private static void loadRootRules() {
     43         if (rootRules != null) {
     44             return;
     45         }
     46         synchronized(CollationLoader.class) {
     47             if (rootRules == null) {
     48                 UResourceBundle rootBundle = UResourceBundle.getBundleInstance(
     49                         ICUData.ICU_COLLATION_BASE_NAME, ULocale.ROOT);
     50                 rootRules = rootBundle.getString("UCARules");
     51             }
     52         }
     53     }
     54 
     55     // C++: static void appendRootRules(UnicodeString &s)
     56     public static String getRootRules() {
     57         loadRootRules();
     58         return rootRules;
     59     }
     60 
     61     /**
     62      * Simpler/faster methods for ASCII than ones based on Unicode data.
     63      * TODO: There should be code like this somewhere already??
     64      */
     65     private static final class ASCII {
     66         static String toLowerCase(String s) {
     67             for (int i = 0; i < s.length(); ++i) {
     68                 char c = s.charAt(i);
     69                 if ('A' <= c && c <= 'Z') {
     70                     StringBuilder sb = new StringBuilder(s.length());
     71                     sb.append(s, 0, i).append((char)(c + 0x20));
     72                     while (++i < s.length()) {
     73                         c = s.charAt(i);
     74                         if ('A' <= c && c <= 'Z') { c = (char)(c + 0x20); }
     75                         sb.append(c);
     76                     }
     77                     return sb.toString();
     78                 }
     79             }
     80             return s;
     81         }
     82     }
     83 
     84     static String loadRules(ULocale locale, String collationType) {
     85         UResourceBundle bundle = UResourceBundle.getBundleInstance(
     86                 ICUData.ICU_COLLATION_BASE_NAME, locale);
     87         UResourceBundle data = ((ICUResourceBundle)bundle).getWithFallback(
     88                 "collations/" + ASCII.toLowerCase(collationType));
     89         String rules = data.getString("Sequence");
     90         return rules;
     91     }
     92 
     93     private static final UResourceBundle findWithFallback(UResourceBundle table, String entryName) {
     94         return ((ICUResourceBundle)table).findWithFallback(entryName);
     95     }
     96 
     97     public static CollationTailoring loadTailoring(ULocale locale, Output<ULocale> outValidLocale) {
     98 
     99         // Java porting note: ICU4J getWithFallback/getStringWithFallback currently does not
    100         // work well when alias table is involved in a resource path, unless full path is specified.
    101         // For now, collation resources does not contain such data, so the code below should work fine.
    102 
    103         CollationTailoring root = CollationRoot.getRoot();
    104         String localeName = locale.getName();
    105         if (localeName.length() == 0 || localeName.equals("root")) {
    106             outValidLocale.value = ULocale.ROOT;
    107             return root;
    108         }
    109 
    110         UResourceBundle bundle = null;
    111         try {
    112             bundle = ICUResourceBundle.getBundleInstance(
    113                     ICUData.ICU_COLLATION_BASE_NAME, locale,
    114                     ICUResourceBundle.OpenType.LOCALE_ROOT);
    115         } catch (MissingResourceException e) {
    116             outValidLocale.value = ULocale.ROOT;
    117             return root;
    118         }
    119 
    120         ULocale validLocale = bundle.getULocale();
    121         // Normalize the root locale. See
    122         // http://bugs.icu-project.org/trac/ticket/10715
    123         String validLocaleName = validLocale.getName();
    124         if (validLocaleName.length() == 0 || validLocaleName.equals("root")) {
    125             validLocale = ULocale.ROOT;
    126         }
    127         outValidLocale.value = validLocale;
    128 
    129         // There are zero or more tailorings in the collations table.
    130         UResourceBundle collations;
    131         try {
    132             collations = bundle.get("collations");
    133             if (collations == null) {
    134                 return root;
    135             }
    136         } catch(MissingResourceException ignored) {
    137             return root;
    138         }
    139 
    140         // Fetch the collation type from the locale ID and the default type from the data.
    141         String type = locale.getKeywordValue("collation");
    142         String defaultType = "standard";
    143 
    144         String defT = ((ICUResourceBundle)collations).findStringWithFallback("default");
    145         if (defT != null) {
    146             defaultType = defT;
    147         }
    148 
    149         if (type == null || type.equals("default")) {
    150             type = defaultType;
    151         } else {
    152             type = ASCII.toLowerCase(type);
    153         }
    154 
    155         // Load the collations/type tailoring, with type fallback.
    156 
    157         // Java porting note: typeFallback is used for setting U_USING_DEFAULT_WARNING in
    158         // ICU4C, but not used by ICU4J
    159 
    160         // boolean typeFallback = false;
    161         UResourceBundle data = findWithFallback(collations, type);
    162         if (data == null &&
    163                 type.length() > 6 && type.startsWith("search")) {
    164             // fall back from something like "searchjl" to "search"
    165             // typeFallback = true;
    166             type = "search";
    167             data = findWithFallback(collations, type);
    168         }
    169 
    170         if (data == null && !type.equals(defaultType)) {
    171             // fall back to the default type
    172             // typeFallback = true;
    173             type = defaultType;
    174             data = findWithFallback(collations, type);
    175         }
    176 
    177         if (data == null && !type.equals("standard")) {
    178             // fall back to the "standard" type
    179             // typeFallback = true;
    180             type = "standard";
    181             data = findWithFallback(collations, type);
    182         }
    183 
    184         if (data == null) {
    185             return root;
    186         }
    187 
    188         // Is this the same as the root collator? If so, then use that instead.
    189         ULocale actualLocale = data.getULocale();
    190         // http://bugs.icu-project.org/trac/ticket/10715 ICUResourceBundle(root).getULocale() != ULocale.ROOT
    191         // Therefore not just if (actualLocale.equals(ULocale.ROOT) && type.equals("standard")) {
    192         String actualLocaleName = actualLocale.getName();
    193         if (actualLocaleName.length() == 0 || actualLocaleName.equals("root")) {
    194             actualLocale = ULocale.ROOT;
    195             if (type.equals("standard")) {
    196                 return root;
    197             }
    198         }
    199 
    200         CollationTailoring t = new CollationTailoring(root.settings);
    201         t.actualLocale = actualLocale;
    202 
    203         // deserialize
    204         UResourceBundle binary = data.get("%%CollationBin");
    205         ByteBuffer inBytes = binary.getBinary();
    206         try {
    207             CollationDataReader.read(root, inBytes, t);
    208         } catch (IOException e) {
    209             throw new ICUUncheckedIOException("Failed to load collation tailoring data for locale:"
    210                     + actualLocale + " type:" + type, e);
    211         }
    212 
    213         // Try to fetch the optional rules string.
    214         try {
    215             t.setRulesResource(data.get("Sequence"));
    216         } catch(MissingResourceException ignored) {
    217         }
    218 
    219         // Set the collation types on the informational locales,
    220         // except when they match the default types (for brevity and backwards compatibility).
    221         // For the valid locale, suppress the default type.
    222         if (!type.equals(defaultType)) {
    223             outValidLocale.value = validLocale.setKeywordValue("collation", type);
    224         }
    225 
    226         // For the actual locale, suppress the default type *according to the actual locale*.
    227         // For example, zh has default=pinyin and contains all of the Chinese tailorings.
    228         // zh_Hant has default=stroke but has no other data.
    229         // For the valid locale "zh_Hant" we need to suppress stroke.
    230         // For the actual locale "zh" we need to suppress pinyin instead.
    231         if (!actualLocale.equals(validLocale)) {
    232             // Opening a bundle for the actual locale should always succeed.
    233             UResourceBundle actualBundle = UResourceBundle.getBundleInstance(
    234                     ICUData.ICU_COLLATION_BASE_NAME, actualLocale);
    235             defT = ((ICUResourceBundle)actualBundle).findStringWithFallback("collations/default");
    236             if (defT != null) {
    237                 defaultType = defT;
    238             }
    239         }
    240 
    241         if (!type.equals(defaultType)) {
    242             t.actualLocale = t.actualLocale.setKeywordValue("collation", type);
    243         }
    244 
    245         // if (typeFallback) {
    246         //     ICU4C implementation sets U_USING_DEFAULT_WARNING here
    247         // }
    248 
    249         return t;
    250     }
    251 }
    252