diff --git a/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/ICUPropertyFactory.java b/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/ICUPropertyFactory.java index 71fca565935..405a481d676 100644 --- a/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/ICUPropertyFactory.java +++ b/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/ICUPropertyFactory.java @@ -10,6 +10,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -17,6 +18,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; +import com.ibm.icu.dev.test.util.UnicodeMap; import com.ibm.icu.lang.UCharacter; import com.ibm.icu.lang.UProperty; import com.ibm.icu.text.Normalizer; @@ -31,276 +33,313 @@ import com.ibm.icu.util.VersionInfo; */ public class ICUPropertyFactory extends UnicodeProperty.Factory { - - static class ICUProperty extends UnicodeProperty { - protected int propEnum = Integer.MIN_VALUE; - - protected ICUProperty(String propName, int propEnum) { - setName(propName); - this.propEnum = propEnum; - setType(internalGetPropertyType(propEnum)); - } - boolean shownException = false; - - public String _getValue(int codePoint) { - switch(propEnum) { - case UProperty.AGE: return getAge(codePoint); - case UProperty.BIDI_MIRRORING_GLYPH: return UTF16.valueOf(UCharacter.getMirror(codePoint)); - case UProperty.CASE_FOLDING: return UCharacter.foldCase(UTF16.valueOf(codePoint),true); - case UProperty.ISO_COMMENT: return UCharacter.getISOComment(codePoint); - case UProperty.LOWERCASE_MAPPING: return UCharacter.toLowerCase(Locale.ENGLISH,UTF16.valueOf(codePoint)); - case UProperty.NAME: return UCharacter.getName(codePoint); - case UProperty.SIMPLE_CASE_FOLDING: return UTF16.valueOf(UCharacter.foldCase(codePoint,true)); - case UProperty.SIMPLE_LOWERCASE_MAPPING: return UTF16.valueOf(UCharacter.toLowerCase(codePoint)); - case UProperty.SIMPLE_TITLECASE_MAPPING: return UTF16.valueOf(UCharacter.toTitleCase(codePoint)); - case UProperty.SIMPLE_UPPERCASE_MAPPING: return UTF16.valueOf(UCharacter.toUpperCase(codePoint)); - case UProperty.TITLECASE_MAPPING: return UCharacter.toTitleCase(Locale.ENGLISH,UTF16.valueOf(codePoint),null); - case UProperty.UNICODE_1_NAME: return UCharacter.getName1_0(codePoint); - case UProperty.UPPERCASE_MAPPING: return UCharacter.toUpperCase(Locale.ENGLISH,UTF16.valueOf(codePoint)); - case NFC: return Normalizer.normalize(codePoint, Normalizer.NFC); - case NFD: return Normalizer.normalize(codePoint, Normalizer.NFD); - case NFKC: return Normalizer.normalize(codePoint, Normalizer.NFKC); - case NFKD: return Normalizer.normalize(codePoint, Normalizer.NFKD); - case isNFC: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFC).equals(UTF16.valueOf(codePoint))); - case isNFD: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFD).equals(UTF16.valueOf(codePoint))); - case isNFKC: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFKC).equals(UTF16.valueOf(codePoint))); - case isNFKD: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFKD).equals(UTF16.valueOf(codePoint))); - case isLowercase: return String.valueOf(UCharacter.toLowerCase(Locale.ENGLISH,UTF16.valueOf(codePoint)).equals(UTF16.valueOf(codePoint))); - case isUppercase: return String.valueOf(UCharacter.toUpperCase(Locale.ENGLISH,UTF16.valueOf(codePoint)).equals(UTF16.valueOf(codePoint))); - case isTitlecase: return String.valueOf(UCharacter.toTitleCase(Locale.ENGLISH,UTF16.valueOf(codePoint),null).equals(UTF16.valueOf(codePoint))); - case isCasefolded: return String.valueOf(UCharacter.foldCase(UTF16.valueOf(codePoint),true).equals(UTF16.valueOf(codePoint))); - case isCased: return String.valueOf(UCharacter.toLowerCase(Locale.ENGLISH,UTF16.valueOf(codePoint)).equals(UTF16.valueOf(codePoint))); - } - if (propEnum < UProperty.INT_LIMIT) { - int enumValue = -1; - String value = null; - try { - enumValue = UCharacter.getIntPropertyValue(codePoint, propEnum); - if (enumValue >= 0) value = fixedGetPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG); - } catch (IllegalArgumentException e) { - if (!shownException) { - System.out.println("Fail: " + getName() + ", " + Integer.toHexString(codePoint)); - shownException = true; - } - } - return value != null ? value : String.valueOf(enumValue); - } else if (propEnum < UProperty.DOUBLE_LIMIT) { - double num = UCharacter.getUnicodeNumericValue(codePoint); - if (num == UCharacter.NO_NUMERIC_VALUE) return null; - return Double.toString(num); - // TODO: Fix HACK -- API deficient - } - return null; - } + static class ICUProperty extends UnicodeProperty { + protected int propEnum = Integer.MIN_VALUE; - private String getAge(int codePoint) { - String temp = UCharacter.getAge(codePoint).toString(); - if (temp.equals("0.0.0.0")) return "unassigned"; - if (temp.endsWith(".0.0")) return temp.substring(0,temp.length()-4); - return temp; - } + protected ICUProperty(String propName, int propEnum) { + setName(propName); + this.propEnum = propEnum; + setType(internalGetPropertyType(propEnum)); + if (propEnum == UProperty.DEFAULT_IGNORABLE_CODE_POINT || propEnum == UProperty.BIDI_CLASS) { + setUniformUnassigned(false); + } + } - /** - * @param valueAlias null if unused. - * @param valueEnum -1 if unused - * @param nameChoice - * @return - */ - private String getFixedValueAlias(String valueAlias, int valueEnum, int nameChoice) { - if (propEnum >= UProperty.STRING_START) { - if (nameChoice != UProperty.NameChoice.LONG) return null; - return ""; - } else if (propEnum >= UProperty.DOUBLE_START) { - if (nameChoice != UProperty.NameChoice.LONG) return null; - return ""; - } - if (valueAlias != null && !valueAlias.equals("")) { - valueEnum = fixedGetPropertyValueEnum(propEnum,valueAlias); - } - // because these are defined badly, there may be no normal (long) name. - // if there is - String result = fixedGetPropertyValueName(propEnum, valueEnum, nameChoice); - if (result != null) return result; - // HACK try other namechoice - if (nameChoice == UProperty.NameChoice.LONG) { - result = fixedGetPropertyValueName(propEnum,valueEnum, UProperty.NameChoice.SHORT); - if (result != null) return result; - if (propEnum == UProperty.CANONICAL_COMBINING_CLASS) return null; - return ""; - } - return null; - } + boolean shownException = false; - private static int fixedGetPropertyValueEnum(int propEnum, String valueAlias) { - try { - if (propEnum < BINARY_LIMIT) { - propEnum = UProperty.ALPHABETIC; - } - return UCharacter.getPropertyValueEnum(propEnum, valueAlias); - } catch (Exception e) { - return Integer.parseInt(valueAlias); - } - } - - static Map fixSkeleton = new HashMap(); - private static String fixedGetPropertyValueName(int propEnum, int valueEnum, int nameChoice) { - - try { - String value = UCharacter.getPropertyValueName(propEnum,valueEnum,nameChoice); - String newValue = (String) fixSkeleton.get(value); - if (newValue == null) { - newValue = value; - if (propEnum == UProperty.JOINING_GROUP) { - newValue = newValue.toLowerCase(Locale.ENGLISH); - } - newValue = regularize(newValue, true); - fixSkeleton.put(value, newValue); - } - return newValue; - } catch (Exception e) { - return null; - } - } - - public List _getNameAliases(List result) { - if (result == null) result = new ArrayList(); - String alias = String_Extras.get(propEnum); - if (alias == null) alias = Binary_Extras.get(propEnum); - if (alias != null) { - addUnique(alias, result); - } else { - addUnique(getFixedPropertyName(propEnum, UProperty.NameChoice.SHORT), result); - addUnique(getFixedPropertyName(propEnum, UProperty.NameChoice.LONG), result); - } - return result; - } - - public String getFixedPropertyName(int propName, int nameChoice) { - try { - return UCharacter.getPropertyName(propEnum, nameChoice); - } catch (IllegalArgumentException e) { - return null; - } - } - - private Map cccHack = new HashMap(); - boolean needCccHack = true; - - public List _getAvailableValues(List result) { - if (result == null) result = new ArrayList(); - if (propEnum == UProperty.AGE) { - addAllUnique(getAges(), result); - return result; - } - if (propEnum < UProperty.INT_LIMIT) { - if (Binary_Extras.isInRange(propEnum)) { - propEnum = UProperty.BINARY_START; // HACK - } - int start = UCharacter.getIntPropertyMinValue(propEnum); - int end = UCharacter.getIntPropertyMaxValue(propEnum); - for (int i = start; i <= end; ++i) { - String alias = getFixedValueAlias(null, i, UProperty.NameChoice.LONG); - String alias2 = getFixedValueAlias(null, i, UProperty.NameChoice.SHORT); - if (alias == null) { - alias = alias2; - if (alias == null && propEnum == UProperty.CANONICAL_COMBINING_CLASS) { - alias = String.valueOf(i); - } - } - if (needCccHack && propEnum == UProperty.CANONICAL_COMBINING_CLASS) { // HACK - cccHack.put(alias, String.valueOf(i)); - } - //System.out.println(propertyAlias + "\t" + i + ":\t" + alias); - addUnique(alias, result); - } - needCccHack = false; - } else { - String alias = getFixedValueAlias(null, -1,UProperty.NameChoice.LONG); - addUnique(alias, result); - } - return result; - } - - static String[] AGES = null; - private String[] getAges() { - if (AGES == null) { - Set ages = new TreeSet(); - for (int i = 0; i < 0x10FFFF; ++i) { - ages.add(getAge(i)); - } - AGES = (String[]) ages.toArray(new String[ages.size()]); - } - return AGES; - } - - public List _getValueAliases(String valueAlias, List result) { - if (result == null) result = new ArrayList(); - if (propEnum == UProperty.AGE) { - addUnique(valueAlias, result); - return result; - } - if (propEnum == UProperty.CANONICAL_COMBINING_CLASS) { - addUnique(cccHack.get(valueAlias), result); // add number - } - addUnique(getFixedValueAlias(valueAlias, -1, UProperty.NameChoice.SHORT), result); - addUnique(getFixedValueAlias(valueAlias, -1, UProperty.NameChoice.LONG), result); - return result; - } - - - /* (non-Javadoc) - * @see com.ibm.icu.dev.test.util.UnicodePropertySource#getPropertyType() - */ - private int internalGetPropertyType(int prop) { - switch(prop) { - case UProperty.AGE: - case UProperty.BLOCK: - case UProperty.SCRIPT: - return UnicodeProperty.CATALOG; - case UProperty.ISO_COMMENT: - case UProperty.NAME: - case UProperty.UNICODE_1_NAME: - return UnicodeProperty.MISC; - case UProperty.BIDI_MIRRORING_GLYPH: - case UProperty.CASE_FOLDING: - case UProperty.LOWERCASE_MAPPING: - case UProperty.SIMPLE_CASE_FOLDING: - case UProperty.SIMPLE_LOWERCASE_MAPPING: - case UProperty.SIMPLE_TITLECASE_MAPPING: - case UProperty.SIMPLE_UPPERCASE_MAPPING: - case UProperty.TITLECASE_MAPPING: - case UProperty.UPPERCASE_MAPPING: - return UnicodeProperty.EXTENDED_STRING; - } - if (prop < UProperty.BINARY_START) return UnicodeProperty.UNKNOWN; - if (prop < UProperty.BINARY_LIMIT) return UnicodeProperty.BINARY; - if (prop < UProperty.INT_START) return UnicodeProperty.EXTENDED_BINARY; - if (prop < UProperty.INT_LIMIT) return UnicodeProperty.ENUMERATED; - if (prop < UProperty.DOUBLE_START) return UnicodeProperty.EXTENDED_ENUMERATED; - if (prop < UProperty.DOUBLE_LIMIT) return UnicodeProperty.NUMERIC; - if (prop < UProperty.STRING_START) return UnicodeProperty.EXTENDED_NUMERIC; - if (prop < UProperty.STRING_LIMIT) return UnicodeProperty.STRING; - return UnicodeProperty.EXTENDED_STRING; - } - - /* (non-Javadoc) - * @see com.ibm.icu.dev.test.util.UnicodeProperty#getVersion() - */ - public String _getVersion() { - return VersionInfo.ICU_VERSION.toString(); - } + public String _getValue(int codePoint) { + switch(propEnum) { + case UProperty.AGE: return getAge(codePoint); + case UProperty.BIDI_MIRRORING_GLYPH: return UTF16.valueOf(UCharacter.getMirror(codePoint)); + case UProperty.CASE_FOLDING: return UCharacter.foldCase(UTF16.valueOf(codePoint),true); + case UProperty.ISO_COMMENT: return UCharacter.getISOComment(codePoint); + case UProperty.LOWERCASE_MAPPING: return UCharacter.toLowerCase(Locale.ENGLISH,UTF16.valueOf(codePoint)); + case UProperty.NAME: return UCharacter.getName(codePoint); + case UProperty.SIMPLE_CASE_FOLDING: return UTF16.valueOf(UCharacter.foldCase(codePoint,true)); + case UProperty.SIMPLE_LOWERCASE_MAPPING: return UTF16.valueOf(UCharacter.toLowerCase(codePoint)); + case UProperty.SIMPLE_TITLECASE_MAPPING: return UTF16.valueOf(UCharacter.toTitleCase(codePoint)); + case UProperty.SIMPLE_UPPERCASE_MAPPING: return UTF16.valueOf(UCharacter.toUpperCase(codePoint)); + case UProperty.TITLECASE_MAPPING: return UCharacter.toTitleCase(Locale.ENGLISH,UTF16.valueOf(codePoint),null); + case UProperty.UNICODE_1_NAME: return UCharacter.getName1_0(codePoint); + case UProperty.UPPERCASE_MAPPING: return UCharacter.toUpperCase(Locale.ENGLISH,UTF16.valueOf(codePoint)); +// case NFC: return Normalizer.normalize(codePoint, Normalizer.NFC); +// case NFD: return Normalizer.normalize(codePoint, Normalizer.NFD); +// case NFKC: return Normalizer.normalize(codePoint, Normalizer.NFKC); +// case NFKD: return Normalizer.normalize(codePoint, Normalizer.NFKD); + case isNFC: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFC).equals(UTF16.valueOf(codePoint))); + case isNFD: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFD).equals(UTF16.valueOf(codePoint))); + case isNFKC: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFKC).equals(UTF16.valueOf(codePoint))); + case isNFKD: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFKD).equals(UTF16.valueOf(codePoint))); + case isLowercase: return String.valueOf(UCharacter.toLowerCase(Locale.ENGLISH,UTF16.valueOf(codePoint)).equals(UTF16.valueOf(codePoint))); + case isUppercase: return String.valueOf(UCharacter.toUpperCase(Locale.ENGLISH,UTF16.valueOf(codePoint)).equals(UTF16.valueOf(codePoint))); + case isTitlecase: return String.valueOf(UCharacter.toTitleCase(Locale.ENGLISH,UTF16.valueOf(codePoint),null).equals(UTF16.valueOf(codePoint))); + case isCasefolded: return String.valueOf(UCharacter.foldCase(UTF16.valueOf(codePoint),true).equals(UTF16.valueOf(codePoint))); + case isCased: return String.valueOf(UCharacter.toLowerCase(Locale.ENGLISH,UTF16.valueOf(codePoint)).equals(UTF16.valueOf(codePoint))); + } + if (propEnum < UProperty.INT_LIMIT) { + int enumValue = -1; + String value = null; + try { + enumValue = UCharacter.getIntPropertyValue(codePoint, propEnum); + if (enumValue >= 0) value = fixedGetPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG); + } catch (IllegalArgumentException e) { + if (!shownException) { + System.out.println("Fail: " + getName() + ", " + Integer.toHexString(codePoint)); + shownException = true; + } } + return value != null ? value : String.valueOf(enumValue); + } else if (propEnum < UProperty.DOUBLE_LIMIT) { + double num = UCharacter.getUnicodeNumericValue(codePoint); + if (num == UCharacter.NO_NUMERIC_VALUE) return null; + return Double.toString(num); + // TODO: Fix HACK -- API deficient + } + return null; + } - /*{ + private String getAge(int codePoint) { + String temp = UCharacter.getAge(codePoint).toString(); + if (temp.equals("0.0.0.0")) return "unassigned"; + if (temp.endsWith(".0.0")) return temp.substring(0,temp.length()-4); + return temp; + } + + /** + * @param valueAlias null if unused. + * @param valueEnum -1 if unused + * @param nameChoice + * @return + */ + private String getFixedValueAlias(String valueAlias, int valueEnum, int nameChoice) { + if (propEnum >= UProperty.STRING_START) { + if (nameChoice > UProperty.NameChoice.LONG) throw new IllegalArgumentException(); + if (nameChoice != UProperty.NameChoice.LONG) return null; + return ""; + } else if (propEnum >= UProperty.DOUBLE_START) { + if (nameChoice > UProperty.NameChoice.LONG) throw new IllegalArgumentException(); + if (nameChoice != UProperty.NameChoice.LONG) return null; + return ""; + } + if (valueAlias != null && !valueAlias.equals("")) { + valueEnum = fixedGetPropertyValueEnum(propEnum,valueAlias); + } + // because these are defined badly, there may be no normal (long) name. + // if there is + String result = fixedGetPropertyValueName(propEnum, valueEnum, nameChoice); + if (result != null) return result; + // HACK try other namechoice + if (nameChoice == UProperty.NameChoice.LONG) { + result = fixedGetPropertyValueName(propEnum,valueEnum, UProperty.NameChoice.SHORT); + if (result != null) return result; + if (isCombiningClassProperty()) return null; + return ""; + } + return null; + } + + public boolean isCombiningClassProperty() { + return (propEnum == UProperty.CANONICAL_COMBINING_CLASS + || propEnum == UProperty.LEAD_CANONICAL_COMBINING_CLASS + || propEnum == UProperty.TRAIL_CANONICAL_COMBINING_CLASS + ); + } + + private static int fixedGetPropertyValueEnum(int propEnum, String valueAlias) { + try { + if (propEnum < BINARY_LIMIT) { + propEnum = UProperty.ALPHABETIC; + } + return UCharacter.getPropertyValueEnum(propEnum, valueAlias); + } catch (Exception e) { + return Integer.parseInt(valueAlias); + } + } + + static Map fixSkeleton = new HashMap(); + private static String fixedGetPropertyValueName(int propEnum, int valueEnum, int nameChoice) { + + String value = UCharacter.getPropertyValueName(propEnum,valueEnum,nameChoice); + String newValue = (String) fixSkeleton.get(value); + if (newValue == null) { + newValue = value; + if (propEnum == UProperty.JOINING_GROUP) { + newValue = newValue == null ? null : newValue.toLowerCase(Locale.ENGLISH); + } + newValue = regularize(newValue, true); + fixSkeleton.put(value, newValue); + } + return newValue; + } + + public List _getNameAliases(List result) { + if (result == null) result = new ArrayList(); +// String alias = String_Extras.get(propEnum); +// if (alias == null) + String alias = Binary_Extras.get(propEnum); + if (alias != null) { + addUnique(alias, result); + } else { + addUnique(getFixedPropertyName(propEnum, UProperty.NameChoice.SHORT), result); + addUnique(getFixedPropertyName(propEnum, UProperty.NameChoice.LONG), result); + } + return result; + } + + public String getFixedPropertyName(int propName, int nameChoice) { + try { + return UCharacter.getPropertyName(propEnum, nameChoice); + } catch (IllegalArgumentException e) { + return null; + } + } + + private static Map cccHack = new HashMap(); + private static Set cccExtras = new HashSet(); + static { + int start = UCharacter.getIntPropertyMinValue(UProperty.CANONICAL_COMBINING_CLASS); + int end = UCharacter.getIntPropertyMaxValue(UProperty.CANONICAL_COMBINING_CLASS); + for (int i = 0; i <= 255; ++i) { + String alias = UCharacter.getPropertyValueName(UProperty.CANONICAL_COMBINING_CLASS, i, UProperty.NameChoice.LONG); + String numStr = String.valueOf(i); + if (alias != null) { + cccHack.put(alias, numStr); + } else { + cccHack.put(numStr, numStr); + cccExtras.add(numStr); + } + } + } + + public List _getAvailableValues(List result) { + if (result == null) result = new ArrayList(); + if (propEnum == UProperty.AGE) { + addAllUnique(getAges(), result); + return result; + + } + if (propEnum < UProperty.INT_LIMIT) { + if (Binary_Extras.isInRange(propEnum)) { + propEnum = UProperty.BINARY_START; // HACK + } + int start = UCharacter.getIntPropertyMinValue(propEnum); + int end = UCharacter.getIntPropertyMaxValue(propEnum); + for (int i = start; i <= end; ++i) { + String alias = getFixedValueAlias(null, i, UProperty.NameChoice.LONG); + String alias2 = getFixedValueAlias(null, i, UProperty.NameChoice.SHORT); + if (alias == null) { + alias = alias2; + if (alias == null && isCombiningClassProperty()) { + alias = String.valueOf(i); + } + } + //System.out.println(propertyAlias + "\t" + i + ":\t" + alias); + addUnique(alias, result); + } + } else if (propEnum >= UProperty.DOUBLE_START && propEnum < UProperty.DOUBLE_LIMIT) { + UnicodeMap map = getUnicodeMap(); + Collection values = map.values(); + addAllUnique(values, result); + } else { + String alias = getFixedValueAlias(null, -1,UProperty.NameChoice.LONG); + addUnique(alias, result); + } + return result; + } + + static String[] AGES = null; + private String[] getAges() { + if (AGES == null) { + Set ages = new TreeSet(); + for (int i = 0; i < 0x10FFFF; ++i) { + ages.add(getAge(i)); + } + AGES = (String[]) ages.toArray(new String[ages.size()]); + } + return AGES; + } + + public List _getValueAliases(String valueAlias, List result) { + if (result == null) result = new ArrayList(); + if (propEnum == UProperty.AGE) { + addUnique(valueAlias, result); + return result; + } + if (isCombiningClassProperty()) { + addUnique(cccHack.get(valueAlias), result); // add number + } + int type = getType(); + if (type == UnicodeProperty.NUMERIC || type == EXTENDED_NUMERIC) { + addUnique(valueAlias, result); + if (valueAlias.endsWith(".0")) { + addUnique(valueAlias.substring(0, valueAlias.length() - 2), result); + } + } else { + for (int nameChoice = UProperty.NameChoice.SHORT; ; ++nameChoice) { + try { + addUnique(getFixedValueAlias(valueAlias, -1, nameChoice), result); + } catch (Exception e) { + break; + } + } + } + return result; + } + + + /* (non-Javadoc) + * @see com.ibm.icu.dev.test.util.UnicodePropertySource#getPropertyType() + */ + private int internalGetPropertyType(int prop) { + switch(prop) { + case UProperty.AGE: + case UProperty.BLOCK: + case UProperty.SCRIPT: + return UnicodeProperty.CATALOG; + case UProperty.ISO_COMMENT: + case UProperty.NAME: + case UProperty.UNICODE_1_NAME: + return UnicodeProperty.MISC; + case UProperty.BIDI_MIRRORING_GLYPH: + case UProperty.CASE_FOLDING: + case UProperty.LOWERCASE_MAPPING: + case UProperty.SIMPLE_CASE_FOLDING: + case UProperty.SIMPLE_LOWERCASE_MAPPING: + case UProperty.SIMPLE_TITLECASE_MAPPING: + case UProperty.SIMPLE_UPPERCASE_MAPPING: + case UProperty.TITLECASE_MAPPING: + case UProperty.UPPERCASE_MAPPING: + return UnicodeProperty.EXTENDED_STRING; + } + if (prop < UProperty.BINARY_START) return UnicodeProperty.UNKNOWN; + if (prop < UProperty.BINARY_LIMIT) return UnicodeProperty.BINARY; + if (prop < UProperty.INT_START) return UnicodeProperty.EXTENDED_BINARY; + if (prop < UProperty.INT_LIMIT) return UnicodeProperty.ENUMERATED; + if (prop < UProperty.DOUBLE_START) return UnicodeProperty.EXTENDED_ENUMERATED; + if (prop < UProperty.DOUBLE_LIMIT) return UnicodeProperty.NUMERIC; + if (prop < UProperty.STRING_START) return UnicodeProperty.EXTENDED_NUMERIC; + if (prop < UProperty.STRING_LIMIT) return UnicodeProperty.STRING; + return UnicodeProperty.EXTENDED_STRING; + } + + /* (non-Javadoc) + * @see com.ibm.icu.dev.test.util.UnicodeProperty#getVersion() + */ + public String _getVersion() { + return VersionInfo.ICU_VERSION.toString(); + } + } + + /*{ matchIterator = new UnicodeSetIterator( new UnicodeSet("[^[:Cn:]-[:Default_Ignorable_Code_Point:]]")); }*/ - - /* - * Other Missing Functions: + + /* + * Other Missing Functions: Expands_On_NFC Expands_On_NFD Expands_On_NFKC @@ -315,120 +354,120 @@ public class ICUPropertyFactory extends UnicodeProperty.Factory { NFKD_Quick_Check Special_Case_Condition Unicode_Radical_Stroke - */ - - static final Names Binary_Extras = new Names(UProperty.BINARY_LIMIT, - new String[] { - "isNFC", "isNFD", "isNFKC", "isNFKD", - "isLowercase", "isUppercase", "isTitlecase", "isCasefolded", "isCased", - }); + */ - static final Names String_Extras = new Names(UProperty.STRING_LIMIT, - new String[] { - "toNFC", "toNFD", "toNFKC", "toNKFD", - }); + static final Names Binary_Extras = new Names(UProperty.BINARY_LIMIT, + new String[] { + "isNFC", "isNFD", "isNFKC", "isNFKD", + "isLowercase", "isUppercase", "isTitlecase", "isCasefolded", "isCased", + }); - static final int - isNFC = UProperty.BINARY_LIMIT, - isNFD = UProperty.BINARY_LIMIT+1, - isNFKC = UProperty.BINARY_LIMIT+2, - isNFKD = UProperty.BINARY_LIMIT+3, - isLowercase = UProperty.BINARY_LIMIT+4, - isUppercase = UProperty.BINARY_LIMIT+5, - isTitlecase = UProperty.BINARY_LIMIT+6, - isCasefolded = UProperty.BINARY_LIMIT+7, - isCased = UProperty.BINARY_LIMIT+8, - BINARY_LIMIT = UProperty.BINARY_LIMIT+9, +// static final Names String_Extras = new Names(UProperty.STRING_LIMIT, +// new String[] { +// "toNFC", "toNFD", "toNFKC", "toNKFD", +// }); - NFC = UProperty.STRING_LIMIT, - NFD = UProperty.STRING_LIMIT+1, - NFKC = UProperty.STRING_LIMIT+2, - NFKD = UProperty.STRING_LIMIT+3 - ; - - private ICUPropertyFactory() { - Collection c = getInternalAvailablePropertyAliases(new ArrayList()); - Iterator it = c.iterator(); - while (it.hasNext()) { - add(getInternalProperty((String)it.next())); - } - } - - private static ICUPropertyFactory singleton = null; - - public static synchronized ICUPropertyFactory make() { - if (singleton != null) return singleton; - singleton = new ICUPropertyFactory(); - return singleton; - } - - public List getInternalAvailablePropertyAliases(List result) { - int[][] ranges = { - {UProperty.BINARY_START, UProperty.BINARY_LIMIT}, - {UProperty.INT_START, UProperty.INT_LIMIT}, - {UProperty.DOUBLE_START, UProperty.DOUBLE_LIMIT}, - {UProperty.STRING_START, UProperty.STRING_LIMIT}, - }; - for (int i = 0; i < ranges.length; ++i) { - for (int j = ranges[i][0]; j < ranges[i][1]; ++j) { - String alias = UCharacter.getPropertyName(j, UProperty.NameChoice.LONG); - UnicodeProperty.addUnique(alias, result); - if (!result.contains(alias)) result.add(alias); - } - } - result.addAll(String_Extras.getNames()); - result.addAll(Binary_Extras.getNames()); - return result; - } - - public UnicodeProperty getInternalProperty(String propertyAlias) { - int propEnum; - main: - { - int possibleItem = Binary_Extras.get(propertyAlias); - if (possibleItem >= 0) { - propEnum = possibleItem; - break main; - } - possibleItem = String_Extras.get(propertyAlias); - if (possibleItem >= 0) { - propEnum = possibleItem; - break main; - } - propEnum = UCharacter.getPropertyEnum(propertyAlias); - } - return new ICUProperty(propertyAlias, propEnum); - } - - /* (non-Javadoc) - * @see com.ibm.icu.dev.test.util.UnicodePropertySource#getProperty(java.lang.String) - */ - // TODO file bug on getPropertyValueName for Canonical_Combining_Class - - public static class Names { - private String[] names; - private int base; - public Names(int base, String[] names) { - this.base = base; - this.names = names; - } - public int get(String name) { - for (int i = 0; i < names.length; ++i) { - if (name.equalsIgnoreCase(names[i])) return base + i; - } - return -1; - } - public String get(int number) { - number -= base; - if (number < 0 || names.length <= number) return null; - return names[number]; - } - public boolean isInRange(int number) { - number -= base; - return (0 <= number && number < names.length); - } - public List getNames() { - return Arrays.asList(names); - } + static final int + isNFC = UProperty.BINARY_LIMIT, + isNFD = UProperty.BINARY_LIMIT+1, + isNFKC = UProperty.BINARY_LIMIT+2, + isNFKD = UProperty.BINARY_LIMIT+3, + isLowercase = UProperty.BINARY_LIMIT+4, + isUppercase = UProperty.BINARY_LIMIT+5, + isTitlecase = UProperty.BINARY_LIMIT+6, + isCasefolded = UProperty.BINARY_LIMIT+7, + isCased = UProperty.BINARY_LIMIT+8, + BINARY_LIMIT = UProperty.BINARY_LIMIT+9 + +// NFC = UProperty.STRING_LIMIT, +// NFD = UProperty.STRING_LIMIT+1, +// NFKC = UProperty.STRING_LIMIT+2, +// NFKD = UProperty.STRING_LIMIT+3 + ; + + private ICUPropertyFactory() { + Collection c = getInternalAvailablePropertyAliases(new ArrayList()); + Iterator it = c.iterator(); + while (it.hasNext()) { + add(getInternalProperty((String)it.next())); } + } + + private static ICUPropertyFactory singleton = null; + + public static synchronized ICUPropertyFactory make() { + if (singleton != null) return singleton; + singleton = new ICUPropertyFactory(); + return singleton; + } + + public List getInternalAvailablePropertyAliases(List result) { + int[][] ranges = { + {UProperty.BINARY_START, UProperty.BINARY_LIMIT}, + {UProperty.INT_START, UProperty.INT_LIMIT}, + {UProperty.DOUBLE_START, UProperty.DOUBLE_LIMIT}, + {UProperty.STRING_START, UProperty.STRING_LIMIT}, + }; + for (int i = 0; i < ranges.length; ++i) { + for (int j = ranges[i][0]; j < ranges[i][1]; ++j) { + String alias = UCharacter.getPropertyName(j, UProperty.NameChoice.LONG); + UnicodeProperty.addUnique(alias, result); + if (!result.contains(alias)) result.add(alias); + } + } + //result.addAll(String_Extras.getNames()); + result.addAll(Binary_Extras.getNames()); + return result; + } + + public UnicodeProperty getInternalProperty(String propertyAlias) { + int propEnum; + main: + { + int possibleItem = Binary_Extras.get(propertyAlias); + if (possibleItem >= 0) { + propEnum = possibleItem; + break main; + } +// possibleItem = String_Extras.get(propertyAlias); +// if (possibleItem >= 0) { +// propEnum = possibleItem; +// break main; +// } + propEnum = UCharacter.getPropertyEnum(propertyAlias); + } + return new ICUProperty(propertyAlias, propEnum); + } + + /* (non-Javadoc) + * @see com.ibm.icu.dev.test.util.UnicodePropertySource#getProperty(java.lang.String) + */ + // TODO file bug on getPropertyValueName for Canonical_Combining_Class + + public static class Names { + private String[] names; + private int base; + public Names(int base, String[] names) { + this.base = base; + this.names = names; + } + public int get(String name) { + for (int i = 0; i < names.length; ++i) { + if (name.equalsIgnoreCase(names[i])) return base + i; + } + return -1; + } + public String get(int number) { + number -= base; + if (number < 0 || names.length <= number) return null; + return names[number]; + } + public boolean isInRange(int number) { + number -= base; + return (0 <= number && number < names.length); + } + public List getNames() { + return Arrays.asList(names); + } + } } diff --git a/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodeProperty.java b/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodeProperty.java index 408b8d91786..db76941aced 100644 --- a/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodeProperty.java +++ b/icu4j/main/tests/translit/src/com/ibm/icu/dev/test/util/UnicodeProperty.java @@ -1,10 +1,11 @@ +package com.ibm.icu.dev.test.util; + /* ******************************************************************************* - * Copyright (C) 1996-2009, International Business Machines Corporation and * + * Copyright (C) 1996-2010, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ -package com.ibm.icu.dev.test.util; import java.io.PrintWriter; import java.io.StringWriter; @@ -19,10 +20,14 @@ import java.util.Map; import java.util.TreeMap; import java.util.regex.Pattern; +import com.ibm.icu.dev.test.util.BagFormatter; +import com.ibm.icu.dev.test.util.UnicodeLabel; +import com.ibm.icu.dev.test.util.UnicodeMap; 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.UFormat; import com.ibm.icu.text.UTF16; import com.ibm.icu.text.UnicodeMatcher; import com.ibm.icu.text.UnicodeSet; @@ -30,1181 +35,1225 @@ import com.ibm.icu.text.UnicodeSetIterator; public abstract class UnicodeProperty extends UnicodeLabel { - public static boolean DEBUG = false; + public static final UnicodeSet UNASSIGNED = new UnicodeSet("[:gc=unassigned:]").freeze(); + public static final UnicodeSet PRIVATE_USE = new UnicodeSet("[:gc=privateuse:]").freeze(); + public static final UnicodeSet SURROGATE = new UnicodeSet("[:gc=surrogate:]").freeze(); + public static final UnicodeSet SPECIALS = new UnicodeSet(UNASSIGNED).addAll(PRIVATE_USE).addAll(SURROGATE).freeze(); + public static final int SAMPLE_UNASSIGNED = UNASSIGNED.charAt(0); + public static final int SAMPLE_PRIVATE_USE = 0xE000; + public static final int SAMPLE_SURROGATE = 0xD800; + public static final UnicodeSet STUFF_TO_TEST = new UnicodeSet(SPECIALS).complement() + .add(SAMPLE_UNASSIGNED).add(SAMPLE_PRIVATE_USE).add(SAMPLE_SURROGATE).freeze(); + public static final UnicodeSet STUFF_TO_TEST_WITH_UNASSIGNED = new UnicodeSet(STUFF_TO_TEST).addAll(UNASSIGNED).freeze(); - public static String CHECK_NAME = "FC_NFKC_Closure"; - public static int CHECK_VALUE = 0x037A; + public static boolean DEBUG = false; - private String name; + public static String CHECK_NAME = "FC_NFKC_Closure"; - private String firstNameAlias = null; + public static int CHECK_VALUE = 0x037A; - private int type; + private String name; - private Map valueToFirstValueAlias = null; + private String firstNameAlias = null; + private int type; + + private Map valueToFirstValueAlias = null; + + private boolean hasUniformUnassigned = true; + + /* + * 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 String getTypeName() { + return TYPE_NAMES[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 valueToFirstValueAlias.get(value).toString(); + } + + 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(); + boolean uniformUnassigned = hasUniformUnassigned(); + if (isType(STRING_OR_MISC_MASK)) { + for (UnicodeSetIterator usi = getStuffToTest(uniformUnassigned); usi.next();) { // int i = 0; i <= 0x10FFFF; ++i + int i = usi.codepoint; + String value = getValue(i); + if (value != null && matcher.matches(value)) { + result.add(i); + } + } + return addUntested(result, uniformUnassigned); + } + 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.keySet(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(); + boolean uniformUnassigned = hasUniformUnassigned(); + + for (UnicodeSetIterator usi = getStuffToTest(uniformUnassigned); usi.next();) { // int i = 0; i <= 0x10FFFF; ++i + int i = usi.codepoint; + // if (DEBUG && i == 0x41) System.out.println(i + "\t" + + // getValue(i)); + String value = getValue(i, true); + result.put(i, value); + } + return addUntested(result, uniformUnassigned); + } + + /** + * @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(); + boolean uniformUnassigned = hasUniformUnassigned(); + + for (UnicodeSetIterator usi = getStuffToTest(uniformUnassigned); usi.next();) { // int i = 0; i <= 0x10FFFF; ++i + int i = usi.codepoint; + // 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); + } + addUntested(result, uniformUnassigned); + + if (DEBUG) { + for (UnicodeSetIterator usi = getStuffToTest(uniformUnassigned); usi.next();) { // int i = 0; i <= 0x10FFFF; ++i + int i = usi.codepoint; + // 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; + } + + private static UnicodeSetIterator getStuffToTest(boolean uniformUnassigned) { + return new UnicodeSetIterator(uniformUnassigned ? STUFF_TO_TEST : STUFF_TO_TEST_WITH_UNASSIGNED); + } + + /** + * 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; /* - * Name: Unicode_1_Name Name: ISO_Comment Name: Name Name: Unicode_1_Name - * + * if (source.equals("noBreak")) { // HACK if (titlecaseStart) return + * "NoBreak"; return source; } */ - - 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; + 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); } - return _getValue(codepoint); + 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 == null) return false; + if (other.length() == 1) { + return codepoint == other.charAt(0); + } + if (other.length() == 2) { + return other.equals(UTF16.valueOf(codepoint)); + } + return false; + } + + /** + * Utility function for comparing objects that may be null + * string. + */ + public static final boolean equals(T a, T b) { + return a == null ? b == null + : b == null ? false + : a.equals(b); + } + + /** + * 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 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 final UnicodeProperty getProperty(String propertyAlias) { + return (UnicodeProperty) skeletonNames + .get(toSkeleton(propertyAlias)); } - 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)); + 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; } - return result; + addUnique(property.getName(), 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.keySet(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); } - */ + InversePatternMatcher inverseMatcher = new InversePatternMatcher(); /** - * Utility for debugging + * Format is: propname ('=' | '!=') propvalue ( '|' propValue )* */ - 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(); + 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); } - // 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; - } + public final UnicodeSet getSet(String propAndValue, + PatternMatcher matcher) { + return getSet(propAndValue, matcher, null); } - /** - * @return the unicode map - */ - public UnicodeMap getUnicodeMap() { - return getUnicodeMap(false); + public final UnicodeSet getSet(String propAndValue) { + return getSet(propAndValue, null, null); } - /** - * @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); + 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"); } - 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); + UnicodeProperty prop = getProperty(s.substring(start, pos)); + if (prop == null) { + throw new IllegalArgumentException("Invalid Property in: " + + s + "\r\nUse " + showSet(getAvailableNames())); } - 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)); - } - } + 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 (DEBUG && CHECK_NAME.equals(getName())) { - System.out.println(getName() + ":\t" + getClass().getName() + "\t" - + getVersion()); - System.out.println(getStack()); - System.out.println(result); + if (set.size() == 0) { + throw new IllegalArgumentException( + "Empty Property-Value in: " + s + "\r\nUse " + + showSet(prop.getAvailableValues())); } - return result; - } + if (DEBUG) + System.out.println("\t(" + prefix + ")Returning " + + set.toPattern(true)); + return set.toPattern(true).toCharArray(); // really ugly + } - /** - * 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); - } + 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(); - } + } - /** - * 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(); - } + public UnicodeMatcher lookupMatcher(int ch) { + return null; + } - /** - * 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) { + 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); } - - 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; - } + 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 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 StringFilter getFilter() { + return filter; } - 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 UnicodeProperty setFilter(StringFilter filter) { + this.filter = filter; + return this; } - public static class MapFilter extends StringFilter { - private Map valueMap; + List temp = new ArrayList(1); - 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 List _getAvailableValues(List result) { + temp.clear(); + return filter.addUnique(property.getAvailableValues(temp), result); } - public interface PatternMatcher extends ObjectMatcher { - public PatternMatcher set(String pattern); + public List _getNameAliases(List result) { + temp.clear(); + return filter.addUnique(property.getNameAliases(temp), result); } - 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 String _getValue(int codepoint) { + return filter.remap(property.getValue(codepoint)); } - 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 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 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.find(); - } + public String _getVersion() { + return property.getVersion(); } - public static abstract class BaseProperty extends UnicodeProperty { - private static final String[] NO_VALUES = {"No", "N", "F", "False"}; - - private static final String[] YES_VALUES = {"Yes", "Y", "T", "True"}; - - /** - * - */ - private static final String[][] YES_NO_ALIASES = new String[][] {YES_VALUES, NO_VALUES}; - - 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); - if (propertyType == BINARY) { - addValueAliases(YES_NO_ALIASES, false); - } - 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 boolean isAllowValueAliasCollisions() { + return allowValueAliasCollisions; } - public static abstract class SimpleProperty extends BaseProperty { - List values; + public FilteredProperty setAllowValueAliasCollisions(boolean b) { + allowValueAliasCollisions = b; + return this; + } - public UnicodeProperty addName(String alias) { - propertyAliases.add(alias); - return this; - } + } - public SimpleProperty setValues(String valueAlias) { - _addToValues(valueAlias, null); - return this; - } + public static abstract class StringFilter implements Cloneable { + public abstract String remap(String original); - public SimpleProperty addAliases(String valueAlias, String... aliases) { - _addToValues(valueAlias, null); - return this; - } + 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 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 static class MapFilter extends StringFilter { + private Map valueMap; - 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 MapFilter(Map valueMap) { + this.valueMap = valueMap; + } - public List _getAvailableValues(List result) { - if (values == null) - _fillValues(); - result.addAll(values); - return result; - } + public String remap(String original) { + Object changed = valueMap.get(original); + return changed == null ? original : (String) changed; + } - protected void _fillValues() { - List newvalues = (List) getUnicodeMap_internal() - .getAvailableValues(new ArrayList()); - for (Iterator it = newvalues.iterator(); it.hasNext();) { - _addToValues((String) it.next(), null); - } - } + public Map getMap() { + return valueMap; + } + } - 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 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; + } + UFormat foo; + public boolean matches(Object value) { + matcher.reset(value.toString()); + return matcher.find(); + } + } + + public static abstract class BaseProperty extends UnicodeProperty { + private static final String[] NO_VALUES = {"No", "N", "F", "False"}; + + private static final String[] YES_VALUES = {"Yes", "Y", "T", "True"}; + + /** + * + */ + private static final String[][] YES_NO_ALIASES = new String[][] {YES_VALUES, NO_VALUES}; + + 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); + if (propertyType == BINARY) { + addValueAliases(YES_NO_ALIASES, false); + } + 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); } - /* public String _getVersion() { + } + 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 addAliases(String valueAlias, String... aliases) { + _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() { + public static class UnicodeMapProperty extends BaseProperty { + /* + * Example of usage: + * new UnicodeProperty.UnicodeMapProperty() { { unicodeMap = new UnicodeMap(); unicodeMap.setErrorOnReset(true); @@ -1228,26 +1277,102 @@ public abstract class UnicodeProperty extends UnicodeLabel { unicodeMap.setMissing("Other"); } }.setMain("Grapheme_Cluster_Break", "GCB", UnicodeProperty.ENUMERATED, version) - */ - protected UnicodeMap unicodeMap; + */ + protected UnicodeMap unicodeMap; - public UnicodeMapProperty set(UnicodeMap map) { - unicodeMap = map; - return this; - } + public UnicodeMapProperty set(UnicodeMap map) { + unicodeMap = map; + return this; + } - protected String _getValue(int codepoint) { - return (String) unicodeMap.getValue(codepoint); - } + protected String _getValue(int codepoint) { + return (String) unicodeMap.getValue(codepoint); + } - /* protected List _getValueAliases(String valueAlias, List result) { + /* 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); - } + */protected List _getAvailableValues(List result) { + return (List) unicodeMap.getAvailableValues(result); + } + } + + public boolean isValidValue(String propertyValue) { + if (isType(STRING_OR_MISC_MASK)) { + return true; } + Collection values = (Collection) getAvailableValues(); + for (String valueAlias : values) { + if (UnicodeProperty.compareNames(valueAlias, propertyValue) == 0) { + return true; + } + for (String valueAlias2 : (Collection) getValueAliases(valueAlias)) { + if (UnicodeProperty.compareNames(valueAlias2, propertyValue) == 0) { + return true; + } + } + } + return false; + } + + public List getValueAliases() { + List result = new ArrayList(); + if (isType(STRING_OR_MISC_MASK)) { + return result; + } + Collection values = (Collection) getAvailableValues(); + for (String valueAlias : values) { + UnicodeProperty.addAllUnique(getValueAliases(valueAlias), result); + } + result.removeAll(values); + return result; + } + + + public static UnicodeSet addUntested(UnicodeSet result, boolean uniformUnassigned) { + if (uniformUnassigned && result.contains(UnicodeProperty.SAMPLE_UNASSIGNED)) { + result.addAll(UnicodeProperty.UNASSIGNED); + } + if (result.contains(UnicodeProperty.SAMPLE_PRIVATE_USE)) { + result.addAll(UnicodeProperty.PRIVATE_USE); + } + if (result.contains(UnicodeProperty.SAMPLE_SURROGATE)) { + result.addAll(UnicodeProperty.SURROGATE); + } + return result; + } + + public static UnicodeMap addUntested(UnicodeMap result, boolean uniformUnassigned) { + Object temp; + if (uniformUnassigned && null != (temp = result.get(UnicodeProperty.SAMPLE_UNASSIGNED))) { + result.putAll(UnicodeProperty.UNASSIGNED, temp); + } + if (null != (temp = result.get(UnicodeProperty.SAMPLE_PRIVATE_USE))) { + result.putAll(UnicodeProperty.PRIVATE_USE, temp); + } + if (null != (temp = result.get(UnicodeProperty.SAMPLE_SURROGATE))) { + result.putAll(UnicodeProperty.SURROGATE, temp); + } + return result; + } + + public boolean isDefault(int cp) { + String value = getValue(cp); + if (isType(STRING_OR_MISC_MASK)) { + return equals(cp, value); + } + String defaultValue = getValue(SAMPLE_UNASSIGNED); + return defaultValue == null ? value == null : defaultValue.equals(value); + } + + public boolean hasUniformUnassigned() { + return hasUniformUnassigned; + } + protected UnicodeProperty setUniformUnassigned(boolean hasUniformUnassigned) { + this.hasUniformUnassigned = hasUniformUnassigned; + return this; + } }