Home | History | Annotate | Download | only in impl
      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