| /* |
| ******************************************************************************* |
| * Copyright (C) 2009, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| */ |
| package com.ibm.icu.impl.locale; |
| |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeMap; |
| |
| import com.ibm.icu.impl.Utility; |
| |
| public final class LocaleExtensions { |
| public static final LocaleExtensions EMPTY_EXTENSIONS = new LocaleExtensions(""); |
| |
| private String _extensions; |
| // private TreeMap<Character, String> _extMap; |
| private TreeMap _extMap; |
| // private TreeMap<String, String> _kwdMap; |
| private TreeMap _kwdMap; |
| |
| private static final String LOCALEEXTSEP = "-"; |
| private static final String LDMLSINGLETON = "u"; |
| private static final String PRIVUSE = "x"; |
| private static final int MINLEN = 3; // minimum length of string representation "x-?" |
| |
| |
| private LocaleExtensions(String extensions) { |
| _extensions = extensions == null ? "" : extensions; |
| } |
| |
| public static LocaleExtensions getInstance(String extensions) { |
| if (extensions == null || extensions.length() == 0) { |
| return EMPTY_EXTENSIONS; |
| } |
| |
| // extensions = AsciiUtil.toLowerString(extensions).replaceAll("_", LOCALEEXTSEP); |
| extensions = Utility.replaceAll(AsciiUtil.toLowerString(extensions), "_", LOCALEEXTSEP); |
| |
| if (extensions.length() < MINLEN) { |
| // malformed extensions - too short |
| return new LocaleExtensions(extensions); |
| } |
| |
| // TreeMap<Character, String> extMap = null; |
| TreeMap extMap = null; |
| // TreeMap<String, String> kwdMap = null; |
| TreeMap kwdMap = null; |
| boolean bParseFailure = false; |
| |
| // parse the extension subtags |
| // String[] subtags = extensions.split(LOCALEEXTSEP); |
| String[] subtags = Utility.split(extensions, '-'); |
| String letter = null; |
| // extMap = new TreeMap<Character, String>(); |
| extMap = new TreeMap(); |
| // StringBuilder buf = new StringBuilder(); |
| StringBuffer buf = new StringBuffer(); |
| boolean inLocaleKeywords = false; |
| boolean inPrivateUse = false; |
| String kwkey = null; |
| |
| for (int i = 0; i < subtags.length; i++) { |
| if (subtags[i].length() == 0) { |
| // empty subtag |
| bParseFailure = true; |
| break; |
| } |
| if (subtags[i].length() == 1 && !inPrivateUse) { |
| if (letter != null) { |
| // next extension singleton |
| if (extMap.containsKey(subtags[i])) { |
| // duplicated singleton extension letter |
| bParseFailure = true; |
| break; |
| } |
| // write out the previous extension |
| if (inLocaleKeywords) { |
| if (kwkey != null) { |
| // no locale keyword key |
| bParseFailure = true; |
| break; |
| } |
| // creating a single string including locale keyword key/type pairs |
| keywordsToString(kwdMap, buf); |
| inLocaleKeywords = false; |
| } |
| if (buf.length() == 0) { |
| // empty subtag |
| bParseFailure = true; |
| break; |
| } |
| // extMap.put(Character.valueOf(letter.charAt(0)), buf.toString().intern()); |
| extMap.put(new Character(letter.charAt(0)), buf.toString().intern()); |
| } |
| // preparation for next extension |
| if (subtags[i].equals(LDMLSINGLETON)) { |
| // kwdMap = new TreeMap<String, String>(); |
| kwdMap = new TreeMap(); |
| inLocaleKeywords = true; |
| } else if (subtags[i].equals(PRIVUSE)) { |
| inPrivateUse = true; |
| } |
| buf.setLength(0); |
| letter = subtags[i]; |
| continue; |
| } |
| if (inLocaleKeywords) { |
| if (kwkey == null) { |
| kwkey = subtags[i]; |
| } else { |
| kwdMap.put(kwkey.intern(), subtags[i].intern()); |
| kwkey = null; |
| } |
| } else { |
| // append an extension/prvate use subtag |
| if (buf.length() > 0) { |
| buf.append(LOCALEEXTSEP); |
| } |
| buf.append(subtags[i]); |
| } |
| } |
| if (!bParseFailure) { |
| // process the last extension |
| if (inLocaleKeywords) { |
| if (kwkey != null) { |
| bParseFailure = true; |
| } else { |
| // creating a single string including locale keyword key/type pairs |
| keywordsToString(kwdMap, buf); |
| } |
| } |
| if (buf.length() == 0) { |
| // empty subtag at the end |
| bParseFailure = true; |
| } else { |
| // extMap.put(Character.valueOf(letter.charAt(0)), buf.toString().intern()); |
| extMap.put(new Character(letter.charAt(0)), buf.toString().intern()); |
| } |
| } |
| |
| if (bParseFailure) { |
| // parsing the extension string failed. |
| // do not set any partial results in the result. |
| return new LocaleExtensions(extensions); |
| } |
| |
| String canonical = extensionsToCanonicalString(extMap); |
| LocaleExtensions le = new LocaleExtensions(canonical); |
| le._extMap = extMap; |
| le._kwdMap = kwdMap; |
| |
| return le; |
| } |
| |
| // This method assumes extension map and locale keyword map |
| // are all in canonicalized format. This method is only used by |
| // InternalLocaleBuilder. |
| // static LocaleExtensions getInstance(TreeMap<Character, String> extMap, TreeMap<String ,String> kwdMap) { |
| public static LocaleExtensions getInstance(TreeMap extMap, TreeMap kwdMap) { |
| if (extMap == null) { |
| return EMPTY_EXTENSIONS; |
| } |
| String canonical = extensionsToCanonicalString(extMap); |
| LocaleExtensions le = new LocaleExtensions(canonical); |
| le._extMap = extMap; |
| le._kwdMap = kwdMap; |
| |
| return le; |
| } |
| |
| public boolean equals(Object obj) { |
| return (this == obj) || |
| ((obj instanceof LocaleExtensions) && _extensions == (((LocaleExtensions)obj)._extensions)); |
| } |
| |
| public int hashCode() { |
| return _extensions.hashCode(); |
| } |
| |
| // public Set<Character> getExtensionKeys() { |
| public Set getExtensionKeys() { |
| if (_extMap != null) { |
| return Collections.unmodifiableSet(_extMap.keySet()); |
| } |
| return null; |
| } |
| |
| public String getExtensionValue(char key) { |
| if (_extMap != null) { |
| // return _extMap.get(Character.valueOf(key)); |
| return (String)_extMap.get(new Character(key)); |
| } |
| return null; |
| } |
| |
| // public Set<String> getLDMLKeywordKeys() { |
| public Set getLDMLKeywordKeys() { |
| if (_kwdMap != null) { |
| return Collections.unmodifiableSet(_kwdMap.keySet()); |
| } |
| return null; |
| } |
| |
| public String getLDMLKeywordType(String key) { |
| if (key == null) { |
| throw new NullPointerException("LDML key must not be null"); |
| } |
| if (_kwdMap != null) { |
| // return _kwdMap.get(key); |
| return (String)_kwdMap.get(key); |
| } |
| return null; |
| } |
| |
| public String getCanonicalString() { |
| return _extensions; |
| } |
| |
| public String toString() { |
| return _extensions; |
| } |
| |
| // private static String extensionsToCanonicalString(TreeMap<Character, String> extMap) { |
| private static String extensionsToCanonicalString(TreeMap extMap) { |
| if (extMap == null || extMap.size() == 0) { |
| return ""; |
| } |
| // StringBuilder canonicalbuf = new StringBuilder(); |
| StringBuffer canonicalbuf = new StringBuffer(); |
| String privUseStr = null; |
| if (extMap != null) { |
| // Set<Map.Entry<Character, String>> entries = extMap.entrySet(); |
| // for (Map.Entry<Character, String> entry : entries) { |
| // Character key = entry.getKey(); |
| // String value = entry.getValue(); |
| Set entries = extMap.entrySet(); |
| Iterator itr = entries.iterator(); |
| while (itr.hasNext()) { |
| Map.Entry entry = (Map.Entry)itr.next(); |
| Character key = (Character)entry.getKey(); |
| String value = (String)entry.getValue(); |
| |
| if (key.charValue() == PRIVUSE.charAt(0)) { |
| privUseStr = value; |
| continue; |
| } |
| if (canonicalbuf.length() > 0) { |
| canonicalbuf.append(LOCALEEXTSEP); |
| } |
| canonicalbuf.append(key); |
| canonicalbuf.append(LOCALEEXTSEP); |
| canonicalbuf.append(value); |
| } |
| } |
| if (privUseStr != null) { |
| if (canonicalbuf.length() > 0) { |
| canonicalbuf.append(LOCALEEXTSEP); |
| } |
| canonicalbuf.append(PRIVUSE); |
| canonicalbuf.append(LOCALEEXTSEP); |
| canonicalbuf.append(privUseStr); |
| } |
| return canonicalbuf.toString().intern(); |
| } |
| |
| // static void keywordsToString(TreeMap<String, String> map, StringBuilder buf) { |
| public static void keywordsToString(TreeMap map, StringBuffer buf) { |
| // Set<Map.Entry<String, String>> entries = map.entrySet(); |
| // for (Map.Entry<String, String> entry : entries) { |
| Set entries = map.entrySet(); |
| Iterator itr = entries.iterator(); |
| while (itr.hasNext()) { |
| Map.Entry entry = (Map.Entry)itr.next(); |
| |
| if (buf.length() > 0) { |
| buf.append(LOCALEEXTSEP); |
| } |
| buf.append(entry.getKey()); |
| buf.append(LOCALEEXTSEP); |
| buf.append(entry.getValue()); |
| } |
| } |
| |
| public static boolean isValidExtensionKey(char key) { |
| return AsciiUtil.isAlphaNumeric(key); |
| } |
| |
| public static boolean isValidLDMLKey(String key) { |
| return (key.length() == 2) && AsciiUtil.isAlphaNumericString(key); |
| } |
| |
| public static boolean isValidLDMLType(String type) { |
| return (type.length() >= 3) && (type.length() <= 8) && AsciiUtil.isAlphaNumericString(type); |
| } |
| } |