/* ******************************************************************************* * 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.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.Map.Entry; import com.ibm.icu.impl.locale.LanguageTag.ParseStatus; public class UnicodeLocaleExtension extends Extension { public static final char SINGLETON = 'u'; public static final UnicodeLocaleExtension CA_JAPANESE = new UnicodeLocaleExtension().put("ca", "japanese"); public static final UnicodeLocaleExtension NU_THAI = new UnicodeLocaleExtension().put("nu", "thai"); private SortedMap _keyTypeMap; protected UnicodeLocaleExtension() { super(SINGLETON); } /* * Package local constructor only used by InternalLocaleBuilder */ UnicodeLocaleExtension(SortedMap keyTypeMap) { super(SINGLETON); _keyTypeMap = keyTypeMap; updateStringValue(); } protected void setExtensionValue(StringTokenIterator itr, ParseStatus sts) { if (sts.isError() || itr.isDone()) { _value = null; return; } SortedMap keyTypeMap = new TreeMap(); String ukey = null; StringBuilder buf = new StringBuilder(); int typeEnd = -1; while (!itr.isDone()) { String s = itr.current(); if (isTypeSubtag(s)) { if (ukey == null) { // key is expected sts.errorIndex = itr.currentStart(); sts.errorMsg = "Invalid Unicode locale extension key: " + s; break; } if (buf.length() > 0) { buf.append(LanguageTag.SEP); } buf.append(canonicalizeTypeSubtag(s)); typeEnd = itr.currentEnd(); if (!itr.hasNext()) { // emit the last key/type keyTypeMap.put(ukey, buf.toString()); sts.parseLength = typeEnd; itr.next(); break; } } else { // key or others if (ukey != null) { if (buf.length() > 0) { // emit previous key and value keyTypeMap.put(ukey, buf.toString()); sts.parseLength = typeEnd; } else { // type is expected sts.errorIndex = itr.currentStart(); sts.errorMsg = "Invalid Unicode locale extension type: " + s; break; } } if (isKey(s)) { if (itr.hasNext()) { ukey = canonicalizeKey(s); if (keyTypeMap.containsKey(ukey)) { // duplicated key sts.errorIndex = itr.currentStart(); sts.errorMsg = "Duplicate Unicode locale extension key: " + s; break; } buf.setLength(0); typeEnd = -1; } else { // missing type sts.errorIndex = itr.currentStart(); sts.errorMsg = "Missing subtag for Unicode locale extension: " + s; itr.next(); break; } } else { // others if (keyTypeMap.size() == 0) { // key is expected sts.errorIndex = itr.currentStart(); sts.errorMsg = "Invalid Unicode locale extension key: " + s; } break; } } itr.next(); } if (keyTypeMap.size() == 0) { _value = null; return; } _keyTypeMap = keyTypeMap; updateStringValue(); } public Set getKeys() { if (_keyTypeMap == null) { return Collections.emptySet(); } return Collections.unmodifiableSet(_keyTypeMap.keySet()); } public String getType(String key) { String type = null; if (_keyTypeMap != null) { type = _keyTypeMap.get(canonicalizeKey(key)); } return (type == null ? "" : type); } public static boolean isKey(String s) { // 2alphanum return (s.length() == 2) && AsciiUtil.isAlphaNumericString(s); } public static boolean isTypeSubtag(String s) { // 3*8alphanum return (s.length() >= 3) && (s.length() <= 8) && AsciiUtil.isAlphaNumericString(s); } public static String canonicalizeKey(String s) { return LanguageTag.canonicalizeExtensionSubtag(s); } public static String canonicalizeTypeSubtag(String s) { return LanguageTag.canonicalizeExtensionSubtag(s); } // These methods are only used by InterlaLocaleBuilder UnicodeLocaleExtension remove(String key) { if (_keyTypeMap != null) { _keyTypeMap.remove(key); updateStringValue(); } return this; } UnicodeLocaleExtension put(String key, String type) { if (_keyTypeMap == null) { _keyTypeMap = new TreeMap(); } _keyTypeMap.put(key, type); updateStringValue(); return this; } boolean isEmpty() { return (_keyTypeMap.size() == 0); } private void updateStringValue() { _value = null; if (_keyTypeMap != null) { // re-construct string representation StringBuilder valBuf = new StringBuilder(); Set> entries = _keyTypeMap.entrySet(); boolean isFirst = true; for (Entry e : entries) { if (isFirst) { isFirst = false; } else { valBuf.append(LanguageTag.SEP); } valBuf.append(e.getKey()); valBuf.append(LanguageTag.SEP); valBuf.append(e.getValue()); } if (valBuf.length() > 0) { _value = valBuf.toString(); } } } }