-//##header\r
-//#if defined(FOUNDATION10) || defined(J2SE13)\r
-//#else\r
-/*\r
- *******************************************************************************\r
- * Copyright (C) 1996-2009, International Business Machines Corporation and *\r
- * others. All Rights Reserved. *\r
- *******************************************************************************\r
- */\r
-package com.ibm.icu.dev.test.util;\r
-\r
-import java.io.PrintWriter;\r
-import java.io.StringWriter;\r
-import java.text.ParsePosition;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Comparator;\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.TreeMap;\r
-import java.util.regex.Pattern;\r
-\r
-import com.ibm.icu.dev.test.util.CollectionUtilities.InverseMatcher;\r
-import com.ibm.icu.dev.test.util.CollectionUtilities.ObjectMatcher;\r
-import com.ibm.icu.impl.Utility;\r
-import com.ibm.icu.text.SymbolTable;\r
-import com.ibm.icu.text.UTF16;\r
-import com.ibm.icu.text.UnicodeMatcher;\r
-import com.ibm.icu.text.UnicodeSet;\r
-import com.ibm.icu.text.UnicodeSetIterator;\r
-\r
-public abstract class UnicodeProperty extends UnicodeLabel {\r
-\r
- public static boolean DEBUG = false;\r
-\r
- public static String CHECK_NAME = "FC_NFKC_Closure";\r
-\r
- public static int CHECK_VALUE = 0x037A;\r
-\r
- private String name;\r
-\r
- private String firstNameAlias = null;\r
-\r
- private int type;\r
-\r
- private Map valueToFirstValueAlias = null;\r
-\r
- /*\r
- * Name: Unicode_1_Name Name: ISO_Comment Name: Name Name: Unicode_1_Name\r
- * \r
- */\r
-\r
- public static final int UNKNOWN = 0, BINARY = 2, EXTENDED_BINARY = 3,\r
- ENUMERATED = 4, EXTENDED_ENUMERATED = 5, CATALOG = 6,\r
- EXTENDED_CATALOG = 7, MISC = 8, EXTENDED_MISC = 9, STRING = 10,\r
- EXTENDED_STRING = 11, NUMERIC = 12, EXTENDED_NUMERIC = 13,\r
- START_TYPE = 2, LIMIT_TYPE = 14, EXTENDED_MASK = 1,\r
- CORE_MASK = ~EXTENDED_MASK, BINARY_MASK = (1 << BINARY)\r
- | (1 << EXTENDED_BINARY), STRING_MASK = (1 << STRING)\r
- | (1 << EXTENDED_STRING),\r
- STRING_OR_MISC_MASK = (1 << STRING) | (1 << EXTENDED_STRING)\r
- | (1 << MISC) | (1 << EXTENDED_MISC),\r
- ENUMERATED_OR_CATALOG_MASK = (1 << ENUMERATED)\r
- | (1 << EXTENDED_ENUMERATED) | (1 << CATALOG)\r
- | (1 << EXTENDED_CATALOG);\r
-\r
- private static final String[] TYPE_NAMES = { "Unknown", "Unknown",\r
- "Binary", "Extended Binary", "Enumerated", "Extended Enumerated",\r
- "Catalog", "Extended Catalog", "Miscellaneous",\r
- "Extended Miscellaneous", "String", "Extended String", "Numeric",\r
- "Extended Numeric", };\r
-\r
- public static String getTypeName(int propType) {\r
- return TYPE_NAMES[propType];\r
- }\r
-\r
- public final String getName() {\r
- return name;\r
- }\r
-\r
- public final int getType() {\r
- return type;\r
- }\r
-\r
- public final boolean isType(int mask) {\r
- return ((1 << type) & mask) != 0;\r
- }\r
-\r
- protected final void setName(String string) {\r
- if (string == null)\r
- throw new IllegalArgumentException("Name must not be null");\r
- name = string;\r
- }\r
-\r
- protected final void setType(int i) {\r
- type = i;\r
- }\r
-\r
- public String getVersion() {\r
- return _getVersion();\r
- }\r
-\r
- public String getValue(int codepoint) {\r
- if (DEBUG && CHECK_VALUE == codepoint && CHECK_NAME.equals(getName())) {\r
- String value = _getValue(codepoint);\r
- System.out.println(getName() + "(" + Utility.hex(codepoint) + "):"\r
- + (getType() == STRING ? Utility.hex(value) : value));\r
- return value;\r
- }\r
- return _getValue(codepoint);\r
- }\r
-\r
- // public String getValue(int codepoint, boolean isShort) {\r
- // return getValue(codepoint);\r
- // }\r
-\r
- public List getNameAliases(List result) {\r
- if (result == null)\r
- result = new ArrayList(1);\r
- return _getNameAliases(result);\r
- }\r
-\r
- public List getValueAliases(String valueAlias, List result) {\r
- if (result == null)\r
- result = new ArrayList(1);\r
- result = _getValueAliases(valueAlias, result);\r
- if (!result.contains(valueAlias)) { // FIX && type < NUMERIC\r
- result = _getValueAliases(valueAlias, result); // for debugging\r
- throw new IllegalArgumentException("Internal error: " + getName()\r
- + " doesn't contain " + valueAlias + ": "\r
- + new BagFormatter().join(result));\r
- }\r
- return result;\r
- }\r
-\r
- public List getAvailableValues(List result) {\r
- if (result == null)\r
- result = new ArrayList(1);\r
- return _getAvailableValues(result);\r
- }\r
-\r
- protected abstract String _getVersion();\r
-\r
- protected abstract String _getValue(int codepoint);\r
-\r
- protected abstract List _getNameAliases(List result);\r
-\r
- protected abstract List _getValueAliases(String valueAlias, List result);\r
-\r
- protected abstract List _getAvailableValues(List result);\r
-\r
- // conveniences\r
- public final List getNameAliases() {\r
- return getNameAliases(null);\r
- }\r
-\r
- public final List getValueAliases(String valueAlias) {\r
- return getValueAliases(valueAlias, null);\r
- }\r
-\r
- public final List getAvailableValues() {\r
- return getAvailableValues(null);\r
- }\r
-\r
- public final String getValue(int codepoint, boolean getShortest) {\r
- String result = getValue(codepoint);\r
- if (type >= MISC || result == null || !getShortest)\r
- return result;\r
- return getFirstValueAlias(result);\r
- }\r
-\r
- public final String getFirstNameAlias() {\r
- if (firstNameAlias == null) {\r
- firstNameAlias = (String) getNameAliases().get(0);\r
- }\r
- return firstNameAlias;\r
- }\r
-\r
- public final String getFirstValueAlias(String value) {\r
- if (valueToFirstValueAlias == null)\r
- _getFirstValueAliasCache();\r
- return (String) valueToFirstValueAlias.get(value);\r
- }\r
-\r
- private void _getFirstValueAliasCache() {\r
- maxValueWidth = 0;\r
- maxFirstValueAliasWidth = 0;\r
- valueToFirstValueAlias = new HashMap(1);\r
- Iterator it = getAvailableValues().iterator();\r
- while (it.hasNext()) {\r
- String value = (String) it.next();\r
- String first = (String) getValueAliases(value).get(0);\r
- if (first == null) { // internal error\r
- throw new IllegalArgumentException(\r
- "Value not in value aliases: " + value);\r
- }\r
- if (DEBUG && CHECK_NAME.equals(getName())) {\r
- System.out.println("First Alias: " + getName() + ": " + value\r
- + " => " + first\r
- + new BagFormatter().join(getValueAliases(value)));\r
- }\r
- valueToFirstValueAlias.put(value, first);\r
- if (value.length() > maxValueWidth) {\r
- maxValueWidth = value.length();\r
- }\r
- if (first.length() > maxFirstValueAliasWidth) {\r
- maxFirstValueAliasWidth = first.length();\r
- }\r
- }\r
- }\r
-\r
- private int maxValueWidth = -1;\r
-\r
- private int maxFirstValueAliasWidth = -1;\r
-\r
- public int getMaxWidth(boolean getShortest) {\r
- if (maxValueWidth < 0)\r
- _getFirstValueAliasCache();\r
- if (getShortest)\r
- return maxFirstValueAliasWidth;\r
- return maxValueWidth;\r
- }\r
-\r
- public final UnicodeSet getSet(String propertyValue) {\r
- return getSet(propertyValue, null);\r
- }\r
-\r
- public final UnicodeSet getSet(PatternMatcher matcher) {\r
- return getSet(matcher, null);\r
- }\r
-\r
- public final UnicodeSet getSet(String propertyValue, UnicodeSet result) {\r
- return getSet(new SimpleMatcher(propertyValue,\r
- isType(STRING_OR_MISC_MASK) ? null : PROPERTY_COMPARATOR),\r
- result);\r
- }\r
-\r
- private UnicodeMap unicodeMap = null;\r
-\r
- public static final String UNUSED = "??";\r
-\r
- public final UnicodeSet getSet(PatternMatcher matcher, UnicodeSet result) {\r
- if (result == null)\r
- result = new UnicodeSet();\r
- if (isType(STRING_OR_MISC_MASK)) {\r
- for (int i = 0; i <= 0x10FFFF; ++i) {\r
- String value = getValue(i);\r
- if (value != null && matcher.matches(value)) {\r
- result.add(i);\r
- }\r
- }\r
- return result;\r
- }\r
- List temp = new ArrayList(1); // to avoid reallocating...\r
- UnicodeMap um = getUnicodeMap_internal();\r
- Iterator it = um.getAvailableValues(null).iterator();\r
- main: while (it.hasNext()) {\r
- String value = (String) it.next();\r
- temp.clear();\r
- Iterator it2 = getValueAliases(value, temp).iterator();\r
- while (it2.hasNext()) {\r
- String value2 = (String) it2.next();\r
- // System.out.println("Values:" + value2);\r
- if (matcher.matches(value2)\r
- || matcher.matches(toSkeleton(value2))) {\r
- um.getSet(value, result);\r
- continue main;\r
- }\r
- }\r
- }\r
- return result;\r
- }\r
-\r
- /*\r
- * public UnicodeSet getMatchSet(UnicodeSet result) { if (result == null)\r
- * result = new UnicodeSet(); addAll(matchIterator, result); return result; }\r
- * \r
- * public void setMatchSet(UnicodeSet set) { matchIterator = new\r
- * UnicodeSetIterator(set); }\r
- */\r
-\r
- /**\r
- * Utility for debugging\r
- */\r
- public static String getStack() {\r
- Exception e = new Exception();\r
- StringWriter sw = new StringWriter();\r
- PrintWriter pw = new PrintWriter(sw);\r
- e.printStackTrace(pw);\r
- pw.flush();\r
- return "Showing Stack with fake " + sw.getBuffer().toString();\r
- }\r
-\r
- // TODO use this instead of plain strings\r
- public static class Name implements Comparable {\r
- private String skeleton;\r
-\r
- private String pretty;\r
-\r
- public final int RAW = 0, TITLE = 1, NORMAL = 2;\r
-\r
- public Name(String name, int style) {\r
- if (name == null)\r
- name = "";\r
- if (style == RAW) {\r
- skeleton = pretty = name;\r
- } else {\r
- pretty = regularize(name, style == TITLE);\r
- skeleton = toSkeleton(pretty);\r
- }\r
- }\r
-\r
- public int compareTo(Object o) {\r
- return skeleton.compareTo(((Name) o).skeleton);\r
- }\r
-\r
- public boolean equals(Object o) {\r
- return skeleton.equals(((Name) o).skeleton);\r
- }\r
-\r
- public int hashCode() {\r
- return skeleton.hashCode();\r
- }\r
-\r
- public String toString() {\r
- return pretty;\r
- }\r
- }\r
-\r
- /**\r
- * @return the unicode map\r
- */\r
- public UnicodeMap getUnicodeMap() {\r
- return getUnicodeMap(false);\r
- }\r
-\r
- /**\r
- * @return the unicode map\r
- */\r
- public UnicodeMap getUnicodeMap(boolean getShortest) {\r
- if (!getShortest)\r
- return (UnicodeMap) getUnicodeMap_internal().cloneAsThawed();\r
- UnicodeMap result = new UnicodeMap();\r
- for (int i = 0; i <= 0x10FFFF; ++i) {\r
- // if (DEBUG && i == 0x41) System.out.println(i + "\t" +\r
- // getValue(i));\r
- String value = getValue(i, true);\r
- result.put(i, value);\r
- }\r
- return result;\r
- }\r
-\r
- /**\r
- * @return the unicode map\r
- */\r
- protected UnicodeMap getUnicodeMap_internal() {\r
- if (unicodeMap == null)\r
- unicodeMap = _getUnicodeMap();\r
- return unicodeMap;\r
- }\r
-\r
- protected UnicodeMap _getUnicodeMap() {\r
- UnicodeMap result = new UnicodeMap();\r
- HashMap myIntern = new HashMap();\r
- for (int i = 0; i <= 0x10FFFF; ++i) {\r
- // if (DEBUG && i == 0x41) System.out.println(i + "\t" +\r
- // getValue(i));\r
- String value = getValue(i);\r
- String iValue = (String) myIntern.get(value);\r
- if (iValue == null)\r
- myIntern.put(value, iValue = value);\r
- result.put(i, iValue);\r
- }\r
- if (DEBUG) {\r
- for (int i = 0; i <= 0x10FFFF; ++i) {\r
- // if (DEBUG && i == 0x41) System.out.println(i + "\t" +\r
- // getValue(i));\r
- String value = getValue(i);\r
- String resultValue = (String) result.getValue(i);\r
- if (!value.equals(resultValue)) {\r
- throw new RuntimeException("Value failure at: "\r
- + Utility.hex(i));\r
- }\r
- }\r
- }\r
- if (DEBUG && CHECK_NAME.equals(getName())) {\r
- System.out.println(getName() + ":\t" + getClass().getName() + "\t"\r
- + getVersion());\r
- System.out.println(getStack());\r
- System.out.println(result);\r
- }\r
- return result;\r
- }\r
-\r
- /**\r
- * Really ought to create a Collection UniqueList, that forces uniqueness.\r
- * But for now...\r
- */\r
- public static Collection addUnique(Object obj, Collection result) {\r
- if (obj != null && !result.contains(obj))\r
- result.add(obj);\r
- return result;\r
- }\r
-\r
- /**\r
- * Utility for managing property & non-string value aliases\r
- */\r
- public static final Comparator PROPERTY_COMPARATOR = new Comparator() {\r
- public int compare(Object o1, Object o2) {\r
- return compareNames((String) o1, (String) o2);\r
- }\r
- };\r
-\r
- /**\r
- * Utility for managing property & non-string value aliases\r
- * \r
- */\r
- // TODO optimize\r
- public static boolean equalNames(String a, String b) {\r
- if (a == b)\r
- return true;\r
- if (a == null)\r
- return false;\r
- return toSkeleton(a).equals(toSkeleton(b));\r
- }\r
-\r
- /**\r
- * Utility for managing property & non-string value aliases\r
- */\r
- // TODO optimize\r
- public static int compareNames(String a, String b) {\r
- if (a == b)\r
- return 0;\r
- if (a == null)\r
- return -1;\r
- if (b == null)\r
- return 1;\r
- return toSkeleton(a).compareTo(toSkeleton(b));\r
- }\r
-\r
- /**\r
- * Utility for managing property & non-string value aliases\r
- */\r
- // TODO account for special names, tibetan, hangul\r
- public static String toSkeleton(String source) {\r
- if (source == null)\r
- return null;\r
- StringBuffer skeletonBuffer = new StringBuffer();\r
- boolean gotOne = false;\r
- // remove spaces, '_', '-'\r
- // we can do this with char, since no surrogates are involved\r
- for (int i = 0; i < source.length(); ++i) {\r
- char ch = source.charAt(i);\r
- if (i > 0 && (ch == '_' || ch == ' ' || ch == '-')) {\r
- gotOne = true;\r
- } else {\r
- char ch2 = Character.toLowerCase(ch);\r
- if (ch2 != ch) {\r
- gotOne = true;\r
- skeletonBuffer.append(ch2);\r
- } else {\r
- skeletonBuffer.append(ch);\r
- }\r
- }\r
- }\r
- if (!gotOne)\r
- return source; // avoid string creation\r
- return skeletonBuffer.toString();\r
- }\r
-\r
- // get the name skeleton\r
- public static String toNameSkeleton(String source) {\r
- if (source == null)\r
- return null;\r
- StringBuffer result = new StringBuffer();\r
- // remove spaces, medial '-'\r
- // we can do this with char, since no surrogates are involved\r
- for (int i = 0; i < source.length(); ++i) {\r
- char ch = source.charAt(i);\r
- if (('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'Z')\r
- || ch == '<' || ch == '>') {\r
- result.append(ch);\r
- } else if (ch == ' ') {\r
- // don't copy ever\r
- } else if (ch == '-') {\r
- // only copy non-medials AND trailing O-E\r
- if (0 == i\r
- || i == source.length() - 1\r
- || source.charAt(i - 1) == ' '\r
- || source.charAt(i + 1) == ' '\r
- || (i == source.length() - 2\r
- && source.charAt(i - 1) == 'O' && source\r
- .charAt(i + 1) == 'E')) {\r
- System.out.println("****** EXCEPTION " + source);\r
- result.append(ch);\r
- }\r
- // otherwise don't copy\r
- } else {\r
- throw new IllegalArgumentException("Illegal Name Char: U+"\r
- + Utility.hex(ch) + ", " + ch);\r
- }\r
- }\r
- return result.toString();\r
- }\r
-\r
- /**\r
- * These routines use the Java functions, because they only need to act on\r
- * ASCII Changes space, - into _, inserts _ between lower and UPPER.\r
- */\r
- public static String regularize(String source, boolean titlecaseStart) {\r
- if (source == null)\r
- return source;\r
- /*\r
- * if (source.equals("noBreak")) { // HACK if (titlecaseStart) return\r
- * "NoBreak"; return source; }\r
- */\r
- StringBuffer result = new StringBuffer();\r
- int lastCat = -1;\r
- boolean haveFirstCased = true;\r
- for (int i = 0; i < source.length(); ++i) {\r
- char c = source.charAt(i);\r
- if (c == ' ' || c == '-' || c == '_') {\r
- c = '_';\r
- haveFirstCased = true;\r
- }\r
- if (c == '=')\r
- haveFirstCased = true;\r
- int cat = Character.getType(c);\r
- if (lastCat == Character.LOWERCASE_LETTER\r
- && cat == Character.UPPERCASE_LETTER) {\r
- result.append('_');\r
- }\r
- if (haveFirstCased\r
- && (cat == Character.LOWERCASE_LETTER\r
- || cat == Character.TITLECASE_LETTER || cat == Character.UPPERCASE_LETTER)) {\r
- if (titlecaseStart) {\r
- c = Character.toUpperCase(c);\r
- }\r
- haveFirstCased = false;\r
- }\r
- result.append(c);\r
- lastCat = cat;\r
- }\r
- return result.toString();\r
- }\r
-\r
- /**\r
- * Utility function for comparing codepoint to string without generating new\r
- * string.\r
- * \r
- * @param codepoint\r
- * @param other\r
- * @return true if the codepoint equals the string\r
- */\r
- public static final boolean equals(int codepoint, String other) {\r
- if (other.length() == 1) {\r
- return codepoint == other.charAt(0);\r
- }\r
- if (other.length() == 2) {\r
- return other.equals(UTF16.valueOf(codepoint));\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * Utility that should be on UnicodeSet\r
- * \r
- * @param source\r
- * @param result\r
- */\r
- static public void addAll(UnicodeSetIterator source, UnicodeSet result) {\r
- while (source.nextRange()) {\r
- if (source.codepoint == UnicodeSetIterator.IS_STRING) {\r
- result.add(source.string);\r
- } else {\r
- result.add(source.codepoint, source.codepointEnd);\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * Really ought to create a Collection UniqueList, that forces uniqueness.\r
- * But for now...\r
- */\r
- public static Collection addAllUnique(Collection source, Collection result) {\r
- for (Iterator it = source.iterator(); it.hasNext();) {\r
- addUnique(it.next(), result);\r
- }\r
- return result;\r
- }\r
-\r
- /**\r
- * Really ought to create a Collection UniqueList, that forces uniqueness.\r
- * But for now...\r
- */\r
- public static Collection addAllUnique(Object[] source, Collection result) {\r
- for (int i = 0; i < source.length; ++i) {\r
- addUnique(source[i], result);\r
- }\r
- return result;\r
- }\r
-\r
- static public class Factory {\r
- static boolean DEBUG = false;\r
-\r
- Map canonicalNames = new TreeMap();\r
-\r
- Map skeletonNames = new TreeMap();\r
-\r
- Map propertyCache = new HashMap(1);\r
-\r
- public final Factory add(UnicodeProperty sp) {\r
- canonicalNames.put(sp.getName(), sp);\r
- List c = sp.getNameAliases(new ArrayList(1));\r
- Iterator it = c.iterator();\r
- while (it.hasNext()) {\r
- skeletonNames.put(toSkeleton((String) it.next()), sp);\r
- }\r
- return this;\r
- }\r
-\r
- public final UnicodeProperty getProperty(String propertyAlias) {\r
- return (UnicodeProperty) skeletonNames\r
- .get(toSkeleton(propertyAlias));\r
- }\r
-\r
- public final List getAvailableNames() {\r
- return getAvailableNames(null);\r
- }\r
-\r
- public final List getAvailableNames(List result) {\r
- if (result == null)\r
- result = new ArrayList(1);\r
- Iterator it = canonicalNames.keySet().iterator();\r
- while (it.hasNext()) {\r
- addUnique(it.next(), result);\r
- }\r
- return result;\r
- }\r
-\r
- public final List getAvailableNames(int propertyTypeMask) {\r
- return getAvailableNames(propertyTypeMask, null);\r
- }\r
-\r
- public final List getAvailableNames(int propertyTypeMask, List result) {\r
- if (result == null)\r
- result = new ArrayList(1);\r
- Iterator it = canonicalNames.keySet().iterator();\r
- while (it.hasNext()) {\r
- String item = (String) it.next();\r
- UnicodeProperty property = getProperty(item);\r
- if (DEBUG)\r
- System.out.println("Properties: " + item + ","\r
- + property.getType());\r
- if (!property.isType(propertyTypeMask)) {\r
- // System.out.println("Masking: " + property.getType() + ","\r
- // + propertyTypeMask);\r
- continue;\r
- }\r
- addUnique(property.getName(), result);\r
- }\r
- return result;\r
- }\r
-\r
- InversePatternMatcher inverseMatcher = new InversePatternMatcher();\r
-\r
- /**\r
- * Format is: propname ('=' | '!=') propvalue ( '|' propValue )*\r
- */\r
- public final UnicodeSet getSet(String propAndValue,\r
- PatternMatcher matcher, UnicodeSet result) {\r
- int equalPos = propAndValue.indexOf('=');\r
- String prop = propAndValue.substring(0, equalPos);\r
- String value = propAndValue.substring(equalPos + 1);\r
- boolean negative = false;\r
- if (prop.endsWith("!")) {\r
- prop = prop.substring(0, prop.length() - 1);\r
- negative = true;\r
- }\r
- prop = prop.trim();\r
- UnicodeProperty up = getProperty(prop);\r
- if (matcher == null) {\r
- matcher = new SimpleMatcher(value, up\r
- .isType(STRING_OR_MISC_MASK) ? null\r
- : PROPERTY_COMPARATOR);\r
- }\r
- if (negative) {\r
- inverseMatcher.set(matcher);\r
- matcher = inverseMatcher;\r
- }\r
- return up.getSet(matcher.set(value), result);\r
- }\r
-\r
- public final UnicodeSet getSet(String propAndValue,\r
- PatternMatcher matcher) {\r
- return getSet(propAndValue, matcher, null);\r
- }\r
-\r
- public final UnicodeSet getSet(String propAndValue) {\r
- return getSet(propAndValue, null, null);\r
- }\r
-\r
- public final SymbolTable getSymbolTable(String prefix) {\r
- return new PropertySymbolTable(prefix);\r
- }\r
-\r
- private class MyXSymbolTable extends UnicodeSet.XSymbolTable {\r
- public boolean applyPropertyAlias(String propertyName,\r
- String propertyValue, UnicodeSet result) {\r
- if (false)\r
- System.out.println(propertyName + "=" + propertyValue);\r
- UnicodeProperty prop = getProperty(propertyName);\r
- if (prop == null)\r
- return false;\r
- result.clear();\r
- UnicodeSet x = prop.getSet(propertyValue, result);\r
- return x.size() != 0;\r
- }\r
- }\r
-\r
- public final UnicodeSet.XSymbolTable getXSymbolTable() {\r
- return new MyXSymbolTable();\r
- }\r
-\r
- private class PropertySymbolTable implements SymbolTable {\r
- static final boolean DEBUG = false;\r
-\r
- private String prefix;\r
-\r
- RegexMatcher regexMatcher = new RegexMatcher();\r
-\r
- PropertySymbolTable(String prefix) {\r
- this.prefix = prefix;\r
- }\r
-\r
- public char[] lookup(String s) {\r
- if (DEBUG)\r
- System.out.println("\t(" + prefix + ")Looking up " + s);\r
- // ensure, again, that prefix matches\r
- int start = prefix.length();\r
- if (!s.regionMatches(true, 0, prefix, 0, start))\r
- return null;\r
-\r
- int pos = s.indexOf(':', start);\r
- if (pos < 0) { // should never happen\r
- throw new IllegalArgumentException(\r
- "Internal Error: missing =: " + s + "\r\n");\r
- }\r
- UnicodeProperty prop = getProperty(s.substring(start, pos));\r
- if (prop == null) {\r
- throw new IllegalArgumentException("Invalid Property in: "\r
- + s + "\r\nUse " + showSet(getAvailableNames()));\r
- }\r
- String value = s.substring(pos + 1);\r
- UnicodeSet set;\r
- if (value.startsWith("\u00AB")) { // regex!\r
- set = prop.getSet(regexMatcher.set(value.substring(1, value\r
- .length() - 1)));\r
- } else {\r
- set = prop.getSet(value);\r
- }\r
- if (set.size() == 0) {\r
- throw new IllegalArgumentException(\r
- "Empty Property-Value in: " + s + "\r\nUse "\r
- + showSet(prop.getAvailableValues()));\r
- }\r
- if (DEBUG)\r
- System.out.println("\t(" + prefix + ")Returning "\r
- + set.toPattern(true));\r
- return set.toPattern(true).toCharArray(); // really ugly\r
- }\r
-\r
- private String showSet(List list) {\r
- StringBuffer result = new StringBuffer("[");\r
- boolean first = true;\r
- for (Iterator it = list.iterator(); it.hasNext();) {\r
- if (!first)\r
- result.append(", ");\r
- else\r
- first = false;\r
- result.append(it.next().toString());\r
- }\r
- result.append("]");\r
- return result.toString();\r
- }\r
-\r
- public UnicodeMatcher lookupMatcher(int ch) {\r
- return null;\r
- }\r
-\r
- public String parseReference(String text, ParsePosition pos,\r
- int limit) {\r
- if (DEBUG)\r
- System.out.println("\t(" + prefix + ")Parsing <"\r
- + text.substring(pos.getIndex(), limit) + ">");\r
- int start = pos.getIndex();\r
- // ensure that it starts with 'prefix'\r
- if (!text\r
- .regionMatches(true, start, prefix, 0, prefix.length()))\r
- return null;\r
- start += prefix.length();\r
- // now see if it is of the form identifier:identifier\r
- int i = getIdentifier(text, start, limit);\r
- if (i == start)\r
- return null;\r
- String prop = text.substring(start, i);\r
- String value = "true";\r
- if (i < limit) {\r
- if (text.charAt(i) == ':') {\r
- int j;\r
- if (text.charAt(i + 1) == '\u00AB') { // regular\r
- // expression\r
- j = text.indexOf('\u00BB', i + 2) + 1; // include\r
- // last\r
- // character\r
- if (j <= 0)\r
- return null;\r
- } else {\r
- j = getIdentifier(text, i + 1, limit);\r
- }\r
- value = text.substring(i + 1, j);\r
- i = j;\r
- }\r
- }\r
- pos.setIndex(i);\r
- if (DEBUG)\r
- System.out.println("\t(" + prefix + ")Parsed <" + prop\r
- + ">=<" + value + ">");\r
- return prefix + prop + ":" + value;\r
- }\r
-\r
- private int getIdentifier(String text, int start, int limit) {\r
- if (DEBUG)\r
- System.out.println("\tGetID <"\r
- + text.substring(start, limit) + ">");\r
- int cp = 0;\r
- int i;\r
- for (i = start; i < limit; i += UTF16.getCharCount(cp)) {\r
- cp = UTF16.charAt(text, i);\r
- if (!com.ibm.icu.lang.UCharacter\r
- .isUnicodeIdentifierPart(cp)\r
- && cp != '.') {\r
- break;\r
- }\r
- }\r
- if (DEBUG)\r
- System.out.println("\tGotID <" + text.substring(start, i)\r
- + ">");\r
- return i;\r
- }\r
- }\r
- }\r
-\r
- public static class FilteredProperty extends UnicodeProperty {\r
- private UnicodeProperty property;\r
-\r
- protected StringFilter filter;\r
-\r
- protected UnicodeSetIterator matchIterator = new UnicodeSetIterator(\r
- new UnicodeSet(0, 0x10FFFF));\r
-\r
- protected HashMap backmap;\r
-\r
- boolean allowValueAliasCollisions = false;\r
-\r
- public FilteredProperty(UnicodeProperty property, StringFilter filter) {\r
- this.property = property;\r
- this.filter = filter;\r
- }\r
-\r
- public StringFilter getFilter() {\r
- return filter;\r
- }\r
-\r
- public UnicodeProperty setFilter(StringFilter filter) {\r
- this.filter = filter;\r
- return this;\r
- }\r
-\r
- List temp = new ArrayList(1);\r
-\r
- public List _getAvailableValues(List result) {\r
- temp.clear();\r
- return filter.addUnique(property.getAvailableValues(temp), result);\r
- }\r
-\r
- public List _getNameAliases(List result) {\r
- temp.clear();\r
- return filter.addUnique(property.getNameAliases(temp), result);\r
- }\r
-\r
- public String _getValue(int codepoint) {\r
- return filter.remap(property.getValue(codepoint));\r
- }\r
-\r
- public List _getValueAliases(String valueAlias, List result) {\r
- if (backmap == null) {\r
- backmap = new HashMap(1);\r
- temp.clear();\r
- Iterator it = property.getAvailableValues(temp).iterator();\r
- while (it.hasNext()) {\r
- String item = (String) it.next();\r
- String mappedItem = filter.remap(item);\r
- if (backmap.get(mappedItem) != null\r
- && !allowValueAliasCollisions) {\r
- throw new IllegalArgumentException(\r
- "Filter makes values collide! " + item + ", "\r
- + mappedItem);\r
- }\r
- backmap.put(mappedItem, item);\r
- }\r
- }\r
- valueAlias = (String) backmap.get(valueAlias);\r
- temp.clear();\r
- return filter.addUnique(property.getValueAliases(valueAlias, temp),\r
- result);\r
- }\r
-\r
- public String _getVersion() {\r
- return property.getVersion();\r
- }\r
-\r
- public boolean isAllowValueAliasCollisions() {\r
- return allowValueAliasCollisions;\r
- }\r
-\r
- public FilteredProperty setAllowValueAliasCollisions(boolean b) {\r
- allowValueAliasCollisions = b;\r
- return this;\r
- }\r
-\r
- }\r
-\r
- public static abstract class StringFilter implements Cloneable {\r
- public abstract String remap(String original);\r
-\r
- public final List addUnique(Collection source, List result) {\r
- if (result == null)\r
- result = new ArrayList(1);\r
- Iterator it = source.iterator();\r
- while (it.hasNext()) {\r
- UnicodeProperty.addUnique(remap((String) it.next()), result);\r
- }\r
- return result;\r
- }\r
- /*\r
- * public Object clone() { try { return super.clone(); } catch\r
- * (CloneNotSupportedException e) { throw new\r
- * IllegalStateException("Should never happen."); } }\r
- */\r
- }\r
-\r
- public static class MapFilter extends StringFilter {\r
- private Map valueMap;\r
-\r
- public MapFilter(Map valueMap) {\r
- this.valueMap = valueMap;\r
- }\r
-\r
- public String remap(String original) {\r
- Object changed = valueMap.get(original);\r
- return changed == null ? original : (String) changed;\r
- }\r
-\r
- public Map getMap() {\r
- return valueMap;\r
- }\r
- }\r
-\r
- public interface PatternMatcher extends ObjectMatcher {\r
- public PatternMatcher set(String pattern);\r
- }\r
-\r
- public static class InversePatternMatcher extends InverseMatcher implements\r
- PatternMatcher {\r
- PatternMatcher other;\r
-\r
- public PatternMatcher set(PatternMatcher toInverse) {\r
- other = toInverse;\r
- return this;\r
- }\r
-\r
- public boolean matches(Object value) {\r
- return !other.matches(value);\r
- }\r
-\r
- public PatternMatcher set(String pattern) {\r
- other.set(pattern);\r
- return this;\r
- }\r
- }\r
-\r
- public static class SimpleMatcher implements PatternMatcher {\r
- Comparator comparator;\r
-\r
- String pattern;\r
-\r
- public SimpleMatcher(String pattern, Comparator comparator) {\r
- this.comparator = comparator;\r
- this.pattern = pattern;\r
- }\r
-\r
- public boolean matches(Object value) {\r
- if (comparator == null)\r
- return pattern.equals(value);\r
- return comparator.compare(pattern, value) == 0;\r
- }\r
-\r
- public PatternMatcher set(String pattern) {\r
- this.pattern = pattern;\r
- return this;\r
- }\r
- }\r
-\r
- public static class RegexMatcher implements UnicodeProperty.PatternMatcher {\r
- private java.util.regex.Matcher matcher;\r
-\r
- public UnicodeProperty.PatternMatcher set(String pattern) {\r
- matcher = Pattern.compile(pattern).matcher("");\r
- return this;\r
- }\r
-\r
- public boolean matches(Object value) {\r
- matcher.reset(value.toString());\r
- return matcher.matches();\r
- }\r
- }\r
-\r
- public static abstract class BaseProperty extends UnicodeProperty {\r
- protected List propertyAliases = new ArrayList(1);\r
-\r
- protected Map toValueAliases;\r
-\r
- protected String version;\r
-\r
- public BaseProperty setMain(String alias, String shortAlias,\r
- int propertyType, String version) {\r
- setName(alias);\r
- setType(propertyType);\r
- propertyAliases.add(shortAlias);\r
- propertyAliases.add(alias);\r
- this.version = version;\r
- return this;\r
- }\r
-\r
- public String _getVersion() {\r
- return version;\r
- }\r
-\r
- public List _getNameAliases(List result) {\r
- addAllUnique(propertyAliases, result);\r
- return result;\r
- }\r
-\r
- public BaseProperty addValueAliases(String[][] valueAndAlternates,\r
- boolean errorIfCant) {\r
- if (toValueAliases == null)\r
- _fixValueAliases();\r
- for (int i = 0; i < valueAndAlternates.length; ++i) {\r
- for (int j = 1; j < valueAndAlternates[0].length; ++j) {\r
- addValueAlias(valueAndAlternates[i][0],\r
- valueAndAlternates[i][j], errorIfCant);\r
- }\r
- }\r
- return this;\r
- }\r
-\r
- public void addValueAlias(String value, String valueAlias,\r
- boolean errorIfCant) {\r
- List result = (List) toValueAliases.get(value);\r
- if (result == null && !errorIfCant)\r
- return;\r
- addUnique(value, result);\r
- addUnique(valueAlias, result);\r
- }\r
-\r
- protected List _getValueAliases(String valueAlias, List result) {\r
- if (toValueAliases == null)\r
- _fixValueAliases();\r
- List a = (List) toValueAliases.get(valueAlias);\r
- if (a != null)\r
- addAllUnique(a, result);\r
- return result;\r
- }\r
-\r
- protected void _fixValueAliases() {\r
- if (toValueAliases == null)\r
- toValueAliases = new HashMap(1);\r
- for (Iterator it = getAvailableValues().iterator(); it.hasNext();) {\r
- Object value = it.next();\r
- _ensureValueInAliases(value);\r
- }\r
- }\r
-\r
- protected void _ensureValueInAliases(Object value) {\r
- List result = (List) toValueAliases.get(value);\r
- if (result == null)\r
- toValueAliases.put(value, result = new ArrayList(1));\r
- addUnique(value, result);\r
- }\r
-\r
- public BaseProperty swapFirst2ValueAliases() {\r
- for (Iterator it = toValueAliases.keySet().iterator(); it.hasNext();) {\r
- List list = (List) toValueAliases.get(it.next());\r
- if (list.size() < 2)\r
- continue;\r
- Object first = list.get(0);\r
- list.set(0, list.get(1));\r
- list.set(1, first);\r
- }\r
- return this;\r
- }\r
-\r
- /**\r
- * @param string\r
- * @return\r
- */\r
- public UnicodeProperty addName(String string) {\r
- throw new UnsupportedOperationException();\r
- }\r
-\r
- }\r
-\r
- public static abstract class SimpleProperty extends BaseProperty {\r
- List values;\r
-\r
- public UnicodeProperty addName(String alias) {\r
- propertyAliases.add(alias);\r
- return this;\r
- }\r
-\r
- public SimpleProperty setValues(String valueAlias) {\r
- _addToValues(valueAlias, null);\r
- return this;\r
- }\r
-\r
- public SimpleProperty setValues(String[] valueAliases,\r
- String[] alternateValueAliases) {\r
- for (int i = 0; i < valueAliases.length; ++i) {\r
- if (valueAliases[i].equals(UNUSED))\r
- continue;\r
- _addToValues(\r
- valueAliases[i],\r
- alternateValueAliases != null ? alternateValueAliases[i]\r
- : null);\r
- }\r
- return this;\r
- }\r
-\r
- public SimpleProperty setValues(List valueAliases) {\r
- this.values = new ArrayList(valueAliases);\r
- for (Iterator it = this.values.iterator(); it.hasNext();) {\r
- _addToValues((String) it.next(), null);\r
- }\r
- return this;\r
- }\r
-\r
- public List _getAvailableValues(List result) {\r
- if (values == null)\r
- _fillValues();\r
- result.addAll(values);\r
- return result;\r
- }\r
-\r
- protected void _fillValues() {\r
- List newvalues = (List) getUnicodeMap_internal()\r
- .getAvailableValues(new ArrayList());\r
- for (Iterator it = newvalues.iterator(); it.hasNext();) {\r
- _addToValues((String) it.next(), null);\r
- }\r
- }\r
-\r
- private void _addToValues(String item, String alias) {\r
- if (values == null)\r
- values = new ArrayList(1);\r
- if (toValueAliases == null)\r
- _fixValueAliases();\r
- addUnique(item, values);\r
- _ensureValueInAliases(item);\r
- addValueAlias(item, alias, true);\r
- }\r
- /* public String _getVersion() {\r
- return version;\r
- }\r
- */\r
- }\r
-\r
- public static class UnicodeMapProperty extends BaseProperty {\r
- /*\r
- * Example of usage:\r
- * new UnicodeProperty.UnicodeMapProperty() {\r
- {\r
- unicodeMap = new UnicodeMap();\r
- unicodeMap.setErrorOnReset(true);\r
- unicodeMap.put(0xD, "CR");\r
- unicodeMap.put(0xA, "LF");\r
- UnicodeProperty cat = getProperty("General_Category");\r
- UnicodeSet temp = cat.getSet("Line_Separator")\r
- .addAll(cat.getSet("Paragraph_Separator"))\r
- .addAll(cat.getSet("Control"))\r
- .addAll(cat.getSet("Format"))\r
- .remove(0xD).remove(0xA).remove(0x200C).remove(0x200D);\r
- unicodeMap.putAll(temp, "Control");\r
- UnicodeSet graphemeExtend = getProperty("Grapheme_Extend").getSet("true");\r
- unicodeMap.putAll(graphemeExtend,"Extend");\r
- UnicodeProperty hangul = getProperty("Hangul_Syllable_Type");\r
- unicodeMap.putAll(hangul.getSet("L"),"L");\r
- unicodeMap.putAll(hangul.getSet("V"),"V");\r
- unicodeMap.putAll(hangul.getSet("T"),"T");\r
- unicodeMap.putAll(hangul.getSet("LV"),"LV");\r
- unicodeMap.putAll(hangul.getSet("LVT"),"LVT");\r
- unicodeMap.setMissing("Other");\r
- }\r
- }.setMain("Grapheme_Cluster_Break", "GCB", UnicodeProperty.ENUMERATED, version)\r
- */\r
- protected UnicodeMap unicodeMap;\r
-\r
- public UnicodeMapProperty set(UnicodeMap map) {\r
- unicodeMap = map;\r
- return this;\r
- }\r
-\r
- protected String _getValue(int codepoint) {\r
- return (String) unicodeMap.getValue(codepoint);\r
- }\r
-\r
- /* protected List _getValueAliases(String valueAlias, List result) {\r
- if (!unicodeMap.getAvailableValues().contains(valueAlias)) return result;\r
- result.add(valueAlias);\r
- return result; // no other aliases\r
- }\r
- */protected List _getAvailableValues(List result) {\r
- return (List) unicodeMap.getAvailableValues(result);\r
- }\r
- }\r
-}\r
-//#endif\r
-\r
+//##header J2SE15
+//#if defined(FOUNDATION10) || defined(J2SE13)
+//#else
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2009, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.test.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+import com.ibm.icu.dev.test.util.CollectionUtilities.InverseMatcher;
+import com.ibm.icu.dev.test.util.CollectionUtilities.ObjectMatcher;
+import com.ibm.icu.impl.Utility;
+import com.ibm.icu.text.SymbolTable;
+import com.ibm.icu.text.UTF16;
+import com.ibm.icu.text.UnicodeMatcher;
+import com.ibm.icu.text.UnicodeSet;
+import com.ibm.icu.text.UnicodeSetIterator;
+
+public abstract class UnicodeProperty extends UnicodeLabel {
+
+ public static boolean DEBUG = false;
+
+ public static String CHECK_NAME = "FC_NFKC_Closure";
+
+ public static int CHECK_VALUE = 0x037A;
+
+ private String name;
+
+ private String firstNameAlias = null;
+
+ private int type;
+
+ private Map valueToFirstValueAlias = null;
+
+ /*
+ * Name: Unicode_1_Name Name: ISO_Comment Name: Name Name: Unicode_1_Name
+ *
+ */
+
+ public static final int UNKNOWN = 0, BINARY = 2, EXTENDED_BINARY = 3,
+ ENUMERATED = 4, EXTENDED_ENUMERATED = 5, CATALOG = 6,
+ EXTENDED_CATALOG = 7, MISC = 8, EXTENDED_MISC = 9, STRING = 10,
+ EXTENDED_STRING = 11, NUMERIC = 12, EXTENDED_NUMERIC = 13,
+ START_TYPE = 2, LIMIT_TYPE = 14, EXTENDED_MASK = 1,
+ CORE_MASK = ~EXTENDED_MASK, BINARY_MASK = (1 << BINARY)
+ | (1 << EXTENDED_BINARY), STRING_MASK = (1 << STRING)
+ | (1 << EXTENDED_STRING),
+ STRING_OR_MISC_MASK = (1 << STRING) | (1 << EXTENDED_STRING)
+ | (1 << MISC) | (1 << EXTENDED_MISC),
+ ENUMERATED_OR_CATALOG_MASK = (1 << ENUMERATED)
+ | (1 << EXTENDED_ENUMERATED) | (1 << CATALOG)
+ | (1 << EXTENDED_CATALOG);
+
+ private static final String[] TYPE_NAMES = { "Unknown", "Unknown",
+ "Binary", "Extended Binary", "Enumerated", "Extended Enumerated",
+ "Catalog", "Extended Catalog", "Miscellaneous",
+ "Extended Miscellaneous", "String", "Extended String", "Numeric",
+ "Extended Numeric", };
+
+ public static String getTypeName(int propType) {
+ return TYPE_NAMES[propType];
+ }
+
+ public final String getName() {
+ return name;
+ }
+
+ public final int getType() {
+ return type;
+ }
+
+ public final boolean isType(int mask) {
+ return ((1 << type) & mask) != 0;
+ }
+
+ protected final void setName(String string) {
+ if (string == null)
+ throw new IllegalArgumentException("Name must not be null");
+ name = string;
+ }
+
+ protected final void setType(int i) {
+ type = i;
+ }
+
+ public String getVersion() {
+ return _getVersion();
+ }
+
+ public String getValue(int codepoint) {
+ if (DEBUG && CHECK_VALUE == codepoint && CHECK_NAME.equals(getName())) {
+ String value = _getValue(codepoint);
+ System.out.println(getName() + "(" + Utility.hex(codepoint) + "):"
+ + (getType() == STRING ? Utility.hex(value) : value));
+ return value;
+ }
+ return _getValue(codepoint);
+ }
+
+ // public String getValue(int codepoint, boolean isShort) {
+ // return getValue(codepoint);
+ // }
+
+ public List getNameAliases(List result) {
+ if (result == null)
+ result = new ArrayList(1);
+ return _getNameAliases(result);
+ }
+
+ public List getValueAliases(String valueAlias, List result) {
+ if (result == null)
+ result = new ArrayList(1);
+ result = _getValueAliases(valueAlias, result);
+ if (!result.contains(valueAlias)) { // FIX && type < NUMERIC
+ result = _getValueAliases(valueAlias, result); // for debugging
+ throw new IllegalArgumentException("Internal error: " + getName()
+ + " doesn't contain " + valueAlias + ": "
+ + new BagFormatter().join(result));
+ }
+ return result;
+ }
+
+ public List getAvailableValues(List result) {
+ if (result == null)
+ result = new ArrayList(1);
+ return _getAvailableValues(result);
+ }
+
+ protected abstract String _getVersion();
+
+ protected abstract String _getValue(int codepoint);
+
+ protected abstract List _getNameAliases(List result);
+
+ protected abstract List _getValueAliases(String valueAlias, List result);
+
+ protected abstract List _getAvailableValues(List result);
+
+ // conveniences
+ public final List getNameAliases() {
+ return getNameAliases(null);
+ }
+
+ public final List getValueAliases(String valueAlias) {
+ return getValueAliases(valueAlias, null);
+ }
+
+ public final List getAvailableValues() {
+ return getAvailableValues(null);
+ }
+
+ public final String getValue(int codepoint, boolean getShortest) {
+ String result = getValue(codepoint);
+ if (type >= MISC || result == null || !getShortest)
+ return result;
+ return getFirstValueAlias(result);
+ }
+
+ public final String getFirstNameAlias() {
+ if (firstNameAlias == null) {
+ firstNameAlias = (String) getNameAliases().get(0);
+ }
+ return firstNameAlias;
+ }
+
+ public final String getFirstValueAlias(String value) {
+ if (valueToFirstValueAlias == null)
+ _getFirstValueAliasCache();
+ return (String) valueToFirstValueAlias.get(value);
+ }
+
+ private void _getFirstValueAliasCache() {
+ maxValueWidth = 0;
+ maxFirstValueAliasWidth = 0;
+ valueToFirstValueAlias = new HashMap(1);
+ Iterator it = getAvailableValues().iterator();
+ while (it.hasNext()) {
+ String value = (String) it.next();
+ String first = (String) getValueAliases(value).get(0);
+ if (first == null) { // internal error
+ throw new IllegalArgumentException(
+ "Value not in value aliases: " + value);
+ }
+ if (DEBUG && CHECK_NAME.equals(getName())) {
+ System.out.println("First Alias: " + getName() + ": " + value
+ + " => " + first
+ + new BagFormatter().join(getValueAliases(value)));
+ }
+ valueToFirstValueAlias.put(value, first);
+ if (value.length() > maxValueWidth) {
+ maxValueWidth = value.length();
+ }
+ if (first.length() > maxFirstValueAliasWidth) {
+ maxFirstValueAliasWidth = first.length();
+ }
+ }
+ }
+
+ private int maxValueWidth = -1;
+
+ private int maxFirstValueAliasWidth = -1;
+
+ public int getMaxWidth(boolean getShortest) {
+ if (maxValueWidth < 0)
+ _getFirstValueAliasCache();
+ if (getShortest)
+ return maxFirstValueAliasWidth;
+ return maxValueWidth;
+ }
+
+ public final UnicodeSet getSet(String propertyValue) {
+ return getSet(propertyValue, null);
+ }
+
+ public final UnicodeSet getSet(PatternMatcher matcher) {
+ return getSet(matcher, null);
+ }
+
+ public final UnicodeSet getSet(String propertyValue, UnicodeSet result) {
+ return getSet(new SimpleMatcher(propertyValue,
+ isType(STRING_OR_MISC_MASK) ? null : PROPERTY_COMPARATOR),
+ result);
+ }
+
+ private UnicodeMap unicodeMap = null;
+
+ public static final String UNUSED = "??";
+
+ public final UnicodeSet getSet(PatternMatcher matcher, UnicodeSet result) {
+ if (result == null)
+ result = new UnicodeSet();
+ if (isType(STRING_OR_MISC_MASK)) {
+ for (int i = 0; i <= 0x10FFFF; ++i) {
+ String value = getValue(i);
+ if (value != null && matcher.matches(value)) {
+ result.add(i);
+ }
+ }
+ return result;
+ }
+ List temp = new ArrayList(1); // to avoid reallocating...
+ UnicodeMap um = getUnicodeMap_internal();
+ Iterator it = um.getAvailableValues(null).iterator();
+ main: while (it.hasNext()) {
+ String value = (String) it.next();
+ temp.clear();
+ Iterator it2 = getValueAliases(value, temp).iterator();
+ while (it2.hasNext()) {
+ String value2 = (String) it2.next();
+ // System.out.println("Values:" + value2);
+ if (matcher.matches(value2)
+ || matcher.matches(toSkeleton(value2))) {
+ um.getSet(value, result);
+ continue main;
+ }
+ }
+ }
+ return result;
+ }
+
+ /*
+ * public UnicodeSet getMatchSet(UnicodeSet result) { if (result == null)
+ * result = new UnicodeSet(); addAll(matchIterator, result); return result; }
+ *
+ * public void setMatchSet(UnicodeSet set) { matchIterator = new
+ * UnicodeSetIterator(set); }
+ */
+
+ /**
+ * Utility for debugging
+ */
+ public static String getStack() {
+ Exception e = new Exception();
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ e.printStackTrace(pw);
+ pw.flush();
+ return "Showing Stack with fake " + sw.getBuffer().toString();
+ }
+
+ // TODO use this instead of plain strings
+ public static class Name implements Comparable {
+ private String skeleton;
+
+ private String pretty;
+
+ public final int RAW = 0, TITLE = 1, NORMAL = 2;
+
+ public Name(String name, int style) {
+ if (name == null)
+ name = "";
+ if (style == RAW) {
+ skeleton = pretty = name;
+ } else {
+ pretty = regularize(name, style == TITLE);
+ skeleton = toSkeleton(pretty);
+ }
+ }
+
+ public int compareTo(Object o) {
+ return skeleton.compareTo(((Name) o).skeleton);
+ }
+
+ public boolean equals(Object o) {
+ return skeleton.equals(((Name) o).skeleton);
+ }
+
+ public int hashCode() {
+ return skeleton.hashCode();
+ }
+
+ public String toString() {
+ return pretty;
+ }
+ }
+
+ /**
+ * @return the unicode map
+ */
+ public UnicodeMap getUnicodeMap() {
+ return getUnicodeMap(false);
+ }
+
+ /**
+ * @return the unicode map
+ */
+ public UnicodeMap getUnicodeMap(boolean getShortest) {
+ if (!getShortest)
+ return (UnicodeMap) getUnicodeMap_internal().cloneAsThawed();
+ UnicodeMap result = new UnicodeMap();
+ for (int i = 0; i <= 0x10FFFF; ++i) {
+ // if (DEBUG && i == 0x41) System.out.println(i + "\t" +
+ // getValue(i));
+ String value = getValue(i, true);
+ result.put(i, value);
+ }
+ return result;
+ }
+
+ /**
+ * @return the unicode map
+ */
+ protected UnicodeMap getUnicodeMap_internal() {
+ if (unicodeMap == null)
+ unicodeMap = _getUnicodeMap();
+ return unicodeMap;
+ }
+
+ protected UnicodeMap _getUnicodeMap() {
+ UnicodeMap result = new UnicodeMap();
+ HashMap myIntern = new HashMap();
+ for (int i = 0; i <= 0x10FFFF; ++i) {
+ // if (DEBUG && i == 0x41) System.out.println(i + "\t" +
+ // getValue(i));
+ String value = getValue(i);
+ String iValue = (String) myIntern.get(value);
+ if (iValue == null)
+ myIntern.put(value, iValue = value);
+ result.put(i, iValue);
+ }
+ if (DEBUG) {
+ for (int i = 0; i <= 0x10FFFF; ++i) {
+ // if (DEBUG && i == 0x41) System.out.println(i + "\t" +
+ // getValue(i));
+ String value = getValue(i);
+ String resultValue = (String) result.getValue(i);
+ if (!value.equals(resultValue)) {
+ throw new RuntimeException("Value failure at: "
+ + Utility.hex(i));
+ }
+ }
+ }
+ if (DEBUG && CHECK_NAME.equals(getName())) {
+ System.out.println(getName() + ":\t" + getClass().getName() + "\t"
+ + getVersion());
+ System.out.println(getStack());
+ System.out.println(result);
+ }
+ return result;
+ }
+
+ /**
+ * Really ought to create a Collection UniqueList, that forces uniqueness.
+ * But for now...
+ */
+ public static Collection addUnique(Object obj, Collection result) {
+ if (obj != null && !result.contains(obj))
+ result.add(obj);
+ return result;
+ }
+
+ /**
+ * Utility for managing property & non-string value aliases
+ */
+ public static final Comparator PROPERTY_COMPARATOR = new Comparator() {
+ public int compare(Object o1, Object o2) {
+ return compareNames((String) o1, (String) o2);
+ }
+ };
+
+ /**
+ * Utility for managing property & non-string value aliases
+ *
+ */
+ // TODO optimize
+ public static boolean equalNames(String a, String b) {
+ if (a == b)
+ return true;
+ if (a == null)
+ return false;
+ return toSkeleton(a).equals(toSkeleton(b));
+ }
+
+ /**
+ * Utility for managing property & non-string value aliases
+ */
+ // TODO optimize
+ public static int compareNames(String a, String b) {
+ if (a == b)
+ return 0;
+ if (a == null)
+ return -1;
+ if (b == null)
+ return 1;
+ return toSkeleton(a).compareTo(toSkeleton(b));
+ }
+
+ /**
+ * Utility for managing property & non-string value aliases
+ */
+ // TODO account for special names, tibetan, hangul
+ public static String toSkeleton(String source) {
+ if (source == null)
+ return null;
+ StringBuffer skeletonBuffer = new StringBuffer();
+ boolean gotOne = false;
+ // remove spaces, '_', '-'
+ // we can do this with char, since no surrogates are involved
+ for (int i = 0; i < source.length(); ++i) {
+ char ch = source.charAt(i);
+ if (i > 0 && (ch == '_' || ch == ' ' || ch == '-')) {
+ gotOne = true;
+ } else {
+ char ch2 = Character.toLowerCase(ch);
+ if (ch2 != ch) {
+ gotOne = true;
+ skeletonBuffer.append(ch2);
+ } else {
+ skeletonBuffer.append(ch);
+ }
+ }
+ }
+ if (!gotOne)
+ return source; // avoid string creation
+ return skeletonBuffer.toString();
+ }
+
+ // get the name skeleton
+ public static String toNameSkeleton(String source) {
+ if (source == null)
+ return null;
+ StringBuffer result = new StringBuffer();
+ // remove spaces, medial '-'
+ // we can do this with char, since no surrogates are involved
+ for (int i = 0; i < source.length(); ++i) {
+ char ch = source.charAt(i);
+ if (('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'Z')
+ || ch == '<' || ch == '>') {
+ result.append(ch);
+ } else if (ch == ' ') {
+ // don't copy ever
+ } else if (ch == '-') {
+ // only copy non-medials AND trailing O-E
+ if (0 == i
+ || i == source.length() - 1
+ || source.charAt(i - 1) == ' '
+ || source.charAt(i + 1) == ' '
+ || (i == source.length() - 2
+ && source.charAt(i - 1) == 'O' && source
+ .charAt(i + 1) == 'E')) {
+ System.out.println("****** EXCEPTION " + source);
+ result.append(ch);
+ }
+ // otherwise don't copy
+ } else {
+ throw new IllegalArgumentException("Illegal Name Char: U+"
+ + Utility.hex(ch) + ", " + ch);
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * These routines use the Java functions, because they only need to act on
+ * ASCII Changes space, - into _, inserts _ between lower and UPPER.
+ */
+ public static String regularize(String source, boolean titlecaseStart) {
+ if (source == null)
+ return source;
+ /*
+ * if (source.equals("noBreak")) { // HACK if (titlecaseStart) return
+ * "NoBreak"; return source; }
+ */
+ StringBuffer result = new StringBuffer();
+ int lastCat = -1;
+ boolean haveFirstCased = true;
+ for (int i = 0; i < source.length(); ++i) {
+ char c = source.charAt(i);
+ if (c == ' ' || c == '-' || c == '_') {
+ c = '_';
+ haveFirstCased = true;
+ }
+ if (c == '=')
+ haveFirstCased = true;
+ int cat = Character.getType(c);
+ if (lastCat == Character.LOWERCASE_LETTER
+ && cat == Character.UPPERCASE_LETTER) {
+ result.append('_');
+ }
+ if (haveFirstCased
+ && (cat == Character.LOWERCASE_LETTER
+ || cat == Character.TITLECASE_LETTER || cat == Character.UPPERCASE_LETTER)) {
+ if (titlecaseStart) {
+ c = Character.toUpperCase(c);
+ }
+ haveFirstCased = false;
+ }
+ result.append(c);
+ lastCat = cat;
+ }
+ return result.toString();
+ }
+
+ /**
+ * Utility function for comparing codepoint to string without generating new
+ * string.
+ *
+ * @param codepoint
+ * @param other
+ * @return true if the codepoint equals the string
+ */
+ public static final boolean equals(int codepoint, String other) {
+ if (other.length() == 1) {
+ return codepoint == other.charAt(0);
+ }
+ if (other.length() == 2) {
+ return other.equals(UTF16.valueOf(codepoint));
+ }
+ return false;
+ }
+
+ /**
+ * Utility that should be on UnicodeSet
+ *
+ * @param source
+ * @param result
+ */
+ static public void addAll(UnicodeSetIterator source, UnicodeSet result) {
+ while (source.nextRange()) {
+ if (source.codepoint == UnicodeSetIterator.IS_STRING) {
+ result.add(source.string);
+ } else {
+ result.add(source.codepoint, source.codepointEnd);
+ }
+ }
+ }
+
+ /**
+ * Really ought to create a Collection UniqueList, that forces uniqueness.
+ * But for now...
+ */
+ public static Collection addAllUnique(Collection source, Collection result) {
+ for (Iterator it = source.iterator(); it.hasNext();) {
+ addUnique(it.next(), result);
+ }
+ return result;
+ }
+
+ /**
+ * Really ought to create a Collection UniqueList, that forces uniqueness.
+ * But for now...
+ */
+ public static Collection addAllUnique(Object[] source, Collection result) {
+ for (int i = 0; i < source.length; ++i) {
+ addUnique(source[i], result);
+ }
+ return result;
+ }
+
+ static public class Factory {
+ static boolean DEBUG = false;
+
+ Map canonicalNames = new TreeMap();
+
+ Map skeletonNames = new TreeMap();
+
+ Map propertyCache = new HashMap(1);
+
+ public final Factory add(UnicodeProperty sp) {
+ canonicalNames.put(sp.getName(), sp);
+ List c = sp.getNameAliases(new ArrayList(1));
+ Iterator it = c.iterator();
+ while (it.hasNext()) {
+ skeletonNames.put(toSkeleton((String) it.next()), sp);
+ }
+ return this;
+ }
+
+ public final UnicodeProperty getProperty(String propertyAlias) {
+ return (UnicodeProperty) skeletonNames
+ .get(toSkeleton(propertyAlias));
+ }
+
+ public final List getAvailableNames() {
+ return getAvailableNames(null);
+ }
+
+ public final List getAvailableNames(List result) {
+ if (result == null)
+ result = new ArrayList(1);
+ Iterator it = canonicalNames.keySet().iterator();
+ while (it.hasNext()) {
+ addUnique(it.next(), result);
+ }
+ return result;
+ }
+
+ public final List getAvailableNames(int propertyTypeMask) {
+ return getAvailableNames(propertyTypeMask, null);
+ }
+
+ public final List getAvailableNames(int propertyTypeMask, List result) {
+ if (result == null)
+ result = new ArrayList(1);
+ Iterator it = canonicalNames.keySet().iterator();
+ while (it.hasNext()) {
+ String item = (String) it.next();
+ UnicodeProperty property = getProperty(item);
+ if (DEBUG)
+ System.out.println("Properties: " + item + ","
+ + property.getType());
+ if (!property.isType(propertyTypeMask)) {
+ // System.out.println("Masking: " + property.getType() + ","
+ // + propertyTypeMask);
+ continue;
+ }
+ addUnique(property.getName(), result);
+ }
+ return result;
+ }
+
+ InversePatternMatcher inverseMatcher = new InversePatternMatcher();
+
+ /**
+ * Format is: propname ('=' | '!=') propvalue ( '|' propValue )*
+ */
+ public final UnicodeSet getSet(String propAndValue,
+ PatternMatcher matcher, UnicodeSet result) {
+ int equalPos = propAndValue.indexOf('=');
+ String prop = propAndValue.substring(0, equalPos);
+ String value = propAndValue.substring(equalPos + 1);
+ boolean negative = false;
+ if (prop.endsWith("!")) {
+ prop = prop.substring(0, prop.length() - 1);
+ negative = true;
+ }
+ prop = prop.trim();
+ UnicodeProperty up = getProperty(prop);
+ if (matcher == null) {
+ matcher = new SimpleMatcher(value, up
+ .isType(STRING_OR_MISC_MASK) ? null
+ : PROPERTY_COMPARATOR);
+ }
+ if (negative) {
+ inverseMatcher.set(matcher);
+ matcher = inverseMatcher;
+ }
+ return up.getSet(matcher.set(value), result);
+ }
+
+ public final UnicodeSet getSet(String propAndValue,
+ PatternMatcher matcher) {
+ return getSet(propAndValue, matcher, null);
+ }
+
+ public final UnicodeSet getSet(String propAndValue) {
+ return getSet(propAndValue, null, null);
+ }
+
+ public final SymbolTable getSymbolTable(String prefix) {
+ return new PropertySymbolTable(prefix);
+ }
+
+ private class MyXSymbolTable extends UnicodeSet.XSymbolTable {
+ public boolean applyPropertyAlias(String propertyName,
+ String propertyValue, UnicodeSet result) {
+ if (false)
+ System.out.println(propertyName + "=" + propertyValue);
+ UnicodeProperty prop = getProperty(propertyName);
+ if (prop == null)
+ return false;
+ result.clear();
+ UnicodeSet x = prop.getSet(propertyValue, result);
+ return x.size() != 0;
+ }
+ }
+
+ public final UnicodeSet.XSymbolTable getXSymbolTable() {
+ return new MyXSymbolTable();
+ }
+
+ private class PropertySymbolTable implements SymbolTable {
+ static final boolean DEBUG = false;
+
+ private String prefix;
+
+ RegexMatcher regexMatcher = new RegexMatcher();
+
+ PropertySymbolTable(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public char[] lookup(String s) {
+ if (DEBUG)
+ System.out.println("\t(" + prefix + ")Looking up " + s);
+ // ensure, again, that prefix matches
+ int start = prefix.length();
+ if (!s.regionMatches(true, 0, prefix, 0, start))
+ return null;
+
+ int pos = s.indexOf(':', start);
+ if (pos < 0) { // should never happen
+ throw new IllegalArgumentException(
+ "Internal Error: missing =: " + s + "\r\n");
+ }
+ UnicodeProperty prop = getProperty(s.substring(start, pos));
+ if (prop == null) {
+ throw new IllegalArgumentException("Invalid Property in: "
+ + s + "\r\nUse " + showSet(getAvailableNames()));
+ }
+ String value = s.substring(pos + 1);
+ UnicodeSet set;
+ if (value.startsWith("\u00AB")) { // regex!
+ set = prop.getSet(regexMatcher.set(value.substring(1, value
+ .length() - 1)));
+ } else {
+ set = prop.getSet(value);
+ }
+ if (set.size() == 0) {
+ throw new IllegalArgumentException(
+ "Empty Property-Value in: " + s + "\r\nUse "
+ + showSet(prop.getAvailableValues()));
+ }
+ if (DEBUG)
+ System.out.println("\t(" + prefix + ")Returning "
+ + set.toPattern(true));
+ return set.toPattern(true).toCharArray(); // really ugly
+ }
+
+ private String showSet(List list) {
+ StringBuffer result = new StringBuffer("[");
+ boolean first = true;
+ for (Iterator it = list.iterator(); it.hasNext();) {
+ if (!first)
+ result.append(", ");
+ else
+ first = false;
+ result.append(it.next().toString());
+ }
+ result.append("]");
+ return result.toString();
+ }
+
+ public UnicodeMatcher lookupMatcher(int ch) {
+ return null;
+ }
+
+ public String parseReference(String text, ParsePosition pos,
+ int limit) {
+ if (DEBUG)
+ System.out.println("\t(" + prefix + ")Parsing <"
+ + text.substring(pos.getIndex(), limit) + ">");
+ int start = pos.getIndex();
+ // ensure that it starts with 'prefix'
+ if (!text
+ .regionMatches(true, start, prefix, 0, prefix.length()))
+ return null;
+ start += prefix.length();
+ // now see if it is of the form identifier:identifier
+ int i = getIdentifier(text, start, limit);
+ if (i == start)
+ return null;
+ String prop = text.substring(start, i);
+ String value = "true";
+ if (i < limit) {
+ if (text.charAt(i) == ':') {
+ int j;
+ if (text.charAt(i + 1) == '\u00AB') { // regular
+ // expression
+ j = text.indexOf('\u00BB', i + 2) + 1; // include
+ // last
+ // character
+ if (j <= 0)
+ return null;
+ } else {
+ j = getIdentifier(text, i + 1, limit);
+ }
+ value = text.substring(i + 1, j);
+ i = j;
+ }
+ }
+ pos.setIndex(i);
+ if (DEBUG)
+ System.out.println("\t(" + prefix + ")Parsed <" + prop
+ + ">=<" + value + ">");
+ return prefix + prop + ":" + value;
+ }
+
+ private int getIdentifier(String text, int start, int limit) {
+ if (DEBUG)
+ System.out.println("\tGetID <"
+ + text.substring(start, limit) + ">");
+ int cp = 0;
+ int i;
+ for (i = start; i < limit; i += UTF16.getCharCount(cp)) {
+ cp = UTF16.charAt(text, i);
+ if (!com.ibm.icu.lang.UCharacter
+ .isUnicodeIdentifierPart(cp)
+ && cp != '.') {
+ break;
+ }
+ }
+ if (DEBUG)
+ System.out.println("\tGotID <" + text.substring(start, i)
+ + ">");
+ return i;
+ }
+ }
+ }
+
+ public static class FilteredProperty extends UnicodeProperty {
+ private UnicodeProperty property;
+
+ protected StringFilter filter;
+
+ protected UnicodeSetIterator matchIterator = new UnicodeSetIterator(
+ new UnicodeSet(0, 0x10FFFF));
+
+ protected HashMap backmap;
+
+ boolean allowValueAliasCollisions = false;
+
+ public FilteredProperty(UnicodeProperty property, StringFilter filter) {
+ this.property = property;
+ this.filter = filter;
+ }
+
+ public StringFilter getFilter() {
+ return filter;
+ }
+
+ public UnicodeProperty setFilter(StringFilter filter) {
+ this.filter = filter;
+ return this;
+ }
+
+ List temp = new ArrayList(1);
+
+ public List _getAvailableValues(List result) {
+ temp.clear();
+ return filter.addUnique(property.getAvailableValues(temp), result);
+ }
+
+ public List _getNameAliases(List result) {
+ temp.clear();
+ return filter.addUnique(property.getNameAliases(temp), result);
+ }
+
+ public String _getValue(int codepoint) {
+ return filter.remap(property.getValue(codepoint));
+ }
+
+ public List _getValueAliases(String valueAlias, List result) {
+ if (backmap == null) {
+ backmap = new HashMap(1);
+ temp.clear();
+ Iterator it = property.getAvailableValues(temp).iterator();
+ while (it.hasNext()) {
+ String item = (String) it.next();
+ String mappedItem = filter.remap(item);
+ if (backmap.get(mappedItem) != null
+ && !allowValueAliasCollisions) {
+ throw new IllegalArgumentException(
+ "Filter makes values collide! " + item + ", "
+ + mappedItem);
+ }
+ backmap.put(mappedItem, item);
+ }
+ }
+ valueAlias = (String) backmap.get(valueAlias);
+ temp.clear();
+ return filter.addUnique(property.getValueAliases(valueAlias, temp),
+ result);
+ }
+
+ public String _getVersion() {
+ return property.getVersion();
+ }
+
+ public boolean isAllowValueAliasCollisions() {
+ return allowValueAliasCollisions;
+ }
+
+ public FilteredProperty setAllowValueAliasCollisions(boolean b) {
+ allowValueAliasCollisions = b;
+ return this;
+ }
+
+ }
+
+ public static abstract class StringFilter implements Cloneable {
+ public abstract String remap(String original);
+
+ public final List addUnique(Collection source, List result) {
+ if (result == null)
+ result = new ArrayList(1);
+ Iterator it = source.iterator();
+ while (it.hasNext()) {
+ UnicodeProperty.addUnique(remap((String) it.next()), result);
+ }
+ return result;
+ }
+ /*
+ * public Object clone() { try { return super.clone(); } catch
+ * (CloneNotSupportedException e) { throw new
+ * IllegalStateException("Should never happen."); } }
+ */
+ }
+
+ public static class MapFilter extends StringFilter {
+ private Map valueMap;
+
+ public MapFilter(Map valueMap) {
+ this.valueMap = valueMap;
+ }
+
+ public String remap(String original) {
+ Object changed = valueMap.get(original);
+ return changed == null ? original : (String) changed;
+ }
+
+ public Map getMap() {
+ return valueMap;
+ }
+ }
+
+ public interface PatternMatcher extends ObjectMatcher {
+ public PatternMatcher set(String pattern);
+ }
+
+ public static class InversePatternMatcher extends InverseMatcher implements
+ PatternMatcher {
+ PatternMatcher other;
+
+ public PatternMatcher set(PatternMatcher toInverse) {
+ other = toInverse;
+ return this;
+ }
+
+ public boolean matches(Object value) {
+ return !other.matches(value);
+ }
+
+ public PatternMatcher set(String pattern) {
+ other.set(pattern);
+ return this;
+ }
+ }
+
+ public static class SimpleMatcher implements PatternMatcher {
+ Comparator comparator;
+
+ String pattern;
+
+ public SimpleMatcher(String pattern, Comparator comparator) {
+ this.comparator = comparator;
+ this.pattern = pattern;
+ }
+
+ public boolean matches(Object value) {
+ if (comparator == null)
+ return pattern.equals(value);
+ return comparator.compare(pattern, value) == 0;
+ }
+
+ public PatternMatcher set(String pattern) {
+ this.pattern = pattern;
+ return this;
+ }
+ }
+
+ public static class RegexMatcher implements UnicodeProperty.PatternMatcher {
+ private java.util.regex.Matcher matcher;
+
+ public UnicodeProperty.PatternMatcher set(String pattern) {
+ matcher = Pattern.compile(pattern).matcher("");
+ return this;
+ }
+
+ public boolean matches(Object value) {
+ matcher.reset(value.toString());
+ return matcher.matches();
+ }
+ }
+
+ public static abstract class BaseProperty extends UnicodeProperty {
+ protected List propertyAliases = new ArrayList(1);
+
+ protected Map toValueAliases;
+
+ protected String version;
+
+ public BaseProperty setMain(String alias, String shortAlias,
+ int propertyType, String version) {
+ setName(alias);
+ setType(propertyType);
+ propertyAliases.add(shortAlias);
+ propertyAliases.add(alias);
+ this.version = version;
+ return this;
+ }
+
+ public String _getVersion() {
+ return version;
+ }
+
+ public List _getNameAliases(List result) {
+ addAllUnique(propertyAliases, result);
+ return result;
+ }
+
+ public BaseProperty addValueAliases(String[][] valueAndAlternates,
+ boolean errorIfCant) {
+ if (toValueAliases == null)
+ _fixValueAliases();
+ for (int i = 0; i < valueAndAlternates.length; ++i) {
+ for (int j = 1; j < valueAndAlternates[0].length; ++j) {
+ addValueAlias(valueAndAlternates[i][0],
+ valueAndAlternates[i][j], errorIfCant);
+ }
+ }
+ return this;
+ }
+
+ public void addValueAlias(String value, String valueAlias,
+ boolean errorIfCant) {
+ List result = (List) toValueAliases.get(value);
+ if (result == null && !errorIfCant)
+ return;
+ addUnique(value, result);
+ addUnique(valueAlias, result);
+ }
+
+ protected List _getValueAliases(String valueAlias, List result) {
+ if (toValueAliases == null)
+ _fixValueAliases();
+ List a = (List) toValueAliases.get(valueAlias);
+ if (a != null)
+ addAllUnique(a, result);
+ return result;
+ }
+
+ protected void _fixValueAliases() {
+ if (toValueAliases == null)
+ toValueAliases = new HashMap(1);
+ for (Iterator it = getAvailableValues().iterator(); it.hasNext();) {
+ Object value = it.next();
+ _ensureValueInAliases(value);
+ }
+ }
+
+ protected void _ensureValueInAliases(Object value) {
+ List result = (List) toValueAliases.get(value);
+ if (result == null)
+ toValueAliases.put(value, result = new ArrayList(1));
+ addUnique(value, result);
+ }
+
+ public BaseProperty swapFirst2ValueAliases() {
+ for (Iterator it = toValueAliases.keySet().iterator(); it.hasNext();) {
+ List list = (List) toValueAliases.get(it.next());
+ if (list.size() < 2)
+ continue;
+ Object first = list.get(0);
+ list.set(0, list.get(1));
+ list.set(1, first);
+ }
+ return this;
+ }
+
+ /**
+ * @param string
+ * @return
+ */
+ public UnicodeProperty addName(String string) {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ public static abstract class SimpleProperty extends BaseProperty {
+ List values;
+
+ public UnicodeProperty addName(String alias) {
+ propertyAliases.add(alias);
+ return this;
+ }
+
+ public SimpleProperty setValues(String valueAlias) {
+ _addToValues(valueAlias, null);
+ return this;
+ }
+
+ public SimpleProperty setValues(String[] valueAliases,
+ String[] alternateValueAliases) {
+ for (int i = 0; i < valueAliases.length; ++i) {
+ if (valueAliases[i].equals(UNUSED))
+ continue;
+ _addToValues(
+ valueAliases[i],
+ alternateValueAliases != null ? alternateValueAliases[i]
+ : null);
+ }
+ return this;
+ }
+
+ public SimpleProperty setValues(List valueAliases) {
+ this.values = new ArrayList(valueAliases);
+ for (Iterator it = this.values.iterator(); it.hasNext();) {
+ _addToValues((String) it.next(), null);
+ }
+ return this;
+ }
+
+ public List _getAvailableValues(List result) {
+ if (values == null)
+ _fillValues();
+ result.addAll(values);
+ return result;
+ }
+
+ protected void _fillValues() {
+ List newvalues = (List) getUnicodeMap_internal()
+ .getAvailableValues(new ArrayList());
+ for (Iterator it = newvalues.iterator(); it.hasNext();) {
+ _addToValues((String) it.next(), null);
+ }
+ }
+
+ private void _addToValues(String item, String alias) {
+ if (values == null)
+ values = new ArrayList(1);
+ if (toValueAliases == null)
+ _fixValueAliases();
+ addUnique(item, values);
+ _ensureValueInAliases(item);
+ addValueAlias(item, alias, true);
+ }
+ /* public String _getVersion() {
+ return version;
+ }
+ */
+ }
+
+ public static class UnicodeMapProperty extends BaseProperty {
+ /*
+ * Example of usage:
+ * new UnicodeProperty.UnicodeMapProperty() {
+ {
+ unicodeMap = new UnicodeMap();
+ unicodeMap.setErrorOnReset(true);
+ unicodeMap.put(0xD, "CR");
+ unicodeMap.put(0xA, "LF");
+ UnicodeProperty cat = getProperty("General_Category");
+ UnicodeSet temp = cat.getSet("Line_Separator")
+ .addAll(cat.getSet("Paragraph_Separator"))
+ .addAll(cat.getSet("Control"))
+ .addAll(cat.getSet("Format"))
+ .remove(0xD).remove(0xA).remove(0x200C).remove(0x200D);
+ unicodeMap.putAll(temp, "Control");
+ UnicodeSet graphemeExtend = getProperty("Grapheme_Extend").getSet("true");
+ unicodeMap.putAll(graphemeExtend,"Extend");
+ UnicodeProperty hangul = getProperty("Hangul_Syllable_Type");
+ unicodeMap.putAll(hangul.getSet("L"),"L");
+ unicodeMap.putAll(hangul.getSet("V"),"V");
+ unicodeMap.putAll(hangul.getSet("T"),"T");
+ unicodeMap.putAll(hangul.getSet("LV"),"LV");
+ unicodeMap.putAll(hangul.getSet("LVT"),"LVT");
+ unicodeMap.setMissing("Other");
+ }
+ }.setMain("Grapheme_Cluster_Break", "GCB", UnicodeProperty.ENUMERATED, version)
+ */
+ protected UnicodeMap unicodeMap;
+
+ public UnicodeMapProperty set(UnicodeMap map) {
+ unicodeMap = map;
+ return this;
+ }
+
+ protected String _getValue(int codepoint) {
+ return (String) unicodeMap.getValue(codepoint);
+ }
+
+ /* protected List _getValueAliases(String valueAlias, List result) {
+ if (!unicodeMap.getAvailableValues().contains(valueAlias)) return result;
+ result.add(valueAlias);
+ return result; // no other aliases
+ }
+ */protected List _getAvailableValues(List result) {
+ return (List) unicodeMap.getAvailableValues(result);
+ }
+ }
+}
+//#endif
+