2 //#if defined(FOUNDATION10) || defined(J2SE13)
5 *******************************************************************************
6 * Copyright (C) 2002-2009, International Business Machines Corporation and *
7 * others. All Rights Reserved. *
8 *******************************************************************************
10 package com.ibm.icu.dev.test.util;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Locale;
21 import java.util.TreeSet;
23 import com.ibm.icu.lang.UCharacter;
24 import com.ibm.icu.lang.UProperty;
25 import com.ibm.icu.text.Normalizer;
26 import com.ibm.icu.text.UTF16;
27 import com.ibm.icu.util.VersionInfo;
31 * Provides a general interface for Unicode Properties, and
32 * extracting sets based on those values.
36 public class ICUPropertyFactory extends UnicodeProperty.Factory {
38 static class ICUProperty extends UnicodeProperty {
39 protected int propEnum = Integer.MIN_VALUE;
41 protected ICUProperty(String propName, int propEnum) {
43 this.propEnum = propEnum;
44 setType(internalGetPropertyType(propEnum));
47 boolean shownException = false;
49 public String _getValue(int codePoint) {
51 case UProperty.AGE: String temp = UCharacter.getAge(codePoint).toString();
52 if (temp.equals("0.0.0.0")) return "unassigned";
53 if (temp.endsWith(".0.0")) return temp.substring(0,temp.length()-4);
55 case UProperty.BIDI_MIRRORING_GLYPH: return UTF16.valueOf(UCharacter.getMirror(codePoint));
56 case UProperty.CASE_FOLDING: return UCharacter.foldCase(UTF16.valueOf(codePoint),true);
57 case UProperty.ISO_COMMENT: return UCharacter.getISOComment(codePoint);
58 case UProperty.LOWERCASE_MAPPING: return UCharacter.toLowerCase(Locale.ENGLISH,UTF16.valueOf(codePoint));
59 case UProperty.NAME: return UCharacter.getName(codePoint);
60 case UProperty.SIMPLE_CASE_FOLDING: return UTF16.valueOf(UCharacter.foldCase(codePoint,true));
61 case UProperty.SIMPLE_LOWERCASE_MAPPING: return UTF16.valueOf(UCharacter.toLowerCase(codePoint));
62 case UProperty.SIMPLE_TITLECASE_MAPPING: return UTF16.valueOf(UCharacter.toTitleCase(codePoint));
63 case UProperty.SIMPLE_UPPERCASE_MAPPING: return UTF16.valueOf(UCharacter.toUpperCase(codePoint));
64 case UProperty.TITLECASE_MAPPING: return UCharacter.toTitleCase(Locale.ENGLISH,UTF16.valueOf(codePoint),null);
65 case UProperty.UNICODE_1_NAME: return UCharacter.getName1_0(codePoint);
66 case UProperty.UPPERCASE_MAPPING: return UCharacter.toUpperCase(Locale.ENGLISH,UTF16.valueOf(codePoint));
67 case NFC: return Normalizer.normalize(codePoint, Normalizer.NFC);
68 case NFD: return Normalizer.normalize(codePoint, Normalizer.NFD);
69 case NFKC: return Normalizer.normalize(codePoint, Normalizer.NFKC);
70 case NFKD: return Normalizer.normalize(codePoint, Normalizer.NFKD);
71 case isNFC: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFC).equals(UTF16.valueOf(codePoint)));
72 case isNFD: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFD).equals(UTF16.valueOf(codePoint)));
73 case isNFKC: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFKC).equals(UTF16.valueOf(codePoint)));
74 case isNFKD: return String.valueOf(Normalizer.normalize(codePoint, Normalizer.NFKD).equals(UTF16.valueOf(codePoint)));
75 case isLowercase: return String.valueOf(UCharacter.toLowerCase(Locale.ENGLISH,UTF16.valueOf(codePoint)).equals(UTF16.valueOf(codePoint)));
76 case isUppercase: return String.valueOf(UCharacter.toUpperCase(Locale.ENGLISH,UTF16.valueOf(codePoint)).equals(UTF16.valueOf(codePoint)));
77 case isTitlecase: return String.valueOf(UCharacter.toTitleCase(Locale.ENGLISH,UTF16.valueOf(codePoint),null).equals(UTF16.valueOf(codePoint)));
78 case isCasefolded: return String.valueOf(UCharacter.foldCase(UTF16.valueOf(codePoint),true).equals(UTF16.valueOf(codePoint)));
79 case isCased: return String.valueOf(UCharacter.toLowerCase(Locale.ENGLISH,UTF16.valueOf(codePoint)).equals(UTF16.valueOf(codePoint)));
81 if (propEnum < UProperty.INT_LIMIT) {
85 enumValue = UCharacter.getIntPropertyValue(codePoint, propEnum);
86 if (enumValue >= 0) value = fixedGetPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG);
87 } catch (IllegalArgumentException e) {
88 if (!shownException) {
89 System.out.println("Fail: " + getName() + ", " + Integer.toHexString(codePoint));
90 shownException = true;
93 return value != null ? value : String.valueOf(enumValue);
94 } else if (propEnum < UProperty.DOUBLE_LIMIT) {
95 double num = UCharacter.getUnicodeNumericValue(codePoint);
96 if (num == UCharacter.NO_NUMERIC_VALUE) return null;
97 return Double.toString(num);
98 // TODO: Fix HACK -- API deficient
104 * @param valueAlias null if unused.
105 * @param valueEnum -1 if unused
109 private String getFixedValueAlias(String valueAlias, int valueEnum, int nameChoice) {
110 if (propEnum >= UProperty.STRING_START) {
111 if (nameChoice != UProperty.NameChoice.LONG) return null;
113 } else if (propEnum >= UProperty.DOUBLE_START) {
114 if (nameChoice != UProperty.NameChoice.LONG) return null;
117 if (valueAlias != null && !valueAlias.equals("<integer>")) {
118 valueEnum = fixedGetPropertyValueEnum(propEnum,valueAlias);
120 // because these are defined badly, there may be no normal (long) name.
122 String result = fixedGetPropertyValueName(propEnum, valueEnum, nameChoice);
123 if (result != null) return result;
124 // HACK try other namechoice
125 if (nameChoice == UProperty.NameChoice.LONG) {
126 result = fixedGetPropertyValueName(propEnum,valueEnum, UProperty.NameChoice.SHORT);
127 if (result != null) return result;
128 if (propEnum == UProperty.CANONICAL_COMBINING_CLASS) return null;
134 private static int fixedGetPropertyValueEnum(int propEnum, String valueAlias) {
136 return UCharacter.getPropertyValueEnum(propEnum, valueAlias);
137 } catch (Exception e) {
138 return Integer.parseInt(valueAlias);
142 static Map fixSkeleton = new HashMap();
143 private static String fixedGetPropertyValueName(int propEnum, int valueEnum, int nameChoice) {
146 String value = UCharacter.getPropertyValueName(propEnum,valueEnum,nameChoice);
147 String newValue = (String) fixSkeleton.get(value);
148 if (newValue == null) {
150 if (propEnum == UProperty.JOINING_GROUP) {
151 newValue = newValue.toLowerCase(Locale.ENGLISH);
153 newValue = regularize(newValue, true);
154 fixSkeleton.put(value, newValue);
157 } catch (Exception e) {
162 public List _getNameAliases(List result) {
163 if (result == null) result = new ArrayList();
164 String alias = String_Extras.get(propEnum);
165 if (alias == null) alias = Binary_Extras.get(propEnum);
167 addUnique(alias, result);
169 addUnique(getFixedPropertyName(propEnum, UProperty.NameChoice.SHORT), result);
170 addUnique(getFixedPropertyName(propEnum, UProperty.NameChoice.LONG), result);
175 public String getFixedPropertyName(int propName, int nameChoice) {
177 return UCharacter.getPropertyName(propEnum, nameChoice);
178 } catch (IllegalArgumentException e) {
183 private Map cccHack = new HashMap();
184 boolean needCccHack = true;
186 public List _getAvailableValues(List result) {
187 if (result == null) result = new ArrayList();
188 if (propEnum == UProperty.AGE) {
189 addAllUnique(getAges(),
193 if (propEnum < UProperty.INT_LIMIT) {
194 if (Binary_Extras.isInRange(propEnum)) {
195 propEnum = UProperty.BINARY_START; // HACK
197 int start = UCharacter.getIntPropertyMinValue(propEnum);
198 int end = UCharacter.getIntPropertyMaxValue(propEnum);
199 for (int i = start; i <= end; ++i) {
200 String alias = getFixedValueAlias(null, i, UProperty.NameChoice.LONG);
201 String alias2 = getFixedValueAlias(null, i, UProperty.NameChoice.SHORT);
204 if (alias == null && propEnum == UProperty.CANONICAL_COMBINING_CLASS) {
205 alias = String.valueOf(i);
208 if (needCccHack && propEnum == UProperty.CANONICAL_COMBINING_CLASS) { // HACK
209 cccHack.put(alias, String.valueOf(i));
211 //System.out.println(propertyAlias + "\t" + i + ":\t" + alias);
212 addUnique(alias, result);
216 String alias = getFixedValueAlias(null, -1,UProperty.NameChoice.LONG);
217 addUnique(alias, result);
222 static String[] AGES = null;
223 private String[] getAges() {
225 Set ages = new TreeSet();
226 for (int i = 0; i < 0x10FFFF; ++i) {
227 VersionInfo age = UCharacter.getAge(i);
228 ages.add(age.toString());
230 AGES = (String[]) ages.toArray(new String[ages.size()]);
235 public List _getValueAliases(String valueAlias, List result) {
236 if (result == null) result = new ArrayList();
237 if (propEnum == UProperty.AGE) {
238 addUnique(valueAlias, result);
241 if (propEnum == UProperty.CANONICAL_COMBINING_CLASS) {
242 addUnique(cccHack.get(valueAlias), result); // add number
244 addUnique(getFixedValueAlias(valueAlias, -1, UProperty.NameChoice.SHORT), result);
245 addUnique(getFixedValueAlias(valueAlias, -1, UProperty.NameChoice.LONG), result);
251 * @see com.ibm.icu.dev.test.util.UnicodePropertySource#getPropertyType()
253 private int internalGetPropertyType(int prop) {
256 case UProperty.BLOCK:
257 case UProperty.SCRIPT:
258 return UnicodeProperty.CATALOG;
259 case UProperty.ISO_COMMENT:
261 case UProperty.UNICODE_1_NAME:
262 return UnicodeProperty.MISC;
263 case UProperty.BIDI_MIRRORING_GLYPH:
264 case UProperty.CASE_FOLDING:
265 case UProperty.LOWERCASE_MAPPING:
266 case UProperty.SIMPLE_CASE_FOLDING:
267 case UProperty.SIMPLE_LOWERCASE_MAPPING:
268 case UProperty.SIMPLE_TITLECASE_MAPPING:
269 case UProperty.SIMPLE_UPPERCASE_MAPPING:
270 case UProperty.TITLECASE_MAPPING:
271 case UProperty.UPPERCASE_MAPPING:
272 return UnicodeProperty.EXTENDED_STRING;
274 if (prop < UProperty.BINARY_START) return UnicodeProperty.UNKNOWN;
275 if (prop < UProperty.BINARY_LIMIT) return UnicodeProperty.BINARY;
276 if (prop < UProperty.INT_START) return UnicodeProperty.EXTENDED_BINARY;
277 if (prop < UProperty.INT_LIMIT) return UnicodeProperty.ENUMERATED;
278 if (prop < UProperty.DOUBLE_START) return UnicodeProperty.EXTENDED_ENUMERATED;
279 if (prop < UProperty.DOUBLE_LIMIT) return UnicodeProperty.NUMERIC;
280 if (prop < UProperty.STRING_START) return UnicodeProperty.EXTENDED_NUMERIC;
281 if (prop < UProperty.STRING_LIMIT) return UnicodeProperty.STRING;
282 return UnicodeProperty.EXTENDED_STRING;
286 * @see com.ibm.icu.dev.test.util.UnicodeProperty#getVersion()
288 public String _getVersion() {
289 return VersionInfo.ICU_VERSION.toString();
294 matchIterator = new UnicodeSetIterator(
295 new UnicodeSet("[^[:Cn:]-[:Default_Ignorable_Code_Point:]]"));
301 * Other Missing Functions:
306 Composition_Exclusion
307 Decomposition_Mapping
314 Special_Case_Condition
315 Unicode_Radical_Stroke
318 static final Names Binary_Extras = new Names(UProperty.BINARY_LIMIT,
320 "isNFC", "isNFD", "isNFKC", "isNFKD",
321 "isLowercase", "isUppercase", "isTitlecase", "isCasefolded", "isCased",
324 static final Names String_Extras = new Names(UProperty.STRING_LIMIT,
326 "toNFC", "toNFD", "toNFKC", "toNKFD",
330 isNFC = UProperty.BINARY_LIMIT,
331 isNFD = UProperty.BINARY_LIMIT+1,
332 isNFKC = UProperty.BINARY_LIMIT+2,
333 isNFKD = UProperty.BINARY_LIMIT+3,
334 isLowercase = UProperty.BINARY_LIMIT+4,
335 isUppercase = UProperty.BINARY_LIMIT+5,
336 isTitlecase = UProperty.BINARY_LIMIT+6,
337 isCasefolded = UProperty.BINARY_LIMIT+7,
338 isCased = UProperty.BINARY_LIMIT+8,
340 NFC = UProperty.STRING_LIMIT,
341 NFD = UProperty.STRING_LIMIT+1,
342 NFKC = UProperty.STRING_LIMIT+2,
343 NFKD = UProperty.STRING_LIMIT+3
346 private ICUPropertyFactory() {
347 Collection c = getInternalAvailablePropertyAliases(new ArrayList());
348 Iterator it = c.iterator();
349 while (it.hasNext()) {
350 add(getInternalProperty((String)it.next()));
354 private static ICUPropertyFactory singleton = null;
356 public static synchronized ICUPropertyFactory make() {
357 if (singleton != null) return singleton;
358 singleton = new ICUPropertyFactory();
362 public List getInternalAvailablePropertyAliases(List result) {
364 {UProperty.BINARY_START, UProperty.BINARY_LIMIT},
365 {UProperty.INT_START, UProperty.INT_LIMIT},
366 {UProperty.DOUBLE_START, UProperty.DOUBLE_LIMIT},
367 {UProperty.STRING_START, UProperty.STRING_LIMIT},
369 for (int i = 0; i < ranges.length; ++i) {
370 for (int j = ranges[i][0]; j < ranges[i][1]; ++j) {
371 String alias = UCharacter.getPropertyName(j, UProperty.NameChoice.LONG);
372 UnicodeProperty.addUnique(alias, result);
373 if (!result.contains(alias)) result.add(alias);
376 result.addAll(String_Extras.getNames());
377 result.addAll(Binary_Extras.getNames());
381 public UnicodeProperty getInternalProperty(String propertyAlias) {
385 int possibleItem = Binary_Extras.get(propertyAlias);
386 if (possibleItem >= 0) {
387 propEnum = possibleItem;
390 possibleItem = String_Extras.get(propertyAlias);
391 if (possibleItem >= 0) {
392 propEnum = possibleItem;
395 propEnum = UCharacter.getPropertyEnum(propertyAlias);
397 return new ICUProperty(propertyAlias, propEnum);
401 * @see com.ibm.icu.dev.test.util.UnicodePropertySource#getProperty(java.lang.String)
403 // TODO file bug on getPropertyValueName for Canonical_Combining_Class
405 public static class Names {
406 private String[] names;
408 public Names(int base, String[] names) {
412 public int get(String name) {
413 for (int i = 0; i < names.length; ++i) {
414 if (name.equalsIgnoreCase(names[i])) return base + i;
418 public String get(int number) {
420 if (number < 0 || names.length <= number) return null;
421 return names[number];
423 public boolean isInRange(int number) {
425 return (0 <= number && number < names.length);
427 public List getNames() {
428 return Arrays.asList(names);