* @return -1 when not match; offset of the end of matched string when match.
*/
private int matchCharacterIterator (Context con, Op op, int offset, int dx, int opts) {
CharacterIterator target = con.ciTarget;
while (true) {
if (op == null)
return isSet(opts, XMLSCHEMA_MODE) && offset != con.limit ? -1 : offset;
if (offset > con.limit || offset < con.start)
return -1;
switch (op.type) {
case Op.CHAR:
if (isSet(opts, IGNORE_CASE)) {
int ch = op.getData();
if (dx > 0) {
if (offset >= con.limit || !matchIgnoreCase(ch, target .setIndex( offset ) ))
return -1;
offset ++;
} else {
int o1 = offset-1;
if (o1 >= con.limit || o1 < 0 || !matchIgnoreCase(ch, target .setIndex( o1 ) ))
return -1;
offset = o1;
}
} else {
int ch = op.getData();
if (dx > 0) {
if (offset >= con.limit || ch != target .setIndex( offset ) )
return -1;
offset ++;
} else {
int o1 = offset-1;
if (o1 >= con.limit || o1 < 0 || ch != target .setIndex( o1 ) )
return -1;
offset = o1;
}
}
op = op.next;
break;
case Op.DOT:
if (dx > 0) {
if (offset >= con.limit)
return -1;
int ch = target .setIndex( offset ) ;
if (isSet(opts, SINGLE_LINE)) {
if (REUtil.isHighSurrogate(ch) && offset+1 < con.limit)
offset ++;
} else {
if (REUtil.isHighSurrogate(ch) && offset+1 < con.limit)
ch = REUtil.composeFromSurrogates(ch, target .setIndex( ++offset ) );
if (isEOLChar(ch))
return -1;
}
offset ++;
} else {
int o1 = offset-1;
if (o1 >= con.limit || o1 < 0)
return -1;
int ch = target .setIndex( o1 ) ;
if (isSet(opts, SINGLE_LINE)) {
if (REUtil.isLowSurrogate(ch) && o1-1 >= 0)
o1 --;
} else {
if (REUtil.isLowSurrogate(ch) && o1-1 >= 0)
ch = REUtil.composeFromSurrogates( target .setIndex( --o1 ) , ch);
if (!isEOLChar(ch))
return -1;
}
offset = o1;
}
op = op.next;
break;
case Op.RANGE:
case Op.NRANGE:
if (dx > 0) {
if (offset >= con.limit)
return -1;
int ch = target .setIndex( offset ) ;
if (REUtil.isHighSurrogate(ch) && offset+1 < con.limit)
ch = REUtil.composeFromSurrogates(ch, target .setIndex( ++offset ) );
RangeToken tok = op.getToken();
if (isSet(opts, IGNORE_CASE)) {
tok = tok.getCaseInsensitiveToken();
if (!tok.match(ch)) {
if (ch >= 0x10000) return -1;
char uch;
if (!tok.match(uch = Character.toUpperCase((char)ch))
&& !tok.match(Character.toLowerCase(uch)))
return -1;
}
} else {
if (!tok.match(ch)) return -1;
}
offset ++;
} else {
int o1 = offset-1;
if (o1 >= con.limit || o1 < 0)
return -1;
int ch = target .setIndex( o1 ) ;
if (REUtil.isLowSurrogate(ch) && o1-1 >= 0)
ch = REUtil.composeFromSurrogates( target .setIndex( --o1 ) , ch);
RangeToken tok = op.getToken();
if (isSet(opts, IGNORE_CASE)) {
tok = tok.getCaseInsensitiveToken();
if (!tok.match(ch)) {
if (ch >= 0x10000) return -1;
char uch;
if (!tok.match(uch = Character.toUpperCase((char)ch))
&& !tok.match(Character.toLowerCase(uch)))
return -1;
}
} else {
if (!tok.match(ch)) return -1;
}
offset = o1;
}
op = op.next;
break;
case Op.ANCHOR:
boolean go = false;
switch (op.getData()) {
case '^':
if (isSet(opts, MULTIPLE_LINES)) {
if (!(offset == con.start
|| offset > con.start && isEOLChar( target .setIndex( offset-1 ) )))
return -1;
} else {
if (offset != con.start)
return -1;
}
break;
case '@': // Internal use only.
// The @ always matches line beginnings.
if (!(offset == con.start
|| offset > con.start && isEOLChar( target .setIndex( offset-1 ) )))
return -1;
break;
case '$':
if (isSet(opts, MULTIPLE_LINES)) {
if (!(offset == con.limit
|| offset < con.limit && isEOLChar( target .setIndex( offset ) )))
return -1;
} else {
if (!(offset == con.limit
|| offset+1 == con.limit && isEOLChar( target .setIndex( offset ) )
|| offset+2 == con.limit && target .setIndex( offset ) == CARRIAGE_RETURN
&& target .setIndex( offset+1 ) == LINE_FEED))
return -1;
}
break;
case 'A':
if (offset != con.start) return -1;
break;
case 'Z':
if (!(offset == con.limit
|| offset+1 == con.limit && isEOLChar( target .setIndex( offset ) )
|| offset+2 == con.limit && target .setIndex( offset ) == CARRIAGE_RETURN
&& target .setIndex( offset+1 ) == LINE_FEED))
return -1;
break;
case 'z':
if (offset != con.limit) return -1;