17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ********************************************************************** 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (c) 2002-2014, International Business Machines 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Corporation and others. All Rights Reserved. 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ********************************************************************** 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Author: Alan Liu 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Created: November 5 2002 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Since: ICU 2.4 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2010nov19 Markus Scherer Rewrite for formatVersion 2. 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ********************************************************************** 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.IOException; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.nio.ByteBuffer; 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.MissingResourceException; 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.lang.UProperty; 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.BytesTrie; 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Wrapper for the pnames.icu binary data file. This data file is 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * imported from icu4c. It contains property and property value 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * aliases from the UCD files PropertyAliases.txt and 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * PropertyValueAliases.txt. The file is built by the icu4c tool 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * genpname. It must be an ASCII big-endian file to be 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * usable in icu4j. 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This class performs two functions. 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (1) It can import the flat binary data into usable objects. 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (2) It provides an API to access the tree of objects. 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Needless to say, this class is tightly coupled to the binary format 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * of icu4c's pnames.icu file. 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Each time a UPropertyAliases is constructed, the pnames.icu file is 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * read, parsed, and data structures assembled. Clients should create one 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * singleton instance and cache it. 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author Alan Liu 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @since ICU 2.4 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic final class UPropertyAliases { 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Byte offsets from the start of the data, after the generic header. 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int IX_VALUE_MAPS_OFFSET=0; 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int IX_BYTE_TRIES_OFFSET=1; 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int IX_NAME_GROUPS_OFFSET=2; 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int IX_RESERVED3_OFFSET=3; 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // private static final int IX_RESERVED4_OFFSET=4; 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // private static final int IX_TOTAL_SIZE=5; 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Other values. 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // private static final int IX_MAX_NAME_LENGTH=6; 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // private static final int IX_RESERVED7=7; 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // private static final int IX_COUNT=8; 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //---------------------------------------------------------------- 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Runtime data. This is an unflattened representation of the 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // data in pnames.icu. 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int[] valueMaps; 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private byte[] bytesTries; 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String nameGroups; 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final class IsAcceptable implements ICUBinary.Authenticate { 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // @Override when we switch to Java 6 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isDataVersionAcceptable(byte version[]) { 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return version[0]==2; 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final IsAcceptable IS_ACCEPTABLE=new IsAcceptable(); 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int DATA_FORMAT=0x706E616D; // "pnam" 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void load(ByteBuffer bytes) throws IOException { 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //dataVersion=ICUBinary.readHeaderAndDataVersion(bytes, DATA_FORMAT, IS_ACCEPTABLE); 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUBinary.readHeader(bytes, DATA_FORMAT, IS_ACCEPTABLE); 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int indexesLength=bytes.getInt()/4; // inIndexes[IX_VALUE_MAPS_OFFSET]/4 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(indexesLength<8) { // formatVersion 2 initially has 8 indexes 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IOException("pnames.icu: not enough indexes"); 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] inIndexes=new int[indexesLength]; 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert inIndexes[0]=indexesLength*4; 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int i=1; i<indexesLength; ++i) { 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert inIndexes[i]=bytes.getInt(); 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Read the valueMaps. 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int offset=inIndexes[IX_VALUE_MAPS_OFFSET]; 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int nextOffset=inIndexes[IX_BYTE_TRIES_OFFSET]; 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int numInts=(nextOffset-offset)/4; 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert valueMaps=new int[numInts]; 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int i=0; i<numInts; ++i) { 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert valueMaps[i]=bytes.getInt(); 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Read the bytesTries. 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert offset=nextOffset; 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nextOffset=inIndexes[IX_NAME_GROUPS_OFFSET]; 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int numBytes=nextOffset-offset; 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bytesTries=new byte[numBytes]; 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bytes.get(bytesTries); 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Read the nameGroups and turn them from ASCII bytes into a Java String. 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert offset=nextOffset; 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nextOffset=inIndexes[IX_RESERVED3_OFFSET]; 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert numBytes=nextOffset-offset; 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder sb=new StringBuilder(numBytes); 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int i=0; i<numBytes; ++i) { 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert sb.append((char)bytes.get()); 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nameGroups=sb.toString(); 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private UPropertyAliases() throws IOException { 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ByteBuffer bytes = ICUBinary.getRequiredData("pnames.icu"); 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert load(bytes); 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int findProperty(int property) { 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int i=1; // valueMaps index, initially after numRanges 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int numRanges=valueMaps[0]; numRanges>0; --numRanges) { 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Read and skip the start and limit of this range. 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int start=valueMaps[i]; 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int limit=valueMaps[i+1]; 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert i+=2; 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(property<start) { 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(property<limit) { 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return i+(property-start)*2; 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert i+=(limit-start)*2; // Skip all entries for this range. 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int findPropertyValueNameGroup(int valueMapIndex, int value) { 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(valueMapIndex==0) { 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; // The property does not have named values. 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ++valueMapIndex; // Skip the BytesTrie offset. 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int numRanges=valueMaps[valueMapIndex++]; 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(numRanges<0x10) { 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Ranges of values. 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(; numRanges>0; --numRanges) { 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Read and skip the start and limit of this range. 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int start=valueMaps[valueMapIndex]; 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int limit=valueMaps[valueMapIndex+1]; 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert valueMapIndex+=2; 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(value<start) { 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(value<limit) { 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return valueMaps[valueMapIndex+value-start]; 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert valueMapIndex+=limit-start; // Skip all entries for this range. 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // List of values. 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int valuesStart=valueMapIndex; 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int nameGroupOffsetsStart=valueMapIndex+numRanges-0x10; 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert do { 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int v=valueMaps[valueMapIndex]; 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(value<v) { 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(value==v) { 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return valueMaps[nameGroupOffsetsStart+valueMapIndex-valuesStart]; 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } while(++valueMapIndex<nameGroupOffsetsStart); 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String getName(int nameGroupsIndex, int nameIndex) { 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int numNames=nameGroups.charAt(nameGroupsIndex++); 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(nameIndex<0 || numNames<=nameIndex) { 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalIcuArgumentException("Invalid property (value) name choice"); 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Skip nameIndex names. 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(; nameIndex>0; --nameIndex) { 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while(0!=nameGroups.charAt(nameGroupsIndex++)) {} 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Find the end of this name. 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int nameStart=nameGroupsIndex; 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while(0!=nameGroups.charAt(nameGroupsIndex)) { 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ++nameGroupsIndex; 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(nameStart==nameGroupsIndex) { 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; // no name (Property[Value]Aliases.txt has "n/a") 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return nameGroups.substring(nameStart, nameGroupsIndex); 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static int asciiToLowercase(int c) { 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 'A'<=c && c<='Z' ? c+0x20 : c; 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private boolean containsName(BytesTrie trie, CharSequence name) { 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert BytesTrie.Result result=BytesTrie.Result.NO_VALUE; 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int i=0; i<name.length(); ++i) { 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int c=name.charAt(i); 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Ignore delimiters '-', '_', and ASCII White_Space. 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(c=='-' || c=='_' || c==' ' || (0x09<=c && c<=0x0d)) { 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(!result.hasNext()) { 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert c=asciiToLowercase(c); 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result=trie.next(c); 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.hasValue(); 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //---------------------------------------------------------------- 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Public API 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final UPropertyAliases INSTANCE; 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static { 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert INSTANCE = new UPropertyAliases(); 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch(IOException e) { 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ///CLOVER:OFF 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MissingResourceException mre = new MissingResourceException( 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Could not construct UPropertyAliases. Missing pnames.icu", "", ""); 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mre.initCause(e); 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw mre; 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ///CLOVER:ON 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a property name given a property enum. 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Multiple names may be available for each property; 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the nameChoice selects among them. 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getPropertyName(int property, int nameChoice) { 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int valueMapIndex=findProperty(property); 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(valueMapIndex==0) { 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException( 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Invalid property enum "+property+" (0x"+Integer.toHexString(property)+")"); 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getName(valueMaps[valueMapIndex], nameChoice); 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a value name given a property enum and a value enum. 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Multiple names may be available for each value; 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the nameChoice selects among them. 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getPropertyValueName(int property, int value, int nameChoice) { 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int valueMapIndex=findProperty(property); 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(valueMapIndex==0) { 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException( 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Invalid property enum "+property+" (0x"+Integer.toHexString(property)+")"); 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int nameGroupOffset=findPropertyValueNameGroup(valueMaps[valueMapIndex+1], value); 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(nameGroupOffset==0) { 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException( 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Property "+property+" (0x"+Integer.toHexString(property)+ 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ") does not have named values"); 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getName(nameGroupOffset, nameChoice); 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int getPropertyOrValueEnum(int bytesTrieOffset, CharSequence alias) { 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert BytesTrie trie=new BytesTrie(bytesTries, bytesTrieOffset); 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(containsName(trie, alias)) { 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return trie.getValue(); 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return UProperty.UNDEFINED; 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a property enum given one of its property names. 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If the property name is not known, this method returns 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * UProperty.UNDEFINED. 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getPropertyEnum(CharSequence alias) { 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getPropertyOrValueEnum(0, alias); 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a value enum given a property enum and one of its value names. 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getPropertyValueEnum(int property, CharSequence alias) { 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int valueMapIndex=findProperty(property); 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(valueMapIndex==0) { 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException( 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Invalid property enum "+property+" (0x"+Integer.toHexString(property)+")"); 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert valueMapIndex=valueMaps[valueMapIndex+1]; 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(valueMapIndex==0) { 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException( 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Property "+property+" (0x"+Integer.toHexString(property)+ 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ") does not have named values"); 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // valueMapIndex is the start of the property's valueMap, 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // where the first word is the BytesTrie offset. 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getPropertyOrValueEnum(valueMaps[valueMapIndex], alias); 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a value enum given a property enum and one of its value names. Does not throw. 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return value enum, or UProperty.UNDEFINED if not defined for that property 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getPropertyValueEnumNoThrow(int property, CharSequence alias) { 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int valueMapIndex=findProperty(property); 3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(valueMapIndex==0) { 3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return UProperty.UNDEFINED; 3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert valueMapIndex=valueMaps[valueMapIndex+1]; 3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(valueMapIndex==0) { 3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return UProperty.UNDEFINED; 3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // valueMapIndex is the start of the property's valueMap, 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // where the first word is the BytesTrie offset. 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getPropertyOrValueEnum(valueMaps[valueMapIndex], alias); 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Compare two property names, returning <0, 0, or >0. The 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * comparison is that described as "loose" matching in the 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Property*Aliases.txt files. 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static int compare(String stra, String strb) { 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: This implementation is a literal copy of 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // uprv_comparePropertyNames. It can probably be improved. 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int istra=0, istrb=0, rc; 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int cstra=0, cstrb=0; 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (;;) { 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* Ignore delimiters '-', '_', and ASCII White_Space */ 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (istra<stra.length()) { 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cstra = stra.charAt(istra); 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (cstra) { 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case '-': case '_': case ' ': case '\t': 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case '\n': case 0xb/*\v*/: case '\f': case '\r': 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ++istra; 3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (istrb<strb.length()) { 3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cstrb = strb.charAt(istrb); 3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (cstrb) { 3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case '-': case '_': case ' ': case '\t': 3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case '\n': case 0xb/*\v*/: case '\f': case '\r': 3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ++istrb; 3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* If we reach the ends of both strings then they match */ 3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean endstra = istra==stra.length(); 3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean endstrb = istrb==strb.length(); 3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (endstra) { 3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (endstrb) return 0; 3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cstra = 0; 3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (endstrb) { 3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cstrb = 0; 3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rc = asciiToLowercase(cstra) - asciiToLowercase(cstrb); 3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (rc != 0) { 3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rc; 3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ++istra; 3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ++istrb; 3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 381