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 * Copyright (C) 2015-2016, International Business Machines Corporation and 7 * others. All Rights Reserved. 8 ******************************************************************************* 9 */ 10 package android.icu.impl; 11 12 import java.util.Collections; 13 import java.util.EnumMap; 14 import java.util.HashMap; 15 import java.util.HashSet; 16 import java.util.Map; 17 import java.util.Map.Entry; 18 import java.util.Set; 19 20 import android.icu.impl.locale.AsciiUtil; 21 import android.icu.util.UResourceBundle; 22 import android.icu.util.UResourceBundleIterator; 23 24 /** 25 * @author markdavis 26 * @hide Only a subset of ICU is exposed in Android 27 * 28 */ 29 public class ValidIdentifiers { 30 31 public enum Datatype { 32 currency, 33 language, 34 region, 35 script, 36 subdivision, 37 unit, 38 variant, 39 u, 40 t, 41 x, 42 illegal 43 } 44 45 public enum Datasubtype { 46 deprecated, 47 private_use, 48 regular, 49 special, 50 unknown, 51 macroregion, 52 } 53 54 public static class ValiditySet { 55 public final Set<String> regularData; 56 public final Map<String,Set<String>> subdivisionData; 57 public ValiditySet(Set<String> plainData, boolean makeMap) { 58 if (makeMap) { 59 HashMap<String,Set<String>> _subdivisionData = new HashMap<String,Set<String>>(); 60 for (String s : plainData) { 61 int pos = s.indexOf('-'); // read v28 data also 62 int pos2 = pos+1; 63 if (pos < 0) { 64 pos2 = pos = s.charAt(0) < 'A' ? 3 : 2; 65 } 66 final String key = s.substring(0, pos); 67 final String subdivision = s.substring(pos2); 68 69 Set<String> oldSet = _subdivisionData.get(key); 70 if (oldSet == null) { 71 _subdivisionData.put(key, oldSet = new HashSet<String>()); 72 } 73 oldSet.add(subdivision); 74 } 75 this.regularData = null; 76 HashMap<String,Set<String>> _subdivisionData2 = new HashMap<String,Set<String>>(); 77 // protect the sets 78 for (Entry<String, Set<String>> e : _subdivisionData.entrySet()) { 79 Set<String> value = e.getValue(); 80 // optimize a bit by using singleton 81 Set<String> set = value.size() == 1 ? Collections.singleton(value.iterator().next()) 82 : Collections.unmodifiableSet(value); 83 _subdivisionData2.put(e.getKey(), set); 84 } 85 86 this.subdivisionData = Collections.unmodifiableMap(_subdivisionData2); 87 } else { 88 this.regularData = Collections.unmodifiableSet(plainData); 89 this.subdivisionData = null; 90 } 91 } 92 93 public boolean contains(String code) { 94 if (regularData != null) { 95 return regularData.contains(code); 96 } else { 97 int pos = code.indexOf('-'); 98 String key = code.substring(0,pos); 99 final String value = code.substring(pos+1); 100 return contains(key, value); 101 } 102 } 103 104 public boolean contains(String key, String value) { 105 Set<String> oldSet = subdivisionData.get(key); 106 return oldSet != null && oldSet.contains(value); 107 } 108 109 @Override 110 public String toString() { 111 if (regularData != null) { 112 return regularData.toString(); 113 } else { 114 return subdivisionData.toString(); 115 } 116 } 117 } 118 119 private static class ValidityData { 120 static final Map<Datatype,Map<Datasubtype,ValiditySet>> data; 121 static { 122 Map<Datatype, Map<Datasubtype, ValiditySet>> _data = new EnumMap<Datatype,Map<Datasubtype,ValiditySet>>(Datatype.class); 123 UResourceBundle suppData = UResourceBundle.getBundleInstance( 124 ICUData.ICU_BASE_NAME, 125 "supplementalData", 126 ICUResourceBundle.ICU_DATA_CLASS_LOADER); 127 UResourceBundle validityInfo = suppData.get("idValidity"); 128 for(UResourceBundleIterator datatypeIterator = validityInfo.getIterator(); 129 datatypeIterator.hasNext();) { 130 UResourceBundle datatype = datatypeIterator.next(); 131 String rawKey = datatype.getKey(); 132 Datatype key = Datatype.valueOf(rawKey); 133 Map<Datasubtype,ValiditySet> values = new EnumMap<Datasubtype,ValiditySet>(Datasubtype.class); 134 for(UResourceBundleIterator datasubtypeIterator = datatype.getIterator(); 135 datasubtypeIterator.hasNext();) { 136 UResourceBundle datasubtype = datasubtypeIterator.next(); 137 String rawsubkey = datasubtype.getKey(); 138 Datasubtype subkey = Datasubtype.valueOf(rawsubkey); 139 // handle single value specially 140 Set<String> subvalues = new HashSet<String>(); 141 if (datasubtype.getType() == UResourceBundle.STRING) { 142 addRange(datasubtype.getString(), subvalues); 143 } else { 144 for (String string : datasubtype.getStringArray()) { 145 addRange(string, subvalues); 146 } 147 } 148 values.put(subkey, new ValiditySet(subvalues, key == Datatype.subdivision)); 149 } 150 _data.put(key, Collections.unmodifiableMap(values)); 151 } 152 data = Collections.unmodifiableMap(_data); 153 } 154 private static void addRange(String string, Set<String> subvalues) { 155 string = AsciiUtil.toLowerString(string); 156 int pos = string.indexOf('~'); 157 if (pos < 0) { 158 subvalues.add(string); 159 } else { 160 StringRange.expand(string.substring(0,pos), string.substring(pos+1), false, subvalues); 161 } 162 } 163 } 164 165 public static Map<Datatype, Map<Datasubtype, ValiditySet>> getData() { 166 return ValidityData.data; 167 } 168 169 /** 170 * Returns the Datasubtype containing the code, or null if there is none. 171 */ 172 public static Datasubtype isValid(Datatype datatype, Set<Datasubtype> datasubtypes, String code) { 173 Map<Datasubtype, ValiditySet> subtable = ValidityData.data.get(datatype); 174 if (subtable != null) { 175 for (Datasubtype datasubtype : datasubtypes) { 176 ValiditySet validitySet = subtable.get(datasubtype); 177 if (validitySet != null) { 178 if (validitySet.contains(AsciiUtil.toLowerString(code))) { 179 return datasubtype; 180 } 181 } 182 } 183 } 184 return null; 185 } 186 187 public static Datasubtype isValid(Datatype datatype, Set<Datasubtype> datasubtypes, String code, String value) { 188 Map<Datasubtype, ValiditySet> subtable = ValidityData.data.get(datatype); 189 if (subtable != null) { 190 code = AsciiUtil.toLowerString(code); 191 value = AsciiUtil.toLowerString(value); 192 for (Datasubtype datasubtype : datasubtypes) { 193 ValiditySet validitySet = subtable.get(datasubtype); 194 if (validitySet != null) { 195 if (validitySet.contains(code, value)) { 196 return datasubtype; 197 } 198 } 199 } 200 } 201 return null; 202 } 203 } 204