package org.apache.fop.fo.expr;
import org.apache.fop.datatypes.Numeric;
import org.apache.fop.datatypes.Length;
import org.apache.fop.datatypes.Frequency;
import org.apache.fop.datatypes.Time;
class PropertyTokenizer {
private static final String tag = "$Name$";
private static final String revision = "$Revision$";
a
static final int
EOF = 0
,NCNAME = 1
,MULTIPLY = 2
,LPAR = 3
,RPAR = 4
,LITERAL = 5
,FUNCTION_LPAR = 6
,PLUS = 7
,MINUS = 8
,MOD = 9
,DIV = 10
,COMMA = 11
,PERCENT = 12
,COLORSPEC = 13
,FLOAT = 14
,INTEGER = 15
,ABSOLUTE_LENGTH = 16
,RELATIVE_LENGTH = 17
,TIME = 18
,FREQ = 19
,ANGLE = 20
,INHERIT = 21
,AUTO = 22
,NONE = 23
,BOOL = 24
,URI = 25
,MIMETYPE = 26
,SLASH = 27
,NO_UNIT = 28
;
int currentToken = EOF;
String currentTokenValue = null;
protected int currentUnitIndex = 0;
protected int currentUnit;
protected String unitString;
protected String uri;
private int currentTokenStartIndex = 0;
private String expr = null;
private int exprIndex = 0;
private int exprLength;
protected int property;
protected PropertyTokenizer() {}
@paramproperty@params
protected void initialize(int property, String s) {
expr = s;
exprLength = s.length();
this.property = property;
}
protected void reset() {
expr = null;
exprIndex = 0;
exprLength = 0;
currentToken = EOF;
currentTokenValue = null;
property = 0;
}
@return
public String getExpr() {
return expr;
}
@throwsPropertyException
void next() throws PropertyException {
currentTokenValue = null;
currentTokenStartIndex = exprIndex;
boolean bSawDecimal;
for (; ; ) {
if (exprIndex >= exprLength) {
currentToken = EOF;
return;
}
char c = expr.charAt(exprIndex++);
switch (c) {
case ' ':
case '\t':
case '\r':
case '\n':
currentTokenStartIndex = exprIndex;
break;
case ',':
currentToken = COMMA;
return;
case '+':
currentToken = PLUS;
return;
case '-':
currentToken = MINUS;
return;
case '(':
currentToken = LPAR;
return;
case ')':
currentToken = RPAR;
return;
case '"':
case '\'':
exprIndex = expr.indexOf(c, exprIndex);
if (exprIndex < 0) {
exprIndex = currentTokenStartIndex + 1;
throw new PropertyException("missing quote");
}
currentTokenValue = expr.substring(currentTokenStartIndex
+ 1, exprIndex++);
currentToken = LITERAL;
return;
case '*':
currentToken = MULTIPLY;
return;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
scanDigits();
if (exprIndex < exprLength && expr.charAt(exprIndex) == '.') {
exprIndex++;
bSawDecimal = true;
if (exprIndex < exprLength
&& isDigit(expr.charAt(exprIndex))) {
exprIndex++;
scanDigits();
}
} else
bSawDecimal = false;
currentUnitIndex = exprIndex;
if (exprIndex < exprLength && expr.charAt(exprIndex) == '%') {
currentToken = PERCENT;
unitString = "%";
exprIndex++;
} else {
currentToken = scanUnitName();
if (currentToken == NO_UNIT)
currentToken = bSawDecimal ? FLOAT : INTEGER;
}
currentTokenValue = expr.substring(currentTokenStartIndex,
currentUnitIndex);
return;
case '.':
if (exprIndex < exprLength
&& isDigit(expr.charAt(exprIndex))) {
++exprIndex;
scanDigits();
currentUnitIndex = exprIndex;
if (exprIndex < exprLength
&& expr.charAt(exprIndex) == '%') {
exprIndex++;
currentToken = PERCENT;
} else {
currentToken = scanUnitName();
if (currentToken == NO_UNIT)
currentToken = FLOAT;
}
currentTokenValue = expr.substring(currentTokenStartIndex,
currentUnitIndex);
return;
}
throw new PropertyException("illegal character '.'");
case '#': if (exprIndex < exprLength
&& isHexDigit(expr.charAt(exprIndex))) {
int len;
++exprIndex;
scanHexDigits();
currentToken = COLORSPEC;
currentTokenValue = expr.substring(currentTokenStartIndex,
exprIndex);
len = exprIndex - currentTokenStartIndex;
if (len == 4 || len == 7) return;
throw new PropertyException("color not 3 or 6 hex digits");
} else {
throw new PropertyException("illegal character '#'");
}
case '/':
currentToken = SLASH;
return;
default:
--exprIndex;
scanName();
if (exprIndex == currentTokenStartIndex)
throw new PropertyException
("illegal character '"
+ expr.charAt(exprIndex) + "'");
currentTokenValue = expr.substring(currentTokenStartIndex,
exprIndex);
if (currentTokenValue.equals("mod")) {
currentToken = MOD;
return;
}
if (currentTokenValue.equals("div")) {
currentToken = DIV;
return;
}
if (currentTokenValue.equals("inherit")) {
currentToken = INHERIT;
return;
}
if (currentTokenValue.equals("auto")) {
currentToken = AUTO;
return;
}
if (currentTokenValue.equals("none")) {
currentToken = NONE;
return;
}
if (currentTokenValue.equals("true")
|| currentTokenValue.equals("false")) {
currentToken = BOOL;
return;
}
if (currentTokenValue.equals("url")
&& expr.charAt(exprIndex) == '(') {
if (! scanUrl()) {
throw new PropertyException
("Invalid url expression :" +
expr.substring(exprIndex));
}
currentToken = URI;
return;
}
if (currentTokenValue.equals("content-type")) {
if (expr.charAt(exprIndex) == ':') {
int mimeptr = ++exprIndex;
scanMimeType();
currentToken = MIMETYPE;
currentTokenValue =
expr.substring(mimeptr, exprIndex);
return;
}
}
if (currentTokenValue.equals("namespace-prefix")) {
if (expr.charAt(exprIndex) == ':') {
int nsptr = ++exprIndex;
scanName(); currentToken = NCNAME;
currentTokenValue =
expr.substring(nsptr, exprIndex);
return;
}
}
if (followingParen()) {
currentToken = FUNCTION_LPAR;
} else {
currentToken = NCNAME;
}
return;
}
}
}
@return@exceptionPropertyException
private int scanUnitName() throws PropertyException {
currentUnitIndex = exprIndex;
scanName();
if (currentUnitIndex < exprIndex) {
unitString = expr.substring(currentUnitIndex, exprIndex);
if (unitString.equals("em")) return RELATIVE_LENGTH;
if (unitString.equals("cm")) {
currentUnit = Length.CM;
return ABSOLUTE_LENGTH;
}
if (unitString.equals("mm")) {
currentUnit = Length.MM;
return ABSOLUTE_LENGTH;
}
if (unitString.equals("in")) {
currentUnit = Length.IN;
return ABSOLUTE_LENGTH;
}
if (unitString.equals("pt")) {
currentUnit = Length.PT;
return ABSOLUTE_LENGTH;
}
if (unitString.equals("pc")) {
currentUnit = Length.PC;
return ABSOLUTE_LENGTH;
}
if (unitString.equals("px")) {
currentUnit = Length.PX;
return ABSOLUTE_LENGTH;
}
if (unitString.equals("s")) {
currentUnit = Time.SEC;
return TIME;
}
if (unitString.equals("ms")) {
currentUnit = Time.MSEC;
return TIME;
}
if (unitString.equals("Hz")) {
currentUnit = Frequency.HZ;
return FREQ;
}
if (unitString.equals("kHz")) {
currentUnit = Frequency.KHZ;
return FREQ;
}
throw new PropertyException
("NCName following a number is not a UnitName");
} else { return NO_UNIT;
}
}
private void scanName() {
if (exprIndex < exprLength && isNameStartChar(expr.charAt(exprIndex)))
while (++exprIndex < exprLength
&& isNameChar(expr.charAt(exprIndex)));
}
private void scanDigits() {
while (exprIndex < exprLength && isDigit(expr.charAt(exprIndex)))
exprIndex++;
}
private void scanWhitespace() {
while (exprIndex < exprLength && isSpace(expr.charAt(exprIndex)))
exprIndex++;
}
private void scanHexDigits() {
while (exprIndex < exprLength && isHexDigit(expr.charAt(exprIndex)))
exprIndex++;
}
private void scanMimeType() throws PropertyException {
int part1 = exprIndex;
scanName();
if (part1 != exprIndex) {
if (expr.charAt(exprIndex) == '/') {
int part2 = ++exprIndex;
scanName();
if (part2 != exprIndex)
return;
}
}
throw new PropertyException("Mime type expected; found:" +
expr.substring(part1));
}
@return
private boolean followingParen() {
for (int i = exprIndex; i < exprLength; i++) {
switch (expr.charAt(i)) {
case '(':
exprIndex = i + 1;
return true;
case ' ':
case '\r':
case '\n':
case '\t':
break;
default:
return false;
}
}
return false;
}
@returnuriexprIndex
private boolean scanUrl() {
char ch;
String str = expr.substring(exprIndex).trim();
if (str.charAt(str.length() - 1) != ')') return false;
str = str.substring(0, str.length() - 1).trim();
if ((ch = str.charAt(0)) == '"' || ch == '\'') {
if (str.charAt(str.length() - 1) != ch) return false;
str = str.substring(1, str.length() - 1);
}
uri = str.trim();
exprIndex = expr.length();
return true;
}
static private final String nameStartChars =
"_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static private final String nameChars = ".-0123456789";
static private final String digits = "0123456789";
static private final String hexchars = digits + "abcdefABCDEF";
@paramc
private static final boolean isDigit(char c) {
return digits.indexOf(c) >= 0;
}
@paramc
private static final boolean isHexDigit(char c) {
return hexchars.indexOf(c) >= 0;
}
@paramc
private static final boolean isSpace(char c) {
switch (c) {
case ' ':
case '\r':
case '\n':
case '\t':
return true;
}
return false;
}
@paramc
private static final boolean isNameStartChar(char c) {
return nameStartChars.indexOf(c) >= 0 || c >= 0x80;
}
@paramc
private static final boolean isNameChar(char c) {
return nameStartChars.indexOf(c) >= 0 || nameChars.indexOf(c) >= 0
|| c >= 0x80;
}
}