17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert******************************************************************************* 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* Copyright (C) 2003-2010, International Business Machines 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* Corporation and others. All Rights Reserved. 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert******************************************************************************* 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*/ 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl; 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.IDNA; 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.StringPrep; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.StringPrepParseException; 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.UCharacterIterator; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * IDNA2003 implementation code, moved out of com.ibm.icu.text.IDNA.java 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * while extending that class to support IDNA2008/UTS #46 as well. 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author Ram Viswanadha 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic final class IDNA2003 { 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* IDNA ACE Prefix is "xn--" */ 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static char[] ACE_PREFIX = new char[]{ 0x0078,0x006E,0x002d,0x002d } ; 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //private static final int ACE_PREFIX_LENGTH = ACE_PREFIX.length; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int MAX_LABEL_LENGTH = 63; 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int HYPHEN = 0x002D; 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int CAPITAL_A = 0x0041; 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int CAPITAL_Z = 0x005A; 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int LOWER_CASE_DELTA = 0x0020; 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int FULL_STOP = 0x002E; 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int MAX_DOMAIN_NAME_LENGTH = 255; 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The NamePrep profile object 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final StringPrep namePrep = StringPrep.getInstance(StringPrep.RFC3491_NAMEPREP); 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static boolean startsWithPrefix(StringBuffer src){ 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean startsWithPrefix = true; 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(src.length() < ACE_PREFIX.length){ 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int i=0; i<ACE_PREFIX.length;i++){ 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(toASCIILower(src.charAt(i)) != ACE_PREFIX[i]){ 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert startsWithPrefix = false; 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return startsWithPrefix; 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static char toASCIILower(char ch){ 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(CAPITAL_A <= ch && ch <= CAPITAL_Z){ 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (char)(ch + LOWER_CASE_DELTA); 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ch; 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static StringBuffer toASCIILower(CharSequence src){ 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer dest = new StringBuffer(); 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int i=0; i<src.length();i++){ 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert dest.append(toASCIILower(src.charAt(i))); 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return dest; 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static int compareCaseInsensitiveASCII(StringBuffer s1, StringBuffer s2){ 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char c1,c2; 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int rc; 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int i =0;/* no condition */;i++) { 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* If we reach the ends of both strings then they match */ 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(i == s1.length()) { 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert c1 = s1.charAt(i); 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert c2 = s2.charAt(i); 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* Case-insensitive comparison */ 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(c1!=c2) { 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rc=toASCIILower(c1)-toASCIILower(c2); 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(rc!=0) { 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rc; 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static int getSeparatorIndex(char[] src,int start, int limit){ 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(; start<limit;start++){ 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(isLabelSeparator(src[start])){ 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return start; 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we have not found the separator just return length 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return start; 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static int getSeparatorIndex(UCharacterIterator iter){ 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int currentIndex = iter.getIndex(); 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int separatorIndex = 0; 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int ch; 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while((ch=iter.next())!= UCharacterIterator.DONE){ 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(isLabelSeparator(ch)){ 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert separatorIndex = iter.getIndex(); 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert iter.setIndex(currentIndex); 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return separatorIndex; 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // reset index 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert iter.setIndex(currentIndex); 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we have not found the separator just return the length 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static boolean isLDHChar(int ch){ 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // high runner case 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(ch>0x007A){ 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //[\\u002D \\u0030-\\u0039 \\u0041-\\u005A \\u0061-\\u007A] 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if( (ch==0x002D) || 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (0x0030 <= ch && ch <= 0x0039) || 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (0x0041 <= ch && ch <= 0x005A) || 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (0x0061 <= ch && ch <= 0x007A) 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ){ 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Ascertain if the given code point is a label separator as 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * defined by the IDNA RFC 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param ch The code point to be ascertained 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return true if the char is a label separator 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 2.8 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static boolean isLabelSeparator(int ch){ 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch(ch){ 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 0x002e: 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 0x3002: 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 0xFF0E: 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 0xFF61: 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert default: 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static StringBuffer convertToASCII(UCharacterIterator src, int options) 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throws StringPrepParseException{ 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean[] caseFlags = null; 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the source contains all ascii codepoints 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean srcIsASCII = true; 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // assume the source contains all LDH codepoints 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean srcIsLDH = true; 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //get the options 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean useSTD3ASCIIRules = ((options & IDNA.USE_STD3_RULES) != 0); 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int ch; 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // step 1 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while((ch = src.next())!= UCharacterIterator.DONE){ 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(ch> 0x7f){ 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert srcIsASCII = false; 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int failPos = -1; 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert src.setToStart(); 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer processOut = null; 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // step 2 is performed only if the source contains non ASCII 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(!srcIsASCII){ 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // step 2 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert processOut = namePrep.prepare(src, options); 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }else{ 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert processOut = new StringBuffer(src.getText()); 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int poLen = processOut.length(); 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(poLen==0){ 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new StringPrepParseException("Found zero length lable after NamePrep.",StringPrepParseException.ZERO_LENGTH_LABEL); 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer dest = new StringBuffer(); 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // reset the variable to verify if output of prepare is ASCII or not 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert srcIsASCII = true; 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // step 3 & 4 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int j=0;j<poLen;j++ ){ 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ch=processOut.charAt(j); 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(ch > 0x7F){ 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert srcIsASCII = false; 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }else if(isLDHChar(ch)==false){ 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // here we do not assemble surrogates 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // since we know that LDH code points 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // are in the ASCII range only 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert srcIsLDH = false; 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert failPos = j; 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(useSTD3ASCIIRules == true){ 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // verify 3a and 3b 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if( srcIsLDH == false /* source contains some non-LDH characters */ 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || processOut.charAt(0) == HYPHEN 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || processOut.charAt(processOut.length()-1) == HYPHEN){ 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* populate the parseError struct */ 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(srcIsLDH==false){ 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new StringPrepParseException( "The input does not conform to the STD 3 ASCII rules", 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringPrepParseException.STD3_ASCII_RULES_ERROR, 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert processOut.toString(), 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (failPos>0) ? (failPos-1) : failPos); 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }else if(processOut.charAt(0) == HYPHEN){ 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new StringPrepParseException("The input does not conform to the STD 3 ASCII rules", 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringPrepParseException.STD3_ASCII_RULES_ERROR,processOut.toString(),0); 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }else{ 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new StringPrepParseException("The input does not conform to the STD 3 ASCII rules", 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringPrepParseException.STD3_ASCII_RULES_ERROR, 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert processOut.toString(), 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (poLen>0) ? poLen-1 : poLen); 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(srcIsASCII){ 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert dest = processOut; 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }else{ 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // step 5 : verify the sequence does not begin with ACE prefix 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(!startsWithPrefix(processOut)){ 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //step 6: encode the sequence with punycode 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert caseFlags = new boolean[poLen]; 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder punyout = Punycode.encode(processOut,caseFlags); 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // convert all codepoints to lower case ASCII 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer lowerOut = toASCIILower(punyout); 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //Step 7: prepend the ACE prefix 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert dest.append(ACE_PREFIX,0,ACE_PREFIX.length); 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //Step 6: copy the contents in b2 into dest 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert dest.append(lowerOut); 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }else{ 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new StringPrepParseException("The input does not start with the ACE Prefix.", 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringPrepParseException.ACE_PREFIX_ERROR,processOut.toString(),0); 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(dest.length() > MAX_LABEL_LENGTH){ 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new StringPrepParseException("The labels in the input are too long. Length > 63.", 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringPrepParseException.LABEL_TOO_LONG_ERROR,dest.toString(),0); 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return dest; 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static StringBuffer convertIDNToASCII(String src,int options) 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throws StringPrepParseException{ 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char[] srcArr = src.toCharArray(); 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer result = new StringBuffer(); 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int sepIndex=0; 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int oldSepIndex=0; 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(;;){ 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert sepIndex = getSeparatorIndex(srcArr,sepIndex,srcArr.length); 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String label = new String(srcArr,oldSepIndex,sepIndex-oldSepIndex); 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //make sure this is not a root label separator. 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(!(label.length()==0 && sepIndex==srcArr.length)){ 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UCharacterIterator iter = UCharacterIterator.getInstance(label); 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(convertToASCII(iter,options)); 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(sepIndex==srcArr.length){ 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // increment the sepIndex to skip past the separator 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert sepIndex++; 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert oldSepIndex = sepIndex; 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append((char)FULL_STOP); 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(result.length() > MAX_DOMAIN_NAME_LENGTH){ 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new StringPrepParseException("The output exceed the max allowed length.", StringPrepParseException.DOMAIN_NAME_TOO_LONG_ERROR); 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static StringBuffer convertToUnicode(UCharacterIterator src, int options) 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throws StringPrepParseException{ 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean[] caseFlags = null; 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the source contains all ascii codepoints 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean srcIsASCII = true; 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // assume the source contains all LDH codepoints 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //boolean srcIsLDH = true; 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //get the options 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //boolean useSTD3ASCIIRules = ((options & USE_STD3_RULES) != 0); 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //int failPos = -1; 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int ch; 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int saveIndex = src.getIndex(); 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // step 1: find out if all the codepoints in src are ASCII 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while((ch=src.next())!= UCharacterIterator.DONE){ 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(ch>0x7F){ 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert srcIsASCII = false; 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }/*else if((srcIsLDH = isLDHChar(ch))==false){ 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert failPos = src.getIndex(); 3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }*/ 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer processOut; 3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(srcIsASCII == false){ 3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // step 2: process the string 3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert src.setIndex(saveIndex); 3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert processOut = namePrep.prepare(src,options); 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (StringPrepParseException ex) { 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new StringBuffer(src.getText()); 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }else{ 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //just point to source 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert processOut = new StringBuffer(src.getText()); 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO: 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The RFC states that 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // <quote> 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ToUnicode never fails. If any step fails, then the original input 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // is returned immediately in that step. 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // </quote> 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //step 3: verify ACE Prefix 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(startsWithPrefix(processOut)){ 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer decodeOut = null; 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //step 4: Remove the ACE Prefix 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String temp = processOut.substring(ACE_PREFIX.length,processOut.length()); 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //step 5: Decode using punycode 3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert decodeOut = new StringBuffer(Punycode.decode(temp,caseFlags)); 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (StringPrepParseException e) { 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert decodeOut = null; 3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //step 6:Apply toASCII 3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (decodeOut != null) { 3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer toASCIIOut = convertToASCII(UCharacterIterator.getInstance(decodeOut), options); 3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //step 7: verify 3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(compareCaseInsensitiveASCII(processOut, toASCIIOut) !=0){ 3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// throw new StringPrepParseException("The verification step prescribed by the RFC 3491 failed", 3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// StringPrepParseException.VERIFICATION_ERROR); 3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert decodeOut = null; 3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //step 8: return output of step 5 3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (decodeOut != null) { 3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return decodeOut; 3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// }else{ 3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// // verify that STD3 ASCII rules are satisfied 3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// if(useSTD3ASCIIRules == true){ 3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// if( srcIsLDH == false /* source contains some non-LDH characters */ 3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// || processOut.charAt(0) == HYPHEN 3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// || processOut.charAt(processOut.length()-1) == HYPHEN){ 3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// 3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// if(srcIsLDH==false){ 3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// throw new StringPrepParseException("The input does not conform to the STD 3 ASCII rules", 3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// StringPrepParseException.STD3_ASCII_RULES_ERROR,processOut.toString(), 3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// (failPos>0) ? (failPos-1) : failPos); 3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// }else if(processOut.charAt(0) == HYPHEN){ 3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// throw new StringPrepParseException("The input does not conform to the STD 3 ASCII rules", 3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// StringPrepParseException.STD3_ASCII_RULES_ERROR, 3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// processOut.toString(),0); 3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// 3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// }else{ 3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// throw new StringPrepParseException("The input does not conform to the STD 3 ASCII rules", 3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// StringPrepParseException.STD3_ASCII_RULES_ERROR, 3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// processOut.toString(), 3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// processOut.length()); 3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// 3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// } 3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// } 3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// } 3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// // just return the source 3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// return new StringBuffer(src.getText()); 3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// } 3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new StringBuffer(src.getText()); 3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static StringBuffer convertIDNToUnicode(String src, int options) 4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throws StringPrepParseException{ 4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char[] srcArr = src.toCharArray(); 4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer result = new StringBuffer(); 4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int sepIndex=0; 4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int oldSepIndex=0; 4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(;;){ 4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert sepIndex = getSeparatorIndex(srcArr,sepIndex,srcArr.length); 4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String label = new String(srcArr,oldSepIndex,sepIndex-oldSepIndex); 4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(label.length()==0 && sepIndex!=srcArr.length ){ 4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new StringPrepParseException("Found zero length lable after NamePrep.",StringPrepParseException.ZERO_LENGTH_LABEL); 4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UCharacterIterator iter = UCharacterIterator.getInstance(label); 4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(convertToUnicode(iter,options)); 4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(sepIndex==srcArr.length){ 4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Unlike the ToASCII operation we don't normalize the label separators 4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(srcArr[sepIndex]); 4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // increment the sepIndex to skip past the separator 4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert sepIndex++; 4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert oldSepIndex =sepIndex; 4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(result.length() > MAX_DOMAIN_NAME_LENGTH){ 4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new StringPrepParseException("The output exceed the max allowed length.", StringPrepParseException.DOMAIN_NAME_TOO_LONG_ERROR); 4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static int compare(String s1, String s2, int options) throws StringPrepParseException{ 4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer s1Out = convertIDNToASCII(s1, options); 4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer s2Out = convertIDNToASCII(s2, options); 4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return compareCaseInsensitiveASCII(s1Out,s2Out); 4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 437