package org.apache.batik.css.parser;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.StringTokenizer;
import org.apache.batik.i18n.Localizable;
import org.apache.batik.i18n.LocalizableSupport;
import org.apache.batik.util.CSSConstants;
import org.apache.batik.util.ParsedURL;
import org.w3c.css.sac.CSSException;
import org.w3c.css.sac.CSSParseException;
import org.w3c.css.sac.Condition;
import org.w3c.css.sac.ConditionFactory;
import org.w3c.css.sac.DocumentHandler;
import org.w3c.css.sac.ErrorHandler;
import org.w3c.css.sac.InputSource;
import org.w3c.css.sac.LexicalUnit;
import org.w3c.css.sac.SACMediaList;
import org.w3c.css.sac.Selector;
import org.w3c.css.sac.SelectorFactory;
import org.w3c.css.sac.SelectorList;
import org.w3c.css.sac.SimpleSelector;
public class Parser implements ExtendedParser, Localizable {
public static final String BUNDLE_CLASSNAME =
"org.apache.batik.css.parser.resources.Messages";
protected LocalizableSupport localizableSupport =
new LocalizableSupport(BUNDLE_CLASSNAME,
Parser.class.getClassLoader());
protected Scanner scanner;
protected int current;
protected DocumentHandler documentHandler =
DefaultDocumentHandler.INSTANCE;
protected SelectorFactory selectorFactory =
DefaultSelectorFactory.INSTANCE;
protected ConditionFactory conditionFactory =
DefaultConditionFactory.INSTANCE;
protected ErrorHandler errorHandler = DefaultErrorHandler.INSTANCE;
protected String pseudoElement;
protected String documentURI;
public String getParserVersion() {
return "http://www.w3.org/TR/REC-CSS2";
}
public void setLocale(Locale locale) throws CSSException {
localizableSupport.setLocale(locale);
}
public Locale getLocale() {
return localizableSupport.getLocale();
}
public String formatMessage(String key, Object[] args)
throws MissingResourceException {
return localizableSupport.formatMessage(key, args);
}
public void setDocumentHandler(DocumentHandler handler) {
documentHandler = handler;
}
public void setSelectorFactory(SelectorFactory factory) {
selectorFactory = factory;
}
public void setConditionFactory(ConditionFactory factory) {
conditionFactory = factory;
}
public void setErrorHandler(ErrorHandler handler) {
errorHandler = handler;
}
public void parseStyleSheet(InputSource source)
throws CSSException, IOException {
scanner = createScanner(source);
try {
documentHandler.startDocument(source);
current = scanner.next();
switch (current) {
case LexicalUnits.CHARSET_SYMBOL:
if (nextIgnoreSpaces() != LexicalUnits.STRING) {
reportError("charset.string");
} else {
if (nextIgnoreSpaces() != LexicalUnits.SEMI_COLON) {
reportError("semicolon");
}
next();
}
break;
case LexicalUnits.COMMENT:
documentHandler.comment(scanner.getStringValue());
}
skipSpacesAndCDOCDC();
for (;;) {
if (current == LexicalUnits.IMPORT_SYMBOL) {
nextIgnoreSpaces();
parseImportRule();
nextIgnoreSpaces();
} else {
break;
}
}
loop: for (;;) {
switch (current) {
case LexicalUnits.PAGE_SYMBOL:
nextIgnoreSpaces();
parsePageRule();
break;
case LexicalUnits.MEDIA_SYMBOL:
nextIgnoreSpaces();
parseMediaRule();
break;
case LexicalUnits.FONT_FACE_SYMBOL:
nextIgnoreSpaces();
parseFontFaceRule();
break;
case LexicalUnits.AT_KEYWORD:
nextIgnoreSpaces();
parseAtRule();
break;
case LexicalUnits.EOF:
break loop;
default:
parseRuleSet();
}
skipSpacesAndCDOCDC();
}
} finally {
documentHandler.endDocument(source);
scanner.close();
scanner = null;
}
}
public void parseStyleSheet(String uri) throws CSSException, IOException {
parseStyleSheet(new InputSource(uri));
}
public void parseStyleDeclaration(InputSource source)
throws CSSException, IOException {
scanner = createScanner(source);
parseStyleDeclarationInternal();
}
protected void parseStyleDeclarationInternal()
throws CSSException, IOException {
nextIgnoreSpaces();
try {
parseStyleDeclaration(false);
} catch (CSSParseException e) {
reportError(e);
} finally {
scanner.close();
scanner = null;
}
}
public void parseRule(InputSource source)
throws CSSException, IOException {
scanner = createScanner(source);
parseRuleInternal();
}
protected void parseRuleInternal() throws CSSException, IOException {
nextIgnoreSpaces();
parseRule();
scanner.close();
scanner = null;
}
public SelectorList parseSelectors(InputSource source)
throws CSSException, IOException {
scanner = createScanner(source);
return parseSelectorsInternal();
}
protected SelectorList parseSelectorsInternal()
throws CSSException, IOException {
nextIgnoreSpaces();
SelectorList ret = parseSelectorList();
scanner.close();
scanner = null;
return ret;
}
public LexicalUnit parsePropertyValue(InputSource source)
throws CSSException, IOException {
scanner = createScanner(source);
return parsePropertyValueInternal();
}
protected LexicalUnit parsePropertyValueInternal()
throws CSSException, IOException {
nextIgnoreSpaces();
LexicalUnit exp = null;
try {
exp = parseExpression(false);
} catch (CSSParseException e) {
reportError(e);
throw e;
}
CSSParseException exception = null;
if (current != LexicalUnits.EOF)
exception = createCSSParseException("eof.expected");
scanner.close();
scanner = null;
if (exception != null) {
errorHandler.fatalError(exception);
}
return exp;
}
public boolean parsePriority(InputSource source)
throws CSSException, IOException {
scanner = createScanner(source);
return parsePriorityInternal();
}
protected boolean parsePriorityInternal()
throws CSSException, IOException {
nextIgnoreSpaces();
scanner.close();
scanner = null;
switch (current) {
case LexicalUnits.EOF:
return false;
case LexicalUnits.IMPORT_SYMBOL:
return true;
default:
reportError("token", new Object[] {current});
return false;
}
}
protected void parseRule() {
switch (scanner.getType()) {
case LexicalUnits.IMPORT_SYMBOL:
nextIgnoreSpaces();
parseImportRule();
break;
case LexicalUnits.AT_KEYWORD:
nextIgnoreSpaces();
parseAtRule();
break;
case LexicalUnits.FONT_FACE_SYMBOL:
nextIgnoreSpaces();
parseFontFaceRule();
break;
case LexicalUnits.MEDIA_SYMBOL:
nextIgnoreSpaces();
parseMediaRule();
break;
case LexicalUnits.PAGE_SYMBOL:
nextIgnoreSpaces();
parsePageRule();
break;
default:
parseRuleSet();
}
}
protected void parseAtRule() {
scanner.scanAtRule();
documentHandler.ignorableAtRule(scanner.getStringValue());
nextIgnoreSpaces();
}
protected void parseImportRule() {
String uri = null;
switch (current) {
default:
reportError("string.or.uri");
return;
case LexicalUnits.STRING:
case LexicalUnits.URI:
uri = scanner.getStringValue();
nextIgnoreSpaces();
}
CSSSACMediaList ml;
if (current != LexicalUnits.IDENTIFIER) {
ml = new CSSSACMediaList();
ml.append("all");
} else {
ml = parseMediaList();
}
documentHandler.importStyle(uri, ml, null);
if (current != LexicalUnits.SEMI_COLON) {
reportError("semicolon");
} else {
next();
}
}
protected CSSSACMediaList parseMediaList() {
CSSSACMediaList result = new CSSSACMediaList();
result.append(scanner.getStringValue());
nextIgnoreSpaces();
while (current == LexicalUnits.COMMA) {
nextIgnoreSpaces();
switch (current) {
default:
reportError("identifier");
break;
case LexicalUnits.IDENTIFIER:
result.append(scanner.getStringValue());
nextIgnoreSpaces();
}
}
return result;
}
protected void parseFontFaceRule() {
try {
documentHandler.startFontFace();
if (current != LexicalUnits.LEFT_CURLY_BRACE) {
reportError("left.curly.brace");
} else {
nextIgnoreSpaces();
try {
parseStyleDeclaration(true);
} catch (CSSParseException e) {
reportError(e);
}
}
} finally {
documentHandler.endFontFace();
}
}
protected void () {
String page = null;
String ppage = null;
if (current == LexicalUnits.IDENTIFIER) {
page = scanner.getStringValue();
nextIgnoreSpaces();
if (current == LexicalUnits.COLON) {
nextIgnoreSpaces();
if (current != LexicalUnits.IDENTIFIER) {
reportError("identifier");
return;
}
ppage = scanner.getStringValue();
nextIgnoreSpaces();
}
}
try {
documentHandler.startPage(page, ppage);
if (current != LexicalUnits.LEFT_CURLY_BRACE) {
reportError("left.curly.brace");
} else {
nextIgnoreSpaces();
try {
parseStyleDeclaration(true);
} catch (CSSParseException e) {
reportError(e);
}
}
} finally {
documentHandler.endPage(page, ppage);
}
}
protected void parseMediaRule() {
if (current != LexicalUnits.IDENTIFIER) {
reportError("identifier");
return;
}
CSSSACMediaList ml = parseMediaList();
try {
documentHandler.startMedia(ml);
if (current != LexicalUnits.LEFT_CURLY_BRACE) {
reportError("left.curly.brace");
} else {
nextIgnoreSpaces();
loop: for (;;) {
switch (current) {
case LexicalUnits.EOF:
case LexicalUnits.RIGHT_CURLY_BRACE:
break loop;
default:
parseRuleSet();
}
}
nextIgnoreSpaces();
}
} finally {
documentHandler.endMedia(ml);
}
}
protected void parseRuleSet() {
SelectorList sl = null;
try {
sl = parseSelectorList();
} catch (CSSParseException e) {
reportError(e);
return;
}
try {
documentHandler.startSelector(sl);
if (current != LexicalUnits.LEFT_CURLY_BRACE) {
reportError("left.curly.brace");
if (current == LexicalUnits.RIGHT_CURLY_BRACE) {
nextIgnoreSpaces();
}
} else {
nextIgnoreSpaces();
try {
parseStyleDeclaration(true);
} catch (CSSParseException e) {
reportError(e);
}
}
} finally {
documentHandler.endSelector(sl);
}
}
protected SelectorList parseSelectorList() {
CSSSelectorList result = new CSSSelectorList();
result.append(parseSelector());
for (;;) {
if (current != LexicalUnits.COMMA) {
return result;
}
nextIgnoreSpaces();
result.append(parseSelector());
}
}
protected Selector parseSelector() {
pseudoElement = null;
Selector result = parseSimpleSelector();
loop: for (;;) {
switch (current) {
default:
break loop;
case LexicalUnits.IDENTIFIER:
case LexicalUnits.ANY:
case LexicalUnits.HASH:
case LexicalUnits.DOT:
case LexicalUnits.LEFT_BRACKET:
case LexicalUnits.COLON:
if (pseudoElement != null) {
throw createCSSParseException("pseudo.element.position");
}
result = selectorFactory.createDescendantSelector
(result,
parseSimpleSelector());
break;
case LexicalUnits.PLUS:
if (pseudoElement != null) {
throw createCSSParseException("pseudo.element.position");
}
nextIgnoreSpaces();
result = selectorFactory.createDirectAdjacentSelector
((short)1,
result,
parseSimpleSelector());
break;
case LexicalUnits.PRECEDE:
if (pseudoElement != null) {
throw createCSSParseException("pseudo.element.position");
}
nextIgnoreSpaces();
result = selectorFactory.createChildSelector
(result,
parseSimpleSelector());
}
}
if (pseudoElement != null) {
result = selectorFactory.createChildSelector
(result,
selectorFactory.createPseudoElementSelector
(null, pseudoElement));
}
return result;
}
protected SimpleSelector parseSimpleSelector() {
SimpleSelector result;
switch (current) {
case LexicalUnits.IDENTIFIER:
result = selectorFactory.createElementSelector
(null, scanner.getStringValue());
next();
break;
case LexicalUnits.ANY:
next();
default:
result = selectorFactory.createElementSelector(null, null);
}
Condition cond = null;
loop: for (;;) {
Condition c = null;
switch (current) {
case LexicalUnits.HASH:
c = conditionFactory.createIdCondition
(scanner.getStringValue());
next();
break;
case LexicalUnits.DOT:
if (next() != LexicalUnits.IDENTIFIER) {
throw createCSSParseException("identifier");
}
c = conditionFactory.createClassCondition
(null, scanner.getStringValue());
next();
break;
case LexicalUnits.LEFT_BRACKET:
if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) {
throw createCSSParseException("identifier");
}
String name = scanner.getStringValue();
int op = nextIgnoreSpaces();
switch (op) {
default:
throw createCSSParseException("right.bracket");
case LexicalUnits.RIGHT_BRACKET:
next();
c = conditionFactory.createAttributeCondition
(name, null, false, null);
break;
case LexicalUnits.EQUAL:
case LexicalUnits.INCLUDES:
case LexicalUnits.DASHMATCH:
String val = null;
switch (nextIgnoreSpaces()) {
default:
throw createCSSParseException("identifier.or.string");
case LexicalUnits.STRING:
case LexicalUnits.IDENTIFIER:
val = scanner.getStringValue();
nextIgnoreSpaces();
}
if (current != LexicalUnits.RIGHT_BRACKET) {
throw createCSSParseException("right.bracket");
}
next();
switch (op) {
case LexicalUnits.EQUAL:
c = conditionFactory.createAttributeCondition
(name, null, false, val);
break;
case LexicalUnits.INCLUDES:
c = conditionFactory.createOneOfAttributeCondition
(name, null, false, val);
break;
default:
c = conditionFactory.
createBeginHyphenAttributeCondition
(name, null, false, val);
}
}
break;
case LexicalUnits.COLON:
switch (nextIgnoreSpaces()) {
case LexicalUnits.IDENTIFIER:
String val = scanner.getStringValue();
if (isPseudoElement(val)) {
if (pseudoElement != null) {
throw createCSSParseException
("duplicate.pseudo.element");
}
pseudoElement = val;
} else {
c = conditionFactory.createPseudoClassCondition
(null, val);
}
next();
break;
case LexicalUnits.FUNCTION:
String func = scanner.getStringValue();
if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) {
throw createCSSParseException("identifier");
}
String lang = scanner.getStringValue();
if (nextIgnoreSpaces() != LexicalUnits.RIGHT_BRACE) {
throw createCSSParseException("right.brace");
}
if (!func.equalsIgnoreCase("lang")) {
throw createCSSParseException("pseudo.function");
}
c = conditionFactory.createLangCondition(lang);
next();
break;
default:
throw createCSSParseException("identifier");
}
break;
default:
break loop;
}
if (c != null) {
if (cond == null) {
cond = c;
} else {
cond = conditionFactory.createAndCondition(cond, c);
}
}
}
skipSpaces();
if (cond != null) {
result = selectorFactory.createConditionalSelector(result, cond);
}
return result;
}
protected boolean isPseudoElement(String s) {
switch (s.charAt(0)) {
case 'a':
case 'A':
return s.equalsIgnoreCase("after");
case 'b':
case 'B':
return s.equalsIgnoreCase("before");
case 'f':
case 'F':
return s.equalsIgnoreCase("first-letter") ||
s.equalsIgnoreCase("first-line");
}
return false;
}
protected void parseStyleDeclaration(boolean inSheet)
throws CSSException {
for (;;) {
switch (current) {
case LexicalUnits.EOF:
if (inSheet) {
throw createCSSParseException("eof");
}
return;
case LexicalUnits.RIGHT_CURLY_BRACE:
if (!inSheet) {
throw createCSSParseException("eof.expected");
}
nextIgnoreSpaces();
return;
case LexicalUnits.SEMI_COLON:
nextIgnoreSpaces();
continue;
default:
throw createCSSParseException("identifier");
case LexicalUnits.IDENTIFIER:
}
String name = scanner.getStringValue();
if (nextIgnoreSpaces() != LexicalUnits.COLON) {
throw createCSSParseException("colon");
}
nextIgnoreSpaces();
LexicalUnit exp = null;
try {
exp = parseExpression(false);
} catch (CSSParseException e) {
reportError(e);
}
if (exp != null) {
boolean important = false;
if (current == LexicalUnits.IMPORTANT_SYMBOL) {
important = true;
nextIgnoreSpaces();
}
documentHandler.property(name, exp, important);
}
}
}
protected LexicalUnit parseExpression(boolean param) {
LexicalUnit result = parseTerm(null);
LexicalUnit curr = result;
for (;;) {
boolean op = false;
switch (current) {
case LexicalUnits.COMMA:
op = true;
curr = CSSLexicalUnit.createSimple
(LexicalUnit.SAC_OPERATOR_COMMA, curr);
nextIgnoreSpaces();
break;
case LexicalUnits.DIVIDE:
op = true;
curr = CSSLexicalUnit.createSimple
(LexicalUnit.SAC_OPERATOR_SLASH, curr);
nextIgnoreSpaces();
}
if (param) {
if (current == LexicalUnits.RIGHT_BRACE) {
if (op) {
throw createCSSParseException
("token", new Object[] {current});
}
return result;
}
curr = parseTerm(curr);
} else {
switch (current) {
case LexicalUnits.IMPORTANT_SYMBOL:
case LexicalUnits.SEMI_COLON:
case LexicalUnits.RIGHT_CURLY_BRACE:
case LexicalUnits.EOF:
if (op) {
throw createCSSParseException
("token", new Object[] {current});
}
return result;
default:
curr = parseTerm(curr);
}
}
}
}
protected LexicalUnit parseTerm(LexicalUnit prev) {
boolean plus = true;
boolean sgn = false;
switch (current) {
case LexicalUnits.MINUS:
plus = false;
case LexicalUnits.PLUS:
next();
sgn = true;
default:
switch (current) {
case LexicalUnits.INTEGER:
String sval = scanner.getStringValue();
if (!plus) sval = "-"+sval;
long lVal = Long.parseLong( sval );
if ( lVal >= Integer.MIN_VALUE && lVal <= Integer.MAX_VALUE ){
int iVal = (int) lVal;
nextIgnoreSpaces();
return CSSLexicalUnit.createInteger( iVal, prev);
}
case LexicalUnits.REAL:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_REAL,
number(plus), prev);
case LexicalUnits.PERCENTAGE:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_PERCENTAGE,
number(plus), prev);
case LexicalUnits.PT:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_POINT,
number(plus), prev);
case LexicalUnits.PC:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_PICA,
number(plus), prev);
case LexicalUnits.PX:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_PIXEL,
number(plus), prev);
case LexicalUnits.CM:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_CENTIMETER,
number(plus), prev);
case LexicalUnits.MM:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_MILLIMETER,
number(plus), prev);
case LexicalUnits.IN:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_INCH,
number(plus), prev);
case LexicalUnits.EM:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_EM,
number(plus), prev);
case LexicalUnits.EX:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_EX,
number(plus), prev);
case LexicalUnits.DEG:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_DEGREE,
number(plus), prev);
case LexicalUnits.RAD:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_RADIAN,
number(plus), prev);
case LexicalUnits.GRAD:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_GRADIAN,
number(plus), prev);
case LexicalUnits.S:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_SECOND,
number(plus), prev);
case LexicalUnits.MS:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_MILLISECOND,
number(plus), prev);
case LexicalUnits.HZ:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_HERTZ,
number(plus), prev);
case LexicalUnits.KHZ:
return CSSLexicalUnit.createFloat(LexicalUnit.SAC_KILOHERTZ,
number(plus), prev);
case LexicalUnits.DIMENSION:
return dimension(plus, prev);
case LexicalUnits.FUNCTION:
return parseFunction(plus, prev);
}
if (sgn) {
throw createCSSParseException
("token",
new Object[] {current});
}
}
switch (current) {
case LexicalUnits.STRING:
String val = scanner.getStringValue();
nextIgnoreSpaces();
return CSSLexicalUnit.createString(LexicalUnit.SAC_STRING_VALUE,
val, prev);
case LexicalUnits.IDENTIFIER:
val = scanner.getStringValue();
nextIgnoreSpaces();
if (val.equalsIgnoreCase("inherit")) {
return CSSLexicalUnit.createSimple(LexicalUnit.SAC_INHERIT,
prev);
} else {
return CSSLexicalUnit.createString(LexicalUnit.SAC_IDENT,
val, prev);
}
case LexicalUnits.URI:
val = scanner.getStringValue();
nextIgnoreSpaces();
return CSSLexicalUnit.createString(LexicalUnit.SAC_URI,
val, prev);
case LexicalUnits.HASH:
return hexcolor(prev);
default:
throw createCSSParseException
("token",
new Object[] {current});
}
}
protected LexicalUnit parseFunction(boolean positive, LexicalUnit prev) {
String name = scanner.getStringValue();
nextIgnoreSpaces();
LexicalUnit params = parseExpression(true);
if (current != LexicalUnits.RIGHT_BRACE) {
throw createCSSParseException
("token",
new Object[] {current});
}
nextIgnoreSpaces();
predefined: switch (name.charAt(0)) {
case 'r':
case 'R':
LexicalUnit lu;
if (name.equalsIgnoreCase("rgb")) {
lu = params;
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_INTEGER:
case LexicalUnit.SAC_PERCENTAGE:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_OPERATOR_COMMA:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_INTEGER:
case LexicalUnit.SAC_PERCENTAGE:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_OPERATOR_COMMA:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_INTEGER:
case LexicalUnit.SAC_PERCENTAGE:
lu = lu.getNextLexicalUnit();
}
if (lu != null) {
break;
}
return CSSLexicalUnit.createPredefinedFunction
(LexicalUnit.SAC_RGBCOLOR, params, prev);
} else if (name.equalsIgnoreCase("rect")) {
lu = params;
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_INTEGER:
if (lu.getIntegerValue() != 0) {
break predefined;
}
lu = lu.getNextLexicalUnit();
break;
case LexicalUnit.SAC_IDENT:
if (!lu.getStringValue().equalsIgnoreCase("auto")) {
break predefined;
}
lu = lu.getNextLexicalUnit();
break;
case LexicalUnit.SAC_EM:
case LexicalUnit.SAC_EX:
case LexicalUnit.SAC_PIXEL:
case LexicalUnit.SAC_CENTIMETER:
case LexicalUnit.SAC_MILLIMETER:
case LexicalUnit.SAC_INCH:
case LexicalUnit.SAC_POINT:
case LexicalUnit.SAC_PICA:
case LexicalUnit.SAC_PERCENTAGE:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_OPERATOR_COMMA:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_INTEGER:
if (lu.getIntegerValue() != 0) {
break predefined;
}
lu = lu.getNextLexicalUnit();
break;
case LexicalUnit.SAC_IDENT:
if (!lu.getStringValue().equalsIgnoreCase("auto")) {
break predefined;
}
lu = lu.getNextLexicalUnit();
break;
case LexicalUnit.SAC_EM:
case LexicalUnit.SAC_EX:
case LexicalUnit.SAC_PIXEL:
case LexicalUnit.SAC_CENTIMETER:
case LexicalUnit.SAC_MILLIMETER:
case LexicalUnit.SAC_INCH:
case LexicalUnit.SAC_POINT:
case LexicalUnit.SAC_PICA:
case LexicalUnit.SAC_PERCENTAGE:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_OPERATOR_COMMA:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_INTEGER:
if (lu.getIntegerValue() != 0) {
break predefined;
}
lu = lu.getNextLexicalUnit();
break;
case LexicalUnit.SAC_IDENT:
if (!lu.getStringValue().equalsIgnoreCase("auto")) {
break predefined;
}
lu = lu.getNextLexicalUnit();
break;
case LexicalUnit.SAC_EM:
case LexicalUnit.SAC_EX:
case LexicalUnit.SAC_PIXEL:
case LexicalUnit.SAC_CENTIMETER:
case LexicalUnit.SAC_MILLIMETER:
case LexicalUnit.SAC_INCH:
case LexicalUnit.SAC_POINT:
case LexicalUnit.SAC_PICA:
case LexicalUnit.SAC_PERCENTAGE:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_OPERATOR_COMMA:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_INTEGER:
if (lu.getIntegerValue() != 0) {
break predefined;
}
lu = lu.getNextLexicalUnit();
break;
case LexicalUnit.SAC_IDENT:
if (!lu.getStringValue().equalsIgnoreCase("auto")) {
break predefined;
}
lu = lu.getNextLexicalUnit();
break;
case LexicalUnit.SAC_EM:
case LexicalUnit.SAC_EX:
case LexicalUnit.SAC_PIXEL:
case LexicalUnit.SAC_CENTIMETER:
case LexicalUnit.SAC_MILLIMETER:
case LexicalUnit.SAC_INCH:
case LexicalUnit.SAC_POINT:
case LexicalUnit.SAC_PICA:
case LexicalUnit.SAC_PERCENTAGE:
lu = lu.getNextLexicalUnit();
}
if (lu != null) {
break;
}
return CSSLexicalUnit.createPredefinedFunction
(LexicalUnit.SAC_RECT_FUNCTION, params, prev);
}
break;
case 'c':
case 'C':
if (name.equalsIgnoreCase("counter")) {
lu = params;
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_IDENT:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_OPERATOR_COMMA:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_IDENT:
lu = lu.getNextLexicalUnit();
}
if (lu != null) {
break;
}
return CSSLexicalUnit.createPredefinedFunction
(LexicalUnit.SAC_COUNTER_FUNCTION, params, prev);
} else if (name.equalsIgnoreCase("counters")) {
lu = params;
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_IDENT:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_OPERATOR_COMMA:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_STRING_VALUE:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_OPERATOR_COMMA:
lu = lu.getNextLexicalUnit();
}
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_IDENT:
lu = lu.getNextLexicalUnit();
}
if (lu != null) {
break;
}
return CSSLexicalUnit.createPredefinedFunction
(LexicalUnit.SAC_COUNTERS_FUNCTION, params, prev);
}
break;
case 'a':
case 'A':
if (name.equalsIgnoreCase("attr")) {
lu = params;
if (lu == null) {
break;
}
switch (lu.getLexicalUnitType()) {
default:
break predefined;
case LexicalUnit.SAC_IDENT:
lu = lu.getNextLexicalUnit();
}
if (lu != null) {
break;
}
return CSSLexicalUnit.createString
(LexicalUnit.SAC_ATTR, params.getStringValue(), prev);
}
}
return CSSLexicalUnit.createFunction(name, params, prev);
}
protected LexicalUnit hexcolor(LexicalUnit prev) {
String val = scanner.getStringValue();
int len = val.length();
LexicalUnit params = null;
switch (len) {
case 3:
char rc = Character.toLowerCase(val.charAt(0));
char gc = Character.toLowerCase(val.charAt(1));
char bc = Character.toLowerCase(val.charAt(2));
if (!ScannerUtilities.isCSSHexadecimalCharacter(rc) ||
!ScannerUtilities.isCSSHexadecimalCharacter(gc) ||
!ScannerUtilities.isCSSHexadecimalCharacter(bc)) {
throw createCSSParseException
("rgb.color", new Object[] { val });
}
int t;
int r = t = (rc >= '0' && rc <= '9') ? rc - '0' : rc - 'a' + 10;
t <<= 4;
r |= t;
int g = t = (gc >= '0' && gc <= '9') ? gc - '0' : gc - 'a' + 10;
t <<= 4;
g |= t;
int b = t = (bc >= '0' && bc <= '9') ? bc - '0' : bc - 'a' + 10;
t <<= 4;
b |= t;
params = CSSLexicalUnit.createInteger(r, null);
LexicalUnit tmp;
tmp = CSSLexicalUnit.createSimple
(LexicalUnit.SAC_OPERATOR_COMMA, params);
tmp = CSSLexicalUnit.createInteger(g, tmp);
tmp = CSSLexicalUnit.createSimple
(LexicalUnit.SAC_OPERATOR_COMMA, tmp);
tmp = CSSLexicalUnit.createInteger(b, tmp);
break;
case 6:
char rc1 = Character.toLowerCase(val.charAt(0));
char rc2 = Character.toLowerCase(val.charAt(1));
char gc1 = Character.toLowerCase(val.charAt(2));
char gc2 = Character.toLowerCase(val.charAt(3));
char bc1 = Character.toLowerCase(val.charAt(4));
char bc2 = Character.toLowerCase(val.charAt(5));
if (!ScannerUtilities.isCSSHexadecimalCharacter(rc1) ||
!ScannerUtilities.isCSSHexadecimalCharacter(rc2) ||
!ScannerUtilities.isCSSHexadecimalCharacter(gc1) ||
!ScannerUtilities.isCSSHexadecimalCharacter(gc2) ||
!ScannerUtilities.isCSSHexadecimalCharacter(bc1) ||
!ScannerUtilities.isCSSHexadecimalCharacter(bc2)) {
throw createCSSParseException("rgb.color");
}
r = (rc1 >= '0' && rc1 <= '9') ? rc1 - '0' : rc1 - 'a' + 10;
r <<= 4;
r |= (rc2 >= '0' && rc2 <= '9') ? rc2 - '0' : rc2 - 'a' + 10;
g = (gc1 >= '0' && gc1 <= '9') ? gc1 - '0' : gc1 - 'a' + 10;
g <<= 4;
g |= (gc2 >= '0' && gc2 <= '9') ? gc2 - '0' : gc2 - 'a' + 10;
b = (bc1 >= '0' && bc1 <= '9') ? bc1 - '0' : bc1 - 'a' + 10;
b <<= 4;
b |= (bc2 >= '0' && bc2 <= '9') ? bc2 - '0' : bc2 - 'a' + 10;
params = CSSLexicalUnit.createInteger(r, null);
tmp = CSSLexicalUnit.createSimple
(LexicalUnit.SAC_OPERATOR_COMMA, params);
tmp = CSSLexicalUnit.createInteger(g, tmp);
tmp = CSSLexicalUnit.createSimple
(LexicalUnit.SAC_OPERATOR_COMMA, tmp);
tmp = CSSLexicalUnit.createInteger(b, tmp);
break;
default:
throw createCSSParseException("rgb.color", new Object[] { val });
}
nextIgnoreSpaces();
return CSSLexicalUnit.createPredefinedFunction
(LexicalUnit.SAC_RGBCOLOR, params, prev);
}
protected Scanner createScanner(InputSource source) {
documentURI = source.getURI();
if (documentURI == null) {
documentURI = "";
}
Reader r = source.getCharacterStream();
if (r != null) {
return new Scanner(r);
}
InputStream is = source.getByteStream();
if (is != null) {
return new Scanner(is, source.getEncoding());
}
String uri = source.getURI();
if (uri == null) {
throw new CSSException(formatMessage("empty.source", null));
}
try {
ParsedURL purl = new ParsedURL(uri);
is = purl.openStreamRaw(CSSConstants.CSS_MIME_TYPE);
return new Scanner(is, source.getEncoding());
} catch (IOException e) {
throw new CSSException(e);
}
}
protected int skipSpaces() {
int lex = scanner.getType();
while (lex == LexicalUnits.SPACE) {
lex = next();
}
return lex;
}
protected int skipSpacesAndCDOCDC() {
loop: for (;;) {
switch (current) {
default:
break loop;
case LexicalUnits.COMMENT:
case LexicalUnits.SPACE:
case LexicalUnits.CDO:
case LexicalUnits.CDC:
}
scanner.clearBuffer();
next();
}
return current;
}
protected float number(boolean positive) {
try {
float sgn = (positive) ? 1 : -1;
String val = scanner.getStringValue();
nextIgnoreSpaces();
return sgn * Float.parseFloat(val);
} catch (NumberFormatException e) {
throw createCSSParseException("number.format");
}
}
protected LexicalUnit dimension(boolean positive, LexicalUnit prev) {
try {
float sgn = (positive) ? 1 : -1;
String val = scanner.getStringValue();
int i;
loop: for (i = 0; i < val.length(); i++) {
switch (val.charAt(i)) {
default:
break loop;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
}
}
nextIgnoreSpaces();
return CSSLexicalUnit.createDimension
(sgn * Float.parseFloat(val.substring(0, i)),
val.substring(i),
prev);
} catch (NumberFormatException e) {
throw createCSSParseException("number.format");
}
}
protected int next() {
try {
for (;;) {
scanner.clearBuffer();
current = scanner.next();
if (current == LexicalUnits.COMMENT) {
documentHandler.comment(scanner.getStringValue());
} else {
break;
}
}
return current;
} catch (ParseException e) {
reportError(e.getMessage());
return current;
}
}
protected int nextIgnoreSpaces() {
try {
loop: for (;;) {
scanner.clearBuffer();
current = scanner.next();
switch (current) {
case LexicalUnits.COMMENT:
documentHandler.comment(scanner.getStringValue());
break;
default:
break loop;
case LexicalUnits.SPACE:
}
}
return current;
} catch (ParseException e) {
errorHandler.error(createCSSParseException(e.getMessage()));
return current;
}
}
protected void reportError(String key) {
reportError(key, null);
}
protected void reportError(String key, Object[] params) {
reportError(createCSSParseException(key, params));
}
protected void reportError(CSSParseException e) {
errorHandler.error(e);
int cbraces = 1;
for (;;) {
switch (current) {
case LexicalUnits.EOF:
return;
case LexicalUnits.SEMI_COLON:
case LexicalUnits.RIGHT_CURLY_BRACE:
if (--cbraces == 0) {
nextIgnoreSpaces();
return;
}
case LexicalUnits.LEFT_CURLY_BRACE:
cbraces++;
}
nextIgnoreSpaces();
}
}
protected CSSParseException createCSSParseException(String key) {
return createCSSParseException(key, null);
}
protected CSSParseException createCSSParseException(String key,
Object[] params) {
return new CSSParseException(formatMessage(key, params),
documentURI,
scanner.getLine(),
scanner.getColumn());
}
public void parseStyleDeclaration(String source)
throws CSSException, IOException {
scanner = new Scanner(source);
parseStyleDeclarationInternal();
}
public void parseRule(String source) throws CSSException, IOException {
scanner = new Scanner(source);
parseRuleInternal();
}
public SelectorList parseSelectors(String source)
throws CSSException, IOException {
scanner = new Scanner(source);
return parseSelectorsInternal();
}
public LexicalUnit parsePropertyValue(String source)
throws CSSException, IOException {
scanner = new Scanner(source);
return parsePropertyValueInternal();
}
public boolean parsePriority(String source)
throws CSSException, IOException {
scanner = new Scanner(source);
return parsePriorityInternal();
}
public SACMediaList parseMedia(String mediaText)
throws CSSException, IOException {
CSSSACMediaList result = new CSSSACMediaList();
if (!"all".equalsIgnoreCase(mediaText)) {
StringTokenizer st = new StringTokenizer(mediaText, " ,");
while (st.hasMoreTokens()) {
result.append(st.nextToken());
}
}
return result;
}
}