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