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