private static int parseClass(char[] data, int i, int out, BlockSet bs,
                                  boolean icase, boolean skipspaces,
                                  boolean unicode, boolean xml) throws PatternSyntaxException {
        char c;
        int prev = -1, oct = 0;
        boolean isFirst = true, setFirst = false, inRange = false;
        BlockSet bs1 = null;
        StringBuilder sb = null;

        for (; i < out; isFirst = setFirst, setFirst = false) {
            handle_special:
            switch (c = data[i++]) {
                case ']':
                    if (isFirst) break; //treat as normal char
                    if (inRange) {
                        bs.setChar('-');
                    }
                    if (prev >= 0) {
                        char c1 = (char) prev;
                        if (icase) {
                            /*
                            bs.setChar(Character.toLowerCase(c1));
                            bs.setChar(Character.toUpperCase(c1));
                            bs.setChar(Character.toTitleCase(c1));
                            */
                            bs.setChar(Category.caseFold(c1));
                        } else bs.setChar(c1);
                    }
                    return i;

                case '-':
                    if (isFirst) break;
                    //if(isFirst) throw new PatternSyntaxException("[-...] is illegal");
                    if (inRange) break;
                    //if(inRange) throw new PatternSyntaxException("[...--...] is illegal");
                    inRange = true;
                    continue;

                case '[':
                    if (inRange && xml) { //[..-[..]]
                        if (prev >= 0) bs.setChar((char) prev);
                        if (bs1 == null) bs1 = new BlockSet();
                        else bs1.reset();
                        i = parseClass(data, i, out, bs1, icase, skipspaces, unicode, xml);
                        bs.subtract(bs1);
                        inRange = false;
                        prev = -1;
                        continue;
                    } else break;

                case '^':
                    //if(!isFirst) throw new PatternSyntaxException("'^' isn't a first char in a class def");
                    //bs.setPositive(false);
                    //setFirst=true;
                    //continue;
                    if (isFirst) {
                        bs.setPositive(false);
                        setFirst = true;
                        continue;
                    }
                    //treat as normal char
                    break;

                case ' ':
                case '\r':
                case '\n':
                case '\t':
                case '\f':
                    if (skipspaces) continue;
                    else break;
                case '\\':
                    BlockSet negativeClass = null;
                    boolean inv = false;
                    switch (c = data[i++]) {
                        case 'r':
                            c = '\r';
                            break handle_special;

                        case 'n':
                            c = '\n';
                            break handle_special;

                        case 't':
                            c = '\t';
                            break handle_special;

                        case 'f':
                            c = '\f';
                            break handle_special;

                        case 'u':
                            if (i >= out - 4) throw new PatternSyntaxException("incomplete escape sequence \\uXXXX");
                            c = (char) ((toHexDigit(data[i++]) << 12)
                                    + (toHexDigit(data[i++]) << 8)
                                    + (toHexDigit(data[i++]) << 4)
                                    + toHexDigit(data[i++]));
                            break handle_special;

                        case 'b':
                            c = 8; // backspace
                            break handle_special;

                        case 'x': {   // hex 2-digit number
                            int hex = 0;
                            char d;
                            if ((d = data[i++]) == '{') {
                                while (i < out && (d = data[i++]) != '}') {
                                    hex = (hex << 4) + toHexDigit(d);
                                }
                                if (hex > 0xffff || i == out)
                                    throw new PatternSyntaxException("\\x{<out of range or incomplete>}");
                            } else {
                                if(i >= out - 2) throw new PatternSyntaxException("incomplete escape sequence \\xHH");
                                hex = (toHexDigit(d) << 4) + toHexDigit(data[i++]);
                            }
                            c = (char) hex;
                            break handle_special;
                        }
                        case 'o':   // oct 2- or 3-digit number
                            oct = 0;
                            for (; ; ) {
                                char d = data[i++];
                                if (d >= '0' && d <= '7') {
                                    oct *= 8;
                                    oct += d - '0';
                                    if (oct > 0xffff){
                                        oct -= d - '0';
                                        oct /= 8;
                                        break;
                                    }
                                } else break;
                            }
                            c = (char) oct;
                            break handle_special;
                        case '0':
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                            oct = 0;
                            for (; ; ) {
                                char d = data[i - 1];
                                if (d >= '0' && d <= '7') {
                                    i++;
                                    oct *= 8;
                                    oct += d - '0';
                                    if (oct > 0xffff){
                                        oct -= d - '0';
                                        oct /= 8;
                                        break;
                                    }
                                } else {
                                    i--;
                                    break;
                                }
                            }
                            c = (char) oct;
                            break handle_special;

                        case 'm':   // decimal number -> char
                            int dec = 0;
                            for (; ; ) {
                                char d = data[i++];
                                if (d >= '0' && d <= '9') {
                                    dec *= 10;
                                    dec += d - '0';
                                    if (dec > 0xffff) {
                                        dec -= d - '0';
                                        dec /= 10;
                                        break;
                                    }
                                } else break;
                            }
                            c = (char) dec;
                            break handle_special;

                        case 'c':   // ctrl-char
                            c = (char) (data[i++] & 0x1f);
                            break handle_special;

                        //classes;
                        //
                        case 'D':   // non-digit
                            negativeClass = unicode ? UNONDIGIT : NONDIGIT;
                            break;

                        case 'S':   // space
                            negativeClass = unicode ? UNONSPACE : NONSPACE;
                            break;

                        case 'W':   // space
                            negativeClass = unicode ? UNONWORDCHAR : NONWORDCHAR;
                            break;

                        case 'd':   // digit
                            if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\d...]");
                            bs.setDigit(unicode);
                            continue;

                        case 's':   // digit
                            if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\s...]");
                            bs.setSpace(unicode);
                            continue;

                        case 'w':   // digit
                            if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\w...]");
                            bs.setWordChar(unicode);
                            continue;

                        case 'h':   // horizontal whitespace
                            if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\w...]");
                            bs.setHorizontalSpace(unicode);
                            continue;

                        case 'v':   // vertical whitespace
                            if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\w...]");
                            bs.setVerticalSpace(unicode);
                            continue;

                        case 'P':   // \\P{..}
                            if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\P...]");
                            inv = true;
                        case 'p':   // \\p{..}
                            if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\p...]");
                            if (sb == null) sb = new StringBuilder();
                            else sb.setLength(0);
                            i = parseName(data, i, out, sb, skipspaces);
                            BlockSet nc = getNamedClass(sb.toString());
                            if (nc == null) throw new PatternSyntaxException("unknown named class: {" + sb + "}");
                            bs.add(nc, inv);
                            continue;
                        case 'Q':
                        case 'E':
                            throw new PatternSyntaxException("Escaped \\Q\\E literals cannot be inside character classes");
                        default:
                            //other escaped treat as normal
                            break handle_special;
                    }
                    //negativeClass;
                    //\S,\D,\W
                    if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\" + c + "...]");
                    bs.add(negativeClass);
                    continue;

                    /*
                case '{':
                    if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\w...]");
                    if (sb == null) sb = new StringBuilder();
                    else sb.setLength(0);
                    i = parseName(data, i - 1, out, sb, skipspaces);
                    BlockSet nc = getNamedClass(sb.toString());
                    if (nc == null) throw new PatternSyntaxException("unknown named class: {" + sb + "}");
                    bs.add(nc, false);
                    continue;
                    */
                default:
            }
            //c is a normal char
            if (prev < 0) {
                prev = c;
                inRange = false;
                continue;
            }
            if (!inRange) {
                char c1 = (char) prev;
                if (icase) {
                    /*
                    bs.setChar(Character.toLowerCase(c1));
                    bs.setChar(Character.toUpperCase(c1));
                    bs.setChar(Character.toTitleCase(c1));
                    */
                    bs.setChar(Category.caseFold(c1));
                } else bs.setChar(c1);
                prev = c;
            } else {
                if (prev > c)
                    throw new PatternSyntaxException("illegal range: " + prev + ">" + c);
                char c0 = (char) prev;
                inRange = false;
                prev = -1;
                if (icase) {
                    /*
                    bs.setRange(Character.toLowerCase(c0), Character.toLowerCase(c));
                    bs.setRange(Character.toUpperCase(c0), Character.toUpperCase(c));
                    bs.setRange(Character.toTitleCase(c0), Character.toTitleCase(c));
                    */
                    bs.setRange(Category.caseFold(c0), Category.caseFold(c));

                } else bs.setRange(c0, c);
            }
        }
        throw new PatternSyntaxException("unbalanced brackets in a class def");
    }
private static int parseClass ( char [ ] data , int i , int out , BlockSet bs , boolean icase , boolean skipspaces , boolean unicode , boolean xml ) throws PatternSyntaxException { char c ; int prev = - 1 , oct = 0 ; boolean isFirst = true , setFirst = false , inRange = false ; BlockSet bs1 = null ; StringBuilder sb = null ; for ( ; i < out ; isFirst = setFirst , setFirst = false ) { handle_special : switch ( c = data [ i ++ ] ) { case ']' : if ( isFirst ) break ; if ( inRange ) { bs . setChar ( '-' ) ; } if ( prev >= 0 ) { char c1 = ( char ) prev ; if ( icase ) { bs . setChar ( Category . caseFold ( c1 ) ) ; } else bs . setChar ( c1 ) ; } return i ; case '-' : if ( isFirst ) break ; if ( inRange ) break ; inRange = true ; continue ; case '[' : if ( inRange && xml ) { if ( prev >= 0 ) bs . setChar ( ( char ) prev ) ; if ( bs1 == null ) bs1 = new BlockSet ( ) ; else bs1 . reset ( ) ; i = parseClass ( data , i , out , bs1 , icase , skipspaces , unicode , xml ) ; bs . subtract ( bs1 ) ; inRange = false ; prev = - 1 ; continue ; } else break ; case '^' : if ( isFirst ) { bs . setPositive ( false ) ; setFirst = true ; continue ; } break ; case ' ' : case '\r' : case '\n' : case '\t' : case '\f' : if ( skipspaces ) continue ; else break ; case '\\' : BlockSet negativeClass = null ; boolean inv = false ; switch ( c = data [ i ++ ] ) { case 'r' : c = '\r' ; break handle_special ; case 'n' : c = '\n' ; break handle_special ; case 't' : c = '\t' ; break handle_special ; case 'f' : c = '\f' ; break handle_special ; case 'u' : if ( i >= out - 4 ) throw new PatternSyntaxException ( "incomplete escape sequence \\uXXXX" ) ; c = ( char ) ( ( toHexDigit ( data [ i ++ ] ) << 12 ) + ( toHexDigit ( data [ i ++ ] ) << 8 ) + ( toHexDigit ( data [ i ++ ] ) << 4 ) + toHexDigit ( data [ i ++ ] ) ) ; break handle_special ; case 'b' : c = 8 ; break handle_special ; case 'x' : { int hex = 0 ; char d ; if ( ( d = data [ i ++ ] ) == '{' ) { while ( i < out && ( d = data [ i ++ ] ) != '}' ) { hex = ( hex << 4 ) + toHexDigit ( d ) ; } if ( hex > 0xffff || i == out ) throw new PatternSyntaxException ( "\\x{<out of range or incomplete>}" ) ; } else { if ( i >= out - 2 ) throw new PatternSyntaxException ( "incomplete escape sequence \\xHH" ) ; hex = ( toHexDigit ( d ) << 4 ) + toHexDigit ( data [ i ++ ] ) ; } c = ( char ) hex ; break handle_special ; } case 'o' : oct = 0 ; for ( ; ; ) { char d = data [ i ++ ] ; if ( d >= '0' && d <= '7' ) { oct *= 8 ; oct += d - '0' ; if ( oct > 0xffff ) { oct -= d - '0' ; oct /= 8 ; break ; } } else break ; } c = ( char ) oct ; break handle_special ; case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : oct = 0 ; for ( ; ; ) { char d = data [ i - 1 ] ; if ( d >= '0' && d <= '7' ) { i ++ ; oct *= 8 ; oct += d - '0' ; if ( oct > 0xffff ) { oct -= d - '0' ; oct /= 8 ; break ; } } else { i -- ; break ; } } c = ( char ) oct ; break handle_special ; case 'm' : int dec = 0 ; for ( ; ; ) { char d = data [ i ++ ] ; if ( d >= '0' && d <= '9' ) { dec *= 10 ; dec += d - '0' ; if ( dec > 0xffff ) { dec -= d - '0' ; dec /= 10 ; break ; } } else break ; } c = ( char ) dec ; break handle_special ; case 'c' : c = ( char ) ( data [ i ++ ] & 0x1f ) ; break handle_special ; case 'D' : negativeClass = unicode ? UNONDIGIT : NONDIGIT ; break ; case 'S' : negativeClass = unicode ? UNONSPACE : NONSPACE ; break ; case 'W' : negativeClass = unicode ? UNONWORDCHAR : NONWORDCHAR ; break ; case 'd' : if ( inRange ) throw new PatternSyntaxException ( "illegal range: [..." + prev + "-\\d...]" ) ; bs . setDigit ( unicode ) ; continue ; case 's' : if ( inRange ) throw new PatternSyntaxException ( "illegal range: [..." + prev + "-\\s...]" ) ; bs . setSpace ( unicode ) ; continue ; case 'w' : if ( inRange ) throw new PatternSyntaxException ( "illegal range: [..." + prev + "-\\w...]" ) ; bs . setWordChar ( unicode ) ; continue ; case 'h' : if ( inRange ) throw new PatternSyntaxException ( "illegal range: [..." + prev + "-\\w...]" ) ; bs . setHorizontalSpace ( unicode ) ; continue ; case 'v' : if ( inRange ) throw new PatternSyntaxException ( "illegal range: [..." + prev + "-\\w...]" ) ; bs . setVerticalSpace ( unicode ) ; continue ; case 'P' : if ( inRange ) throw new PatternSyntaxException ( "illegal range: [..." + prev + "-\\P...]" ) ; inv = true ; case 'p' : if ( inRange ) throw new PatternSyntaxException ( "illegal range: [..." + prev + "-\\p...]" ) ; if ( sb == null ) sb = new StringBuilder ( ) ; else sb . setLength ( 0 ) ; i = parseName ( data , i , out , sb , skipspaces ) ; BlockSet nc = getNamedClass ( sb . toString ( ) ) ; if ( nc == null ) throw new PatternSyntaxException ( "unknown named class: {" + sb + "}" ) ; bs . add ( nc , inv ) ; continue ; case 'Q' : case 'E' : throw new PatternSyntaxException ( "Escaped \\Q\\E literals cannot be inside character classes" ) ; default : break handle_special ; } if ( inRange ) throw new PatternSyntaxException ( "illegal range: [..." + prev + "-\\" + c + "...]" ) ; bs . add ( negativeClass ) ; continue ; default : } if ( prev < 0 ) { prev = c ; inRange = false ; continue ; } if ( ! inRange ) { char c1 = ( char ) prev ; if ( icase ) { bs . setChar ( Category . caseFold ( c1 ) ) ; } else bs . setChar ( c1 ) ; prev = c ; } else { if ( prev > c ) throw new PatternSyntaxException ( "illegal range: " + prev + ">" + c ) ; char c0 = ( char ) prev ; inRange = false ; prev = - 1 ; if ( icase ) { bs . setRange ( Category . caseFold ( c0 ) , Category . caseFold ( c ) ) ; } else bs . setRange ( c0 , c ) ; } } throw new PatternSyntaxException ( "unbalanced brackets in a class def" ) ; }
/*
@param mode add/subtract