org.apache.fop.fo.expr.PropertyTokenizer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.fop Show documentation
Show all versions of org.apache.fop Show documentation
The core maven build properties
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id: PropertyTokenizer.java 1617052 2014-08-10 06:55:01Z gadams $ */
package org.apache.fop.fo.expr;
/**
* Class to tokenize XSL FO property expression.
* This class is heavily based on the epxression tokenizer in James Clark's
* XT, an XSLT processor.
*/
class PropertyTokenizer {
static final int TOK_EOF = 0;
static final int TOK_NCNAME = 1;
static final int TOK_MULTIPLY = TOK_NCNAME + 1;
static final int TOK_LPAR = TOK_MULTIPLY + 1;
static final int TOK_RPAR = TOK_LPAR + 1;
static final int TOK_LITERAL = TOK_RPAR + 1;
static final int TOK_NUMBER = TOK_LITERAL + 1;
static final int TOK_FUNCTION_LPAR = TOK_NUMBER + 1;
static final int TOK_PLUS = TOK_FUNCTION_LPAR + 1;
static final int TOK_MINUS = TOK_PLUS + 1;
static final int TOK_MOD = TOK_MINUS + 1;
static final int TOK_DIV = TOK_MOD + 1;
static final int TOK_NUMERIC = TOK_DIV + 1;
static final int TOK_COMMA = TOK_NUMERIC + 1;
static final int TOK_PERCENT = TOK_COMMA + 1;
static final int TOK_COLORSPEC = TOK_PERCENT + 1;
static final int TOK_FLOAT = TOK_COLORSPEC + 1;
static final int TOK_INTEGER = TOK_FLOAT + 1;
protected int currentToken = TOK_EOF;
protected String currentTokenValue;
protected int currentUnitLength;
private int currentTokenStartIndex;
private /* final */ String expr;
private int exprIndex;
private int exprLength;
/**
* Construct a new PropertyTokenizer object to tokenize the passed
* String.
* @param s The Property expressio to tokenize.
*/
PropertyTokenizer(String s) {
this.expr = s;
this.exprLength = s.length();
}
/**
* Parse the next token in the expression string.
* This sets the following package visible variables:
* currentToken An enumerated value identifying the recognized token
* currentTokenValue A String containing the token contents
* currentUnitLength If currentToken = TOK_NUMERIC, the number of
* characters in the unit name.
* @throws PropertyException If un unrecognized token is encountered.
*/
void next() throws PropertyException {
currentTokenValue = null;
currentTokenStartIndex = exprIndex;
boolean bSawDecimal;
while (true) {
if (exprIndex >= exprLength) {
currentToken = TOK_EOF;
return;
}
char c = expr.charAt(exprIndex++);
switch (c) {
case ' ':
case '\t':
case '\r':
case '\n':
currentTokenStartIndex = exprIndex;
break;
case ',':
currentToken = TOK_COMMA;
return;
case '+':
currentToken = TOK_PLUS;
return;
case '-':
currentToken = TOK_MINUS;
return;
case '(':
currentToken = TOK_LPAR;
return;
case ')':
currentToken = TOK_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 = TOK_LITERAL;
return;
case '*':
/*
* if (currentMaybeOperator) {
* recognizeOperator = false;
*/
currentToken = TOK_MULTIPLY;
/*
* }
* else
* throw new PropertyException("illegal operator *");
*/
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;
}
if (exprIndex < exprLength && expr.charAt(exprIndex) == '%') {
exprIndex++;
currentToken = TOK_PERCENT;
} else {
// Check for possible unit name following number
currentUnitLength = exprIndex;
scanName();
currentUnitLength = exprIndex - currentUnitLength;
currentToken = (currentUnitLength > 0) ? TOK_NUMERIC
: (bSawDecimal ? TOK_FLOAT : TOK_INTEGER);
}
currentTokenValue = expr.substring(currentTokenStartIndex,
exprIndex);
return;
case '.':
nextDecimalPoint();
return;
case '#': // Start of color value
nextColor();
return;
default:
--exprIndex;
scanName();
if (exprIndex == currentTokenStartIndex) {
throw new PropertyException("illegal character");
}
currentTokenValue = expr.substring(currentTokenStartIndex, exprIndex);
if (currentTokenValue.equals("mod")) {
currentToken = TOK_MOD;
return;
} else if (currentTokenValue.equals("div")) {
currentToken = TOK_DIV;
return;
}
if (followingParen()) {
currentToken = TOK_FUNCTION_LPAR;
} else {
currentToken = TOK_NCNAME;
}
return;
}
}
}
private void nextDecimalPoint() throws PropertyException {
if (exprIndex < exprLength
&& isDigit(expr.charAt(exprIndex))) {
++exprIndex;
scanDigits();
if (exprIndex < exprLength
&& expr.charAt(exprIndex) == '%') {
exprIndex++;
currentToken = TOK_PERCENT;
} else {
// Check for possible unit name following number
currentUnitLength = exprIndex;
scanName();
currentUnitLength = exprIndex - currentUnitLength;
currentToken = (currentUnitLength > 0) ? TOK_NUMERIC
: TOK_FLOAT;
}
currentTokenValue = expr.substring(currentTokenStartIndex,
exprIndex);
return;
}
throw new PropertyException("illegal character '.'");
}
private void nextColor() throws PropertyException {
if (exprIndex < exprLength) {
++exprIndex;
scanHexDigits();
int len = exprIndex - currentTokenStartIndex - 1;
if (len % 3 == 0) {
currentToken = TOK_COLORSPEC;
} else {
//Actually not a color at all, but an NCNAME starting with "#"
scanRestOfName();
currentToken = TOK_NCNAME;
}
currentTokenValue = expr.substring(currentTokenStartIndex,
exprIndex);
return;
} else {
throw new PropertyException("illegal character '#'");
}
}
/**
* Attempt to recognize a valid NAME token in the input expression.
*/
private void scanName() {
if (exprIndex < exprLength && isNameStartChar(expr.charAt(exprIndex))) {
scanRestOfName();
}
}
private void scanRestOfName() {
while (++exprIndex < exprLength) {
if (!isNameChar(expr.charAt(exprIndex))) {
break;
}
}
}
/**
* Attempt to recognize a valid sequence of decimal DIGITS in the
* input expression.
*/
private void scanDigits() {
while (exprIndex < exprLength && isDigit(expr.charAt(exprIndex))) {
exprIndex++;
}
}
/**
* Attempt to recognize a valid sequence of hexadecimal DIGITS in the
* input expression.
*/
private void scanHexDigits() {
while (exprIndex < exprLength && isHexDigit(expr.charAt(exprIndex))) {
exprIndex++;
}
}
/**
* Return a boolean value indicating whether the following non-whitespace
* character is an opening parenthesis.
*/
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;
}
private static final String NAME_START_CHARS
= "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String NAME_CHARS = ".-0123456789";
private static final String DIGITS = "0123456789";
private static final String HEX_CHARS = DIGITS + "abcdefABCDEF";
/**
* Return a boolean value indicating whether the argument is a
* decimal digit (0-9).
* @param c The character to check
*/
private static boolean isDigit(char c) {
return DIGITS.indexOf(c) >= 0;
}
/**
* Return a boolean value indicating whether the argument is a
* hexadecimal digit (0-9, A-F, a-f).
* @param c The character to check
*/
private static boolean isHexDigit(char c) {
return HEX_CHARS.indexOf(c) >= 0;
}
/**
* Return a boolean value indicating whether the argument is whitespace
* as defined by XSL (space, newline, CR, tab).
* @param c The character to check
*/
/* not used
private static boolean isSpace(char c) {
switch (c) {
case ' ':
case '\r':
case '\n':
case '\t':
return true;
default:
return false;
}
}
*/
/**
* Return a boolean value indicating whether the argument is a valid name
* start character, ie. can start a NAME as defined by XSL.
* @param c The character to check
*/
private static boolean isNameStartChar(char c) {
return NAME_START_CHARS.indexOf(c) >= 0 || c >= 0x80;
}
/**
* Return a boolean value indicating whether the argument is a valid name
* character, ie. can occur in a NAME as defined by XSL.
* @param c The character to check
*/
private static boolean isNameChar(char c) {
return NAME_START_CHARS.indexOf(c) >= 0 || NAME_CHARS.indexOf(c) >= 0
|| c >= 0x80;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy