0001: /*
0002:
0003: Licensed to the Apache Software Foundation (ASF) under one or more
0004: contributor license agreements. See the NOTICE file distributed with
0005: this work for additional information regarding copyright ownership.
0006: The ASF licenses this file to You under the Apache License, Version 2.0
0007: (the "License"); you may not use this file except in compliance with
0008: the License. You may obtain a copy of the License at
0009:
0010: http://www.apache.org/licenses/LICENSE-2.0
0011:
0012: Unless required by applicable law or agreed to in writing, software
0013: distributed under the License is distributed on an "AS IS" BASIS,
0014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0015: See the License for the specific language governing permissions and
0016: limitations under the License.
0017:
0018: */
0019: package org.apache.batik.css.parser;
0020:
0021: import java.io.IOException;
0022: import java.io.InputStream;
0023: import java.io.Reader;
0024: import java.util.Locale;
0025: import java.util.MissingResourceException;
0026: import java.util.StringTokenizer;
0027:
0028: import org.apache.batik.i18n.Localizable;
0029: import org.apache.batik.i18n.LocalizableSupport;
0030: import org.apache.batik.util.CSSConstants;
0031: import org.apache.batik.util.ParsedURL;
0032: import org.w3c.css.sac.CSSException;
0033: import org.w3c.css.sac.CSSParseException;
0034: import org.w3c.css.sac.Condition;
0035: import org.w3c.css.sac.ConditionFactory;
0036: import org.w3c.css.sac.DocumentHandler;
0037: import org.w3c.css.sac.ErrorHandler;
0038: import org.w3c.css.sac.InputSource;
0039: import org.w3c.css.sac.LexicalUnit;
0040: import org.w3c.css.sac.SACMediaList;
0041: import org.w3c.css.sac.Selector;
0042: import org.w3c.css.sac.SelectorFactory;
0043: import org.w3c.css.sac.SelectorList;
0044: import org.w3c.css.sac.SimpleSelector;
0045:
0046: /**
0047: * This class implements the {@link org.w3c.css.sac.Parser} interface.
0048: *
0049: * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
0050: * @version $Id: Parser.java 522311 2007-03-25 17:39:19Z dvholten $
0051: */
0052: public class Parser implements ExtendedParser, Localizable {
0053:
0054: /**
0055: * The default resource bundle base name.
0056: */
0057: public static final String BUNDLE_CLASSNAME = "org.apache.batik.css.parser.resources.Messages";
0058:
0059: /**
0060: * The localizable support.
0061: */
0062: protected LocalizableSupport localizableSupport = new LocalizableSupport(
0063: BUNDLE_CLASSNAME, Parser.class.getClassLoader());
0064:
0065: /**
0066: * The scanner used to scan the input source.
0067: */
0068: protected Scanner scanner;
0069:
0070: /**
0071: * The current lexical unit.
0072: */
0073: protected int current;
0074:
0075: /**
0076: * The document handler.
0077: */
0078: protected DocumentHandler documentHandler = DefaultDocumentHandler.INSTANCE;
0079:
0080: /**
0081: * The selector factory.
0082: */
0083: protected SelectorFactory selectorFactory = DefaultSelectorFactory.INSTANCE;
0084:
0085: /**
0086: * The condition factory.
0087: */
0088: protected ConditionFactory conditionFactory = DefaultConditionFactory.INSTANCE;
0089:
0090: /**
0091: * The error handler.
0092: */
0093: protected ErrorHandler errorHandler = DefaultErrorHandler.INSTANCE;
0094:
0095: /**
0096: * To store the current pseudo element.
0097: */
0098: protected String pseudoElement;
0099:
0100: /**
0101: * The document URI.
0102: */
0103: protected String documentURI;
0104:
0105: /**
0106: * <b>SAC</b>: Implements {@link
0107: * org.w3c.css.sac.Parser#getParserVersion()}.
0108: * @return "http://www.w3.org/TR/REC-CSS2".
0109: */
0110: public String getParserVersion() {
0111: return "http://www.w3.org/TR/REC-CSS2";
0112: }
0113:
0114: /**
0115: * <b>SAC</b>: Implements {@link org.w3c.css.sac.Parser#setLocale(Locale)}.
0116: */
0117: public void setLocale(Locale locale) throws CSSException {
0118: localizableSupport.setLocale(locale);
0119: }
0120:
0121: /**
0122: * Implements {@link org.apache.batik.i18n.Localizable#getLocale()}.
0123: */
0124: public Locale getLocale() {
0125: return localizableSupport.getLocale();
0126: }
0127:
0128: /**
0129: * Implements {@link
0130: * org.apache.batik.i18n.Localizable#formatMessage(String,Object[])}.
0131: */
0132: public String formatMessage(String key, Object[] args)
0133: throws MissingResourceException {
0134: return localizableSupport.formatMessage(key, args);
0135: }
0136:
0137: /**
0138: * <b>SAC</b>: Implements {@link
0139: * org.w3c.css.sac.Parser#setDocumentHandler(DocumentHandler)}.
0140: */
0141: public void setDocumentHandler(DocumentHandler handler) {
0142: documentHandler = handler;
0143: }
0144:
0145: /**
0146: * <b>SAC</b>: Implements {@link
0147: * org.w3c.css.sac.Parser#setSelectorFactory(SelectorFactory)}.
0148: */
0149: public void setSelectorFactory(SelectorFactory factory) {
0150: selectorFactory = factory;
0151: }
0152:
0153: /**
0154: * <b>SAC</b>: Implements {@link
0155: * org.w3c.css.sac.Parser#setConditionFactory(ConditionFactory)}.
0156: */
0157: public void setConditionFactory(ConditionFactory factory) {
0158: conditionFactory = factory;
0159: }
0160:
0161: /**
0162: * <b>SAC</b>: Implements {@link
0163: * org.w3c.css.sac.Parser#setErrorHandler(ErrorHandler)}.
0164: */
0165: public void setErrorHandler(ErrorHandler handler) {
0166: errorHandler = handler;
0167: }
0168:
0169: /**
0170: * <b>SAC</b>: Implements {@link
0171: * org.w3c.css.sac.Parser#parseStyleSheet(InputSource)}.
0172: */
0173: public void parseStyleSheet(InputSource source)
0174: throws CSSException, IOException {
0175: scanner = createScanner(source);
0176:
0177: try {
0178: documentHandler.startDocument(source);
0179:
0180: current = scanner.next();
0181: switch (current) {
0182: case LexicalUnits.CHARSET_SYMBOL:
0183: if (nextIgnoreSpaces() != LexicalUnits.STRING) {
0184: reportError("charset.string");
0185: } else {
0186: if (nextIgnoreSpaces() != LexicalUnits.SEMI_COLON) {
0187: reportError("semicolon");
0188: }
0189: next();
0190: }
0191: break;
0192: case LexicalUnits.COMMENT:
0193: documentHandler.comment(scanner.getStringValue());
0194: }
0195:
0196: skipSpacesAndCDOCDC();
0197: for (;;) {
0198: if (current == LexicalUnits.IMPORT_SYMBOL) {
0199: nextIgnoreSpaces();
0200: parseImportRule();
0201: nextIgnoreSpaces();
0202: } else {
0203: break;
0204: }
0205: }
0206:
0207: loop: for (;;) {
0208: switch (current) {
0209: case LexicalUnits.PAGE_SYMBOL:
0210: nextIgnoreSpaces();
0211: parsePageRule();
0212: break;
0213: case LexicalUnits.MEDIA_SYMBOL:
0214: nextIgnoreSpaces();
0215: parseMediaRule();
0216: break;
0217: case LexicalUnits.FONT_FACE_SYMBOL:
0218: nextIgnoreSpaces();
0219: parseFontFaceRule();
0220: break;
0221: case LexicalUnits.AT_KEYWORD:
0222: nextIgnoreSpaces();
0223: parseAtRule();
0224: break;
0225: case LexicalUnits.EOF:
0226: break loop;
0227: default:
0228: parseRuleSet();
0229: }
0230: skipSpacesAndCDOCDC();
0231: }
0232: } finally {
0233: documentHandler.endDocument(source);
0234: scanner = null;
0235: }
0236: }
0237:
0238: /**
0239: * <b>SAC</b>: Implements {@link
0240: * org.w3c.css.sac.Parser#parseStyleSheet(String)}.
0241: */
0242: public void parseStyleSheet(String uri) throws CSSException,
0243: IOException {
0244: parseStyleSheet(new InputSource(uri));
0245: }
0246:
0247: /**
0248: * <b>SAC</b>: Implements {@link
0249: * org.w3c.css.sac.Parser#parseStyleDeclaration(InputSource)}.
0250: */
0251: public void parseStyleDeclaration(InputSource source)
0252: throws CSSException, IOException {
0253:
0254: scanner = createScanner(source);
0255: parseStyleDeclarationInternal();
0256: }
0257:
0258: /**
0259: * Parses a style declaration using the current scanner.
0260: */
0261: protected void parseStyleDeclarationInternal() throws CSSException,
0262: IOException {
0263: nextIgnoreSpaces();
0264: try {
0265: parseStyleDeclaration(false);
0266: } catch (CSSParseException e) {
0267: reportError(e);
0268: } finally {
0269: scanner = null;
0270: }
0271: }
0272:
0273: /**
0274: * <b>SAC</b>: Implements {@link
0275: * org.w3c.css.sac.Parser#parseRule(InputSource)}.
0276: */
0277: public void parseRule(InputSource source) throws CSSException,
0278: IOException {
0279: scanner = createScanner(source);
0280: parseRuleInternal();
0281: }
0282:
0283: /**
0284: * Parses a rule using the current scanner.
0285: */
0286: protected void parseRuleInternal() throws CSSException, IOException {
0287: nextIgnoreSpaces();
0288: parseRule();
0289: scanner = null;
0290: }
0291:
0292: /**
0293: * <b>SAC</b>: Implements {@link
0294: * org.w3c.css.sac.Parser#parseSelectors(InputSource)}.
0295: */
0296: public SelectorList parseSelectors(InputSource source)
0297: throws CSSException, IOException {
0298: scanner = createScanner(source);
0299: return parseSelectorsInternal();
0300: }
0301:
0302: /**
0303: * Parses selectors using the current scanner.
0304: */
0305: protected SelectorList parseSelectorsInternal()
0306: throws CSSException, IOException {
0307: nextIgnoreSpaces();
0308: SelectorList ret = parseSelectorList();
0309: scanner = null;
0310: return ret;
0311: }
0312:
0313: /**
0314: * <b>SAC</b>: Implements
0315: * {@link org.w3c.css.sac.Parser#parsePropertyValue(InputSource)}.
0316: */
0317: public LexicalUnit parsePropertyValue(InputSource source)
0318: throws CSSException, IOException {
0319: scanner = createScanner(source);
0320: return parsePropertyValueInternal();
0321: }
0322:
0323: /**
0324: * Parses property value using the current scanner.
0325: */
0326: protected LexicalUnit parsePropertyValueInternal()
0327: throws CSSException, IOException {
0328: nextIgnoreSpaces();
0329:
0330: LexicalUnit exp = null;
0331:
0332: try {
0333: exp = parseExpression(false);
0334: } catch (CSSParseException e) {
0335: reportError(e);
0336: throw e;
0337: }
0338:
0339: CSSParseException exception = null;
0340: if (current != LexicalUnits.EOF)
0341: exception = createCSSParseException("eof.expected");
0342:
0343: scanner = null;
0344:
0345: if (exception != null) {
0346: errorHandler.fatalError(exception);
0347: }
0348: return exp;
0349: }
0350:
0351: /**
0352: * <b>SAC</b>: Implements
0353: * {@link org.w3c.css.sac.Parser#parsePriority(InputSource)}.
0354: */
0355: public boolean parsePriority(InputSource source)
0356: throws CSSException, IOException {
0357: scanner = createScanner(source);
0358: return parsePriorityInternal();
0359: }
0360:
0361: /**
0362: * Parses the priority using the current scanner.
0363: */
0364: protected boolean parsePriorityInternal() throws CSSException,
0365: IOException {
0366: nextIgnoreSpaces();
0367:
0368: scanner = null;
0369:
0370: switch (current) {
0371: case LexicalUnits.EOF:
0372: return false;
0373: case LexicalUnits.IMPORT_SYMBOL:
0374: return true;
0375: default:
0376: reportError("token", new Object[] { new Integer(current) });
0377: return false;
0378: }
0379: }
0380:
0381: /**
0382: * Parses a rule.
0383: */
0384: protected void parseRule() {
0385: switch (scanner.getType()) {
0386: case LexicalUnits.IMPORT_SYMBOL:
0387: nextIgnoreSpaces();
0388: parseImportRule();
0389: break;
0390: case LexicalUnits.AT_KEYWORD:
0391: nextIgnoreSpaces();
0392: parseAtRule();
0393: break;
0394: case LexicalUnits.FONT_FACE_SYMBOL:
0395: nextIgnoreSpaces();
0396: parseFontFaceRule();
0397: break;
0398: case LexicalUnits.MEDIA_SYMBOL:
0399: nextIgnoreSpaces();
0400: parseMediaRule();
0401: break;
0402: case LexicalUnits.PAGE_SYMBOL:
0403: nextIgnoreSpaces();
0404: parsePageRule();
0405: break;
0406: default:
0407: parseRuleSet();
0408: }
0409: }
0410:
0411: /**
0412: * Parses an unknown rule.
0413: */
0414: protected void parseAtRule() {
0415: scanner.scanAtRule();
0416: documentHandler.ignorableAtRule(scanner.getStringValue());
0417: nextIgnoreSpaces();
0418: }
0419:
0420: /**
0421: * Parses an import rule. Assumes the current token is '@import'.
0422: */
0423: protected void parseImportRule() {
0424: String uri = null;
0425: switch (current) {
0426: default:
0427: reportError("string.or.uri");
0428: return;
0429: case LexicalUnits.STRING:
0430: case LexicalUnits.URI:
0431: uri = scanner.getStringValue();
0432: nextIgnoreSpaces();
0433: }
0434:
0435: CSSSACMediaList ml;
0436: if (current != LexicalUnits.IDENTIFIER) {
0437: ml = new CSSSACMediaList();
0438: ml.append("all");
0439: } else {
0440: ml = parseMediaList();
0441: }
0442:
0443: documentHandler.importStyle(uri, ml, null);
0444:
0445: if (current != LexicalUnits.SEMI_COLON) {
0446: reportError("semicolon");
0447: } else {
0448: next();
0449: }
0450: }
0451:
0452: /**
0453: * Parses a media list.
0454: */
0455: protected CSSSACMediaList parseMediaList() {
0456: CSSSACMediaList result = new CSSSACMediaList();
0457: result.append(scanner.getStringValue());
0458: nextIgnoreSpaces();
0459:
0460: while (current == LexicalUnits.COMMA) {
0461: nextIgnoreSpaces();
0462:
0463: switch (current) {
0464: default:
0465: reportError("identifier");
0466: break;
0467: case LexicalUnits.IDENTIFIER:
0468: result.append(scanner.getStringValue());
0469: nextIgnoreSpaces();
0470: }
0471: }
0472: return result;
0473: }
0474:
0475: /**
0476: * Parses a font-face rule.
0477: */
0478: protected void parseFontFaceRule() {
0479: try {
0480: documentHandler.startFontFace();
0481:
0482: if (current != LexicalUnits.LEFT_CURLY_BRACE) {
0483: reportError("left.curly.brace");
0484: } else {
0485: nextIgnoreSpaces();
0486:
0487: try {
0488: parseStyleDeclaration(true);
0489: } catch (CSSParseException e) {
0490: reportError(e);
0491: }
0492: }
0493: } finally {
0494: documentHandler.endFontFace();
0495: }
0496: }
0497:
0498: /**
0499: * Parses a page rule.
0500: */
0501: protected void parsePageRule() {
0502: String page = null;
0503: String ppage = null;
0504:
0505: if (current == LexicalUnits.IDENTIFIER) {
0506: page = scanner.getStringValue();
0507: nextIgnoreSpaces();
0508:
0509: if (current == LexicalUnits.COLON) {
0510: nextIgnoreSpaces();
0511:
0512: if (current != LexicalUnits.IDENTIFIER) {
0513: reportError("identifier");
0514: return;
0515: }
0516: ppage = scanner.getStringValue();
0517: nextIgnoreSpaces();
0518: }
0519: }
0520:
0521: try {
0522: documentHandler.startPage(page, ppage);
0523:
0524: if (current != LexicalUnits.LEFT_CURLY_BRACE) {
0525: reportError("left.curly.brace");
0526: } else {
0527: nextIgnoreSpaces();
0528:
0529: try {
0530: parseStyleDeclaration(true);
0531: } catch (CSSParseException e) {
0532: reportError(e);
0533: }
0534: }
0535: } finally {
0536: documentHandler.endPage(page, ppage);
0537: }
0538: }
0539:
0540: /**
0541: * Parses a media rule.
0542: */
0543: protected void parseMediaRule() {
0544: if (current != LexicalUnits.IDENTIFIER) {
0545: reportError("identifier");
0546: return;
0547: }
0548:
0549: CSSSACMediaList ml = parseMediaList();
0550: try {
0551: documentHandler.startMedia(ml);
0552:
0553: if (current != LexicalUnits.LEFT_CURLY_BRACE) {
0554: reportError("left.curly.brace");
0555: } else {
0556: nextIgnoreSpaces();
0557:
0558: loop: for (;;) {
0559: switch (current) {
0560: case LexicalUnits.EOF:
0561: case LexicalUnits.RIGHT_CURLY_BRACE:
0562: break loop;
0563: default:
0564: parseRuleSet();
0565: }
0566: }
0567:
0568: nextIgnoreSpaces();
0569: }
0570: } finally {
0571: documentHandler.endMedia(ml);
0572: }
0573: }
0574:
0575: /**
0576: * Parses a ruleset.
0577: */
0578: protected void parseRuleSet() {
0579: SelectorList sl = null;
0580:
0581: try {
0582: sl = parseSelectorList();
0583: } catch (CSSParseException e) {
0584: reportError(e);
0585: return;
0586: }
0587:
0588: try {
0589: documentHandler.startSelector(sl);
0590:
0591: if (current != LexicalUnits.LEFT_CURLY_BRACE) {
0592: reportError("left.curly.brace");
0593: if (current == LexicalUnits.RIGHT_CURLY_BRACE) {
0594: nextIgnoreSpaces();
0595: }
0596: } else {
0597: nextIgnoreSpaces();
0598:
0599: try {
0600: parseStyleDeclaration(true);
0601: } catch (CSSParseException e) {
0602: reportError(e);
0603: }
0604: }
0605: } finally {
0606: documentHandler.endSelector(sl);
0607: }
0608: }
0609:
0610: /**
0611: * Parses a selector list
0612: */
0613: protected SelectorList parseSelectorList() {
0614: CSSSelectorList result = new CSSSelectorList();
0615: result.append(parseSelector());
0616:
0617: for (;;) {
0618: if (current != LexicalUnits.COMMA) {
0619: return result;
0620: }
0621: nextIgnoreSpaces();
0622: result.append(parseSelector());
0623: }
0624: }
0625:
0626: /**
0627: * Parses a selector.
0628: */
0629: protected Selector parseSelector() {
0630: SimpleSelector ss = parseSimpleSelector();
0631: Selector result = ss;
0632:
0633: pseudoElement = null;
0634:
0635: loop: for (;;) {
0636: switch (current) {
0637: default:
0638: break loop;
0639: case LexicalUnits.IDENTIFIER:
0640: case LexicalUnits.ANY:
0641: case LexicalUnits.HASH:
0642: case LexicalUnits.DOT:
0643: case LexicalUnits.LEFT_BRACKET:
0644: case LexicalUnits.COLON:
0645: result = selectorFactory.createDescendantSelector(
0646: result, parseSimpleSelector());
0647: break;
0648: case LexicalUnits.PLUS:
0649: nextIgnoreSpaces();
0650: result = selectorFactory.createDirectAdjacentSelector(
0651: (short) 1, result, parseSimpleSelector());
0652: break;
0653: case LexicalUnits.PRECEDE:
0654: nextIgnoreSpaces();
0655: result = selectorFactory.createChildSelector(result,
0656: parseSimpleSelector());
0657: }
0658: }
0659: if (pseudoElement != null) {
0660: result = selectorFactory.createChildSelector(result,
0661: selectorFactory.createPseudoElementSelector(null,
0662: pseudoElement));
0663: }
0664: return result;
0665: }
0666:
0667: /**
0668: * Parses a simple selector.
0669: */
0670: protected SimpleSelector parseSimpleSelector() {
0671: SimpleSelector result;
0672:
0673: switch (current) {
0674: case LexicalUnits.IDENTIFIER:
0675: result = selectorFactory.createElementSelector(null,
0676: scanner.getStringValue());
0677: next();
0678: break;
0679: case LexicalUnits.ANY:
0680: next();
0681: default:
0682: result = selectorFactory.createElementSelector(null, null);
0683: }
0684: Condition cond = null;
0685: loop: for (;;) {
0686: Condition c = null;
0687: switch (current) {
0688: case LexicalUnits.HASH:
0689: c = conditionFactory.createIdCondition(scanner
0690: .getStringValue());
0691: next();
0692: break;
0693: case LexicalUnits.DOT:
0694: if (next() != LexicalUnits.IDENTIFIER) {
0695: throw createCSSParseException("identifier");
0696: }
0697: c = conditionFactory.createClassCondition(null, scanner
0698: .getStringValue());
0699: next();
0700: break;
0701: case LexicalUnits.LEFT_BRACKET:
0702: if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) {
0703: throw createCSSParseException("identifier");
0704: }
0705: String name = scanner.getStringValue();
0706: int op = nextIgnoreSpaces();
0707: switch (op) {
0708: default:
0709: throw createCSSParseException("right.bracket");
0710: case LexicalUnits.RIGHT_BRACKET:
0711: nextIgnoreSpaces();
0712: c = conditionFactory.createAttributeCondition(name,
0713: null, false, null);
0714: break;
0715: case LexicalUnits.EQUAL:
0716: case LexicalUnits.INCLUDES:
0717: case LexicalUnits.DASHMATCH:
0718: String val = null;
0719: switch (nextIgnoreSpaces()) {
0720: default:
0721: throw createCSSParseException("identifier.or.string");
0722: case LexicalUnits.STRING:
0723: case LexicalUnits.IDENTIFIER:
0724: val = scanner.getStringValue();
0725: nextIgnoreSpaces();
0726: }
0727: if (current != LexicalUnits.RIGHT_BRACKET) {
0728: throw createCSSParseException("right.bracket");
0729: }
0730: next();
0731: switch (op) {
0732: case LexicalUnits.EQUAL:
0733: c = conditionFactory.createAttributeCondition(
0734: name, null, false, val);
0735: break;
0736: case LexicalUnits.INCLUDES:
0737: c = conditionFactory
0738: .createOneOfAttributeCondition(name,
0739: null, false, val);
0740: break;
0741: default:
0742: c = conditionFactory
0743: .createBeginHyphenAttributeCondition(
0744: name, null, false, val);
0745: }
0746: }
0747: break;
0748: case LexicalUnits.COLON:
0749: switch (nextIgnoreSpaces()) {
0750: case LexicalUnits.IDENTIFIER:
0751: String val = scanner.getStringValue();
0752: if (isPseudoElement(val)) {
0753: if (pseudoElement != null) {
0754: throw createCSSParseException("duplicate.pseudo.element");
0755: }
0756: pseudoElement = val;
0757: } else {
0758: c = conditionFactory
0759: .createPseudoClassCondition(null, val);
0760: }
0761: next();
0762: break;
0763: case LexicalUnits.FUNCTION:
0764: String func = scanner.getStringValue();
0765: if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) {
0766: throw createCSSParseException("identifier");
0767: }
0768: String lang = scanner.getStringValue();
0769: if (nextIgnoreSpaces() != LexicalUnits.RIGHT_BRACE) {
0770: throw createCSSParseException("right.brace");
0771: }
0772:
0773: if (!func.equalsIgnoreCase("lang")) {
0774: throw createCSSParseException("pseudo.function");
0775: }
0776:
0777: c = conditionFactory.createLangCondition(lang);
0778:
0779: next();
0780: break;
0781: default:
0782: throw createCSSParseException("identifier");
0783: }
0784: break;
0785: default:
0786: break loop;
0787: }
0788: if (c != null) {
0789: if (cond == null) {
0790: cond = c;
0791: } else {
0792: cond = conditionFactory.createAndCondition(cond, c);
0793: }
0794: }
0795: }
0796: skipSpaces();
0797: if (cond != null) {
0798: result = selectorFactory.createConditionalSelector(result,
0799: cond);
0800: }
0801: return result;
0802: }
0803:
0804: /**
0805: * Tells whether or not the given string represents a pseudo-element.
0806: */
0807: protected boolean isPseudoElement(String s) {
0808: switch (s.charAt(0)) {
0809: case 'a':
0810: case 'A':
0811: return s.equalsIgnoreCase("after");
0812: case 'b':
0813: case 'B':
0814: return s.equalsIgnoreCase("before");
0815: case 'f':
0816: case 'F':
0817: return s.equalsIgnoreCase("first-letter")
0818: || s.equalsIgnoreCase("first-line");
0819: }
0820: return false;
0821: }
0822:
0823: /**
0824: * Parses the given reader.
0825: */
0826: protected void parseStyleDeclaration(boolean inSheet)
0827: throws CSSException {
0828: for (;;) {
0829: switch (current) {
0830: case LexicalUnits.EOF:
0831: if (inSheet) {
0832: throw createCSSParseException("eof");
0833: }
0834: return;
0835: case LexicalUnits.RIGHT_CURLY_BRACE:
0836: if (!inSheet) {
0837: throw createCSSParseException("eof.expected");
0838: }
0839: nextIgnoreSpaces();
0840: return;
0841: case LexicalUnits.SEMI_COLON:
0842: nextIgnoreSpaces();
0843: continue;
0844: default:
0845: throw createCSSParseException("identifier");
0846: case LexicalUnits.IDENTIFIER:
0847: }
0848:
0849: String name = scanner.getStringValue();
0850:
0851: if (nextIgnoreSpaces() != LexicalUnits.COLON) {
0852: throw createCSSParseException("colon");
0853: }
0854: nextIgnoreSpaces();
0855:
0856: LexicalUnit exp = null;
0857:
0858: try {
0859: exp = parseExpression(false);
0860: } catch (CSSParseException e) {
0861: reportError(e);
0862: }
0863:
0864: if (exp != null) {
0865: boolean important = false;
0866: if (current == LexicalUnits.IMPORTANT_SYMBOL) {
0867: important = true;
0868: nextIgnoreSpaces();
0869: }
0870: documentHandler.property(name, exp, important);
0871: }
0872: }
0873: }
0874:
0875: /**
0876: * Parses a CSS2 expression.
0877: * @param param whether the expression to be parsed is a function parameter
0878: */
0879: protected LexicalUnit parseExpression(boolean param) {
0880: LexicalUnit result = parseTerm(null);
0881: LexicalUnit curr = result;
0882:
0883: for (;;) {
0884: boolean op = false;
0885: switch (current) {
0886: case LexicalUnits.COMMA:
0887: op = true;
0888: curr = CSSLexicalUnit.createSimple(
0889: LexicalUnit.SAC_OPERATOR_COMMA, curr);
0890: nextIgnoreSpaces();
0891: break;
0892: case LexicalUnits.DIVIDE:
0893: op = true;
0894: curr = CSSLexicalUnit.createSimple(
0895: LexicalUnit.SAC_OPERATOR_SLASH, curr);
0896: nextIgnoreSpaces();
0897: }
0898: if (param) {
0899: if (current == LexicalUnits.RIGHT_BRACE) {
0900: if (op) {
0901: throw createCSSParseException("token",
0902: new Object[] { new Integer(current) });
0903: }
0904: return result;
0905: }
0906: curr = parseTerm(curr);
0907: } else {
0908: switch (current) {
0909: case LexicalUnits.IMPORTANT_SYMBOL:
0910: case LexicalUnits.SEMI_COLON:
0911: case LexicalUnits.RIGHT_CURLY_BRACE:
0912: case LexicalUnits.EOF:
0913: if (op) {
0914: throw createCSSParseException("token",
0915: new Object[] { new Integer(current) });
0916: }
0917: return result;
0918: default:
0919: curr = parseTerm(curr);
0920: }
0921: }
0922: }
0923: }
0924:
0925: /**
0926: * Parses a CSS2 term.
0927: */
0928: protected LexicalUnit parseTerm(LexicalUnit prev) {
0929: boolean plus = true;
0930: boolean sgn = false;
0931:
0932: switch (current) {
0933: case LexicalUnits.MINUS:
0934: plus = false;
0935: case LexicalUnits.PLUS:
0936: next();
0937: sgn = true;
0938: default:
0939: switch (current) {
0940: case LexicalUnits.INTEGER:
0941: String sval = scanner.getStringValue();
0942: if (!plus)
0943: sval = "-" + sval;
0944:
0945: long lVal = Long.parseLong(sval); // fix #41288
0946: if (lVal >= Integer.MIN_VALUE
0947: && lVal <= Integer.MAX_VALUE) {
0948: // we can safely convert to int
0949: int iVal = (int) lVal;
0950: nextIgnoreSpaces();
0951: return CSSLexicalUnit.createInteger(iVal, prev);
0952: }
0953:
0954: // we are too large for an int: convert to float
0955: // we can just fall-through to the float-handling ...
0956: case LexicalUnits.REAL:
0957: return CSSLexicalUnit.createFloat(LexicalUnit.SAC_REAL,
0958: number(plus), prev);
0959: case LexicalUnits.PERCENTAGE:
0960: return CSSLexicalUnit.createFloat(
0961: LexicalUnit.SAC_PERCENTAGE, number(plus), prev);
0962: case LexicalUnits.PT:
0963: return CSSLexicalUnit.createFloat(
0964: LexicalUnit.SAC_POINT, number(plus), prev);
0965: case LexicalUnits.PC:
0966: return CSSLexicalUnit.createFloat(LexicalUnit.SAC_PICA,
0967: number(plus), prev);
0968: case LexicalUnits.PX:
0969: return CSSLexicalUnit.createFloat(
0970: LexicalUnit.SAC_PIXEL, number(plus), prev);
0971: case LexicalUnits.CM:
0972: return CSSLexicalUnit.createFloat(
0973: LexicalUnit.SAC_CENTIMETER, number(plus), prev);
0974: case LexicalUnits.MM:
0975: return CSSLexicalUnit.createFloat(
0976: LexicalUnit.SAC_MILLIMETER, number(plus), prev);
0977: case LexicalUnits.IN:
0978: return CSSLexicalUnit.createFloat(LexicalUnit.SAC_INCH,
0979: number(plus), prev);
0980: case LexicalUnits.EM:
0981: return CSSLexicalUnit.createFloat(LexicalUnit.SAC_EM,
0982: number(plus), prev);
0983: case LexicalUnits.EX:
0984: return CSSLexicalUnit.createFloat(LexicalUnit.SAC_EX,
0985: number(plus), prev);
0986: case LexicalUnits.DEG:
0987: return CSSLexicalUnit.createFloat(
0988: LexicalUnit.SAC_DEGREE, number(plus), prev);
0989: case LexicalUnits.RAD:
0990: return CSSLexicalUnit.createFloat(
0991: LexicalUnit.SAC_RADIAN, number(plus), prev);
0992: case LexicalUnits.GRAD:
0993: return CSSLexicalUnit.createFloat(
0994: LexicalUnit.SAC_GRADIAN, number(plus), prev);
0995: case LexicalUnits.S:
0996: return CSSLexicalUnit.createFloat(
0997: LexicalUnit.SAC_SECOND, number(plus), prev);
0998: case LexicalUnits.MS:
0999: return CSSLexicalUnit
1000: .createFloat(LexicalUnit.SAC_MILLISECOND,
1001: number(plus), prev);
1002: case LexicalUnits.HZ:
1003: return CSSLexicalUnit.createFloat(
1004: LexicalUnit.SAC_HERTZ, number(plus), prev);
1005: case LexicalUnits.KHZ:
1006: return CSSLexicalUnit.createFloat(
1007: LexicalUnit.SAC_KILOHERTZ, number(plus), prev);
1008: case LexicalUnits.DIMENSION:
1009: return dimension(plus, prev);
1010: case LexicalUnits.FUNCTION:
1011: return parseFunction(plus, prev);
1012: }
1013: if (sgn) {
1014: throw createCSSParseException("token",
1015: new Object[] { new Integer(current) });
1016: }
1017: }
1018: switch (current) {
1019: case LexicalUnits.STRING:
1020: String val = scanner.getStringValue();
1021: nextIgnoreSpaces();
1022: return CSSLexicalUnit.createString(
1023: LexicalUnit.SAC_STRING_VALUE, val, prev);
1024: case LexicalUnits.IDENTIFIER:
1025: val = scanner.getStringValue();
1026: nextIgnoreSpaces();
1027: if (val.equalsIgnoreCase("inherit")) {
1028: return CSSLexicalUnit.createSimple(
1029: LexicalUnit.SAC_INHERIT, prev);
1030: } else {
1031: return CSSLexicalUnit.createString(
1032: LexicalUnit.SAC_IDENT, val, prev);
1033: }
1034: case LexicalUnits.URI:
1035: val = scanner.getStringValue();
1036: nextIgnoreSpaces();
1037: return CSSLexicalUnit.createString(LexicalUnit.SAC_URI,
1038: val, prev);
1039: case LexicalUnits.HASH:
1040: return hexcolor(prev);
1041: default:
1042: throw createCSSParseException("token",
1043: new Object[] { new Integer(current) });
1044: }
1045: }
1046:
1047: /**
1048: * Parses a CSS2 function.
1049: */
1050: protected LexicalUnit parseFunction(boolean positive,
1051: LexicalUnit prev) {
1052: String name = scanner.getStringValue();
1053: nextIgnoreSpaces();
1054:
1055: LexicalUnit params = parseExpression(true);
1056:
1057: if (current != LexicalUnits.RIGHT_BRACE) {
1058: throw createCSSParseException("token",
1059: new Object[] { new Integer(current) });
1060: }
1061: nextIgnoreSpaces();
1062:
1063: predefined: switch (name.charAt(0)) {
1064: case 'r':
1065: case 'R':
1066: LexicalUnit lu;
1067: if (name.equalsIgnoreCase("rgb")) {
1068: lu = params;
1069: if (lu == null) {
1070: break;
1071: }
1072: switch (lu.getLexicalUnitType()) {
1073: default:
1074: break predefined;
1075: case LexicalUnit.SAC_INTEGER:
1076: case LexicalUnit.SAC_PERCENTAGE:
1077: lu = lu.getNextLexicalUnit();
1078: }
1079: if (lu == null) {
1080: break;
1081: }
1082: switch (lu.getLexicalUnitType()) {
1083: default:
1084: break predefined;
1085: case LexicalUnit.SAC_OPERATOR_COMMA:
1086: lu = lu.getNextLexicalUnit();
1087: }
1088: if (lu == null) {
1089: break;
1090: }
1091: switch (lu.getLexicalUnitType()) {
1092: default:
1093: break predefined;
1094: case LexicalUnit.SAC_INTEGER:
1095: case LexicalUnit.SAC_PERCENTAGE:
1096: lu = lu.getNextLexicalUnit();
1097: }
1098: if (lu == null) {
1099: break;
1100: }
1101: switch (lu.getLexicalUnitType()) {
1102: default:
1103: break predefined;
1104: case LexicalUnit.SAC_OPERATOR_COMMA:
1105: lu = lu.getNextLexicalUnit();
1106: }
1107: if (lu == null) {
1108: break;
1109: }
1110: switch (lu.getLexicalUnitType()) {
1111: default:
1112: break predefined;
1113: case LexicalUnit.SAC_INTEGER:
1114: case LexicalUnit.SAC_PERCENTAGE:
1115: lu = lu.getNextLexicalUnit();
1116: }
1117: if (lu != null) {
1118: break;
1119: }
1120: return CSSLexicalUnit.createPredefinedFunction(
1121: LexicalUnit.SAC_RGBCOLOR, params, prev);
1122: } else if (name.equalsIgnoreCase("rect")) {
1123: lu = params;
1124: if (lu == null) {
1125: break;
1126: }
1127: switch (lu.getLexicalUnitType()) {
1128: default:
1129: break predefined;
1130: case LexicalUnit.SAC_INTEGER:
1131: if (lu.getIntegerValue() != 0) {
1132: break predefined;
1133: }
1134: lu = lu.getNextLexicalUnit();
1135: break;
1136: case LexicalUnit.SAC_IDENT:
1137: if (!lu.getStringValue().equalsIgnoreCase("auto")) {
1138: break predefined;
1139: }
1140: lu = lu.getNextLexicalUnit();
1141: break;
1142: case LexicalUnit.SAC_EM:
1143: case LexicalUnit.SAC_EX:
1144: case LexicalUnit.SAC_PIXEL:
1145: case LexicalUnit.SAC_CENTIMETER:
1146: case LexicalUnit.SAC_MILLIMETER:
1147: case LexicalUnit.SAC_INCH:
1148: case LexicalUnit.SAC_POINT:
1149: case LexicalUnit.SAC_PICA:
1150: case LexicalUnit.SAC_PERCENTAGE:
1151: lu = lu.getNextLexicalUnit();
1152: }
1153: if (lu == null) {
1154: break;
1155: }
1156: switch (lu.getLexicalUnitType()) {
1157: default:
1158: break predefined;
1159: case LexicalUnit.SAC_OPERATOR_COMMA:
1160: lu = lu.getNextLexicalUnit();
1161: }
1162: if (lu == null) {
1163: break;
1164: }
1165: switch (lu.getLexicalUnitType()) {
1166: default:
1167: break predefined;
1168: case LexicalUnit.SAC_INTEGER:
1169: if (lu.getIntegerValue() != 0) {
1170: break predefined;
1171: }
1172: lu = lu.getNextLexicalUnit();
1173: break;
1174: case LexicalUnit.SAC_IDENT:
1175: if (!lu.getStringValue().equalsIgnoreCase("auto")) {
1176: break predefined;
1177: }
1178: lu = lu.getNextLexicalUnit();
1179: break;
1180: case LexicalUnit.SAC_EM:
1181: case LexicalUnit.SAC_EX:
1182: case LexicalUnit.SAC_PIXEL:
1183: case LexicalUnit.SAC_CENTIMETER:
1184: case LexicalUnit.SAC_MILLIMETER:
1185: case LexicalUnit.SAC_INCH:
1186: case LexicalUnit.SAC_POINT:
1187: case LexicalUnit.SAC_PICA:
1188: case LexicalUnit.SAC_PERCENTAGE:
1189: lu = lu.getNextLexicalUnit();
1190: }
1191: if (lu == null) {
1192: break;
1193: }
1194: switch (lu.getLexicalUnitType()) {
1195: default:
1196: break predefined;
1197: case LexicalUnit.SAC_OPERATOR_COMMA:
1198: lu = lu.getNextLexicalUnit();
1199: }
1200: if (lu == null) {
1201: break;
1202: }
1203: switch (lu.getLexicalUnitType()) {
1204: default:
1205: break predefined;
1206: case LexicalUnit.SAC_INTEGER:
1207: if (lu.getIntegerValue() != 0) {
1208: break predefined;
1209: }
1210: lu = lu.getNextLexicalUnit();
1211: break;
1212: case LexicalUnit.SAC_IDENT:
1213: if (!lu.getStringValue().equalsIgnoreCase("auto")) {
1214: break predefined;
1215: }
1216: lu = lu.getNextLexicalUnit();
1217: break;
1218: case LexicalUnit.SAC_EM:
1219: case LexicalUnit.SAC_EX:
1220: case LexicalUnit.SAC_PIXEL:
1221: case LexicalUnit.SAC_CENTIMETER:
1222: case LexicalUnit.SAC_MILLIMETER:
1223: case LexicalUnit.SAC_INCH:
1224: case LexicalUnit.SAC_POINT:
1225: case LexicalUnit.SAC_PICA:
1226: case LexicalUnit.SAC_PERCENTAGE:
1227: lu = lu.getNextLexicalUnit();
1228: }
1229: if (lu == null) {
1230: break;
1231: }
1232: switch (lu.getLexicalUnitType()) {
1233: default:
1234: break predefined;
1235: case LexicalUnit.SAC_OPERATOR_COMMA:
1236: lu = lu.getNextLexicalUnit();
1237: }
1238: if (lu == null) {
1239: break;
1240: }
1241: switch (lu.getLexicalUnitType()) {
1242: default:
1243: break predefined;
1244: case LexicalUnit.SAC_INTEGER:
1245: if (lu.getIntegerValue() != 0) {
1246: break predefined;
1247: }
1248: lu = lu.getNextLexicalUnit();
1249: break;
1250: case LexicalUnit.SAC_IDENT:
1251: if (!lu.getStringValue().equalsIgnoreCase("auto")) {
1252: break predefined;
1253: }
1254: lu = lu.getNextLexicalUnit();
1255: break;
1256: case LexicalUnit.SAC_EM:
1257: case LexicalUnit.SAC_EX:
1258: case LexicalUnit.SAC_PIXEL:
1259: case LexicalUnit.SAC_CENTIMETER:
1260: case LexicalUnit.SAC_MILLIMETER:
1261: case LexicalUnit.SAC_INCH:
1262: case LexicalUnit.SAC_POINT:
1263: case LexicalUnit.SAC_PICA:
1264: case LexicalUnit.SAC_PERCENTAGE:
1265: lu = lu.getNextLexicalUnit();
1266: }
1267: if (lu != null) {
1268: break;
1269: }
1270: return CSSLexicalUnit.createPredefinedFunction(
1271: LexicalUnit.SAC_RECT_FUNCTION, params, prev);
1272: }
1273: break;
1274: case 'c':
1275: case 'C':
1276: if (name.equalsIgnoreCase("counter")) {
1277: lu = params;
1278: if (lu == null) {
1279: break;
1280: }
1281: switch (lu.getLexicalUnitType()) {
1282: default:
1283: break predefined;
1284: case LexicalUnit.SAC_IDENT:
1285: lu = lu.getNextLexicalUnit();
1286: }
1287: if (lu == null) {
1288: break;
1289: }
1290: switch (lu.getLexicalUnitType()) {
1291: default:
1292: break predefined;
1293: case LexicalUnit.SAC_OPERATOR_COMMA:
1294: lu = lu.getNextLexicalUnit();
1295: }
1296: if (lu == null) {
1297: break;
1298: }
1299: switch (lu.getLexicalUnitType()) {
1300: default:
1301: break predefined;
1302: case LexicalUnit.SAC_IDENT:
1303: lu = lu.getNextLexicalUnit();
1304: }
1305: if (lu != null) {
1306: break;
1307: }
1308: return CSSLexicalUnit.createPredefinedFunction(
1309: LexicalUnit.SAC_COUNTER_FUNCTION, params, prev);
1310: } else if (name.equalsIgnoreCase("counters")) {
1311: lu = params;
1312: if (lu == null) {
1313: break;
1314: }
1315: switch (lu.getLexicalUnitType()) {
1316: default:
1317: break predefined;
1318: case LexicalUnit.SAC_IDENT:
1319: lu = lu.getNextLexicalUnit();
1320: }
1321: if (lu == null) {
1322: break;
1323: }
1324: switch (lu.getLexicalUnitType()) {
1325: default:
1326: break predefined;
1327: case LexicalUnit.SAC_OPERATOR_COMMA:
1328: lu = lu.getNextLexicalUnit();
1329: }
1330: if (lu == null) {
1331: break;
1332: }
1333: switch (lu.getLexicalUnitType()) {
1334: default:
1335: break predefined;
1336: case LexicalUnit.SAC_STRING_VALUE:
1337: lu = lu.getNextLexicalUnit();
1338: }
1339: if (lu == null) {
1340: break;
1341: }
1342: switch (lu.getLexicalUnitType()) {
1343: default:
1344: break predefined;
1345: case LexicalUnit.SAC_OPERATOR_COMMA:
1346: lu = lu.getNextLexicalUnit();
1347: }
1348: if (lu == null) {
1349: break;
1350: }
1351: switch (lu.getLexicalUnitType()) {
1352: default:
1353: break predefined;
1354: case LexicalUnit.SAC_IDENT:
1355: lu = lu.getNextLexicalUnit();
1356: }
1357: if (lu != null) {
1358: break;
1359: }
1360: return CSSLexicalUnit
1361: .createPredefinedFunction(
1362: LexicalUnit.SAC_COUNTERS_FUNCTION,
1363: params, prev);
1364: }
1365: break;
1366: case 'a':
1367: case 'A':
1368: if (name.equalsIgnoreCase("attr")) {
1369: lu = params;
1370: if (lu == null) {
1371: break;
1372: }
1373: switch (lu.getLexicalUnitType()) {
1374: default:
1375: break predefined;
1376: case LexicalUnit.SAC_IDENT:
1377: lu = lu.getNextLexicalUnit();
1378: }
1379: if (lu != null) {
1380: break;
1381: }
1382: return CSSLexicalUnit.createString(
1383: LexicalUnit.SAC_ATTR, params.getStringValue(),
1384: prev);
1385: }
1386: }
1387:
1388: return CSSLexicalUnit.createFunction(name, params, prev);
1389: }
1390:
1391: /**
1392: * Converts a hash unit to a RGB color.
1393: */
1394: protected LexicalUnit hexcolor(LexicalUnit prev) {
1395: String val = scanner.getStringValue();
1396: int len = val.length();
1397: LexicalUnit params = null;
1398: switch (len) {
1399: case 3:
1400: char rc = Character.toLowerCase(val.charAt(0));
1401: char gc = Character.toLowerCase(val.charAt(1));
1402: char bc = Character.toLowerCase(val.charAt(2));
1403: if (!ScannerUtilities.isCSSHexadecimalCharacter(rc)
1404: || !ScannerUtilities.isCSSHexadecimalCharacter(gc)
1405: || !ScannerUtilities.isCSSHexadecimalCharacter(bc)) {
1406: throw createCSSParseException("rgb.color",
1407: new Object[] { val });
1408: }
1409: int t;
1410: int r = t = (rc >= '0' && rc <= '9') ? rc - '0'
1411: : rc - 'a' + 10;
1412: t <<= 4;
1413: r |= t;
1414: int g = t = (gc >= '0' && gc <= '9') ? gc - '0'
1415: : gc - 'a' + 10;
1416: t <<= 4;
1417: g |= t;
1418: int b = t = (bc >= '0' && bc <= '9') ? bc - '0'
1419: : bc - 'a' + 10;
1420: t <<= 4;
1421: b |= t;
1422: params = CSSLexicalUnit.createInteger(r, null);
1423: LexicalUnit tmp;
1424: tmp = CSSLexicalUnit.createSimple(
1425: LexicalUnit.SAC_OPERATOR_COMMA, params);
1426: tmp = CSSLexicalUnit.createInteger(g, tmp);
1427: tmp = CSSLexicalUnit.createSimple(
1428: LexicalUnit.SAC_OPERATOR_COMMA, tmp);
1429: tmp = CSSLexicalUnit.createInteger(b, tmp);
1430: break;
1431: case 6:
1432: char rc1 = Character.toLowerCase(val.charAt(0));
1433: char rc2 = Character.toLowerCase(val.charAt(1));
1434: char gc1 = Character.toLowerCase(val.charAt(2));
1435: char gc2 = Character.toLowerCase(val.charAt(3));
1436: char bc1 = Character.toLowerCase(val.charAt(4));
1437: char bc2 = Character.toLowerCase(val.charAt(5));
1438: if (!ScannerUtilities.isCSSHexadecimalCharacter(rc1)
1439: || !ScannerUtilities.isCSSHexadecimalCharacter(rc2)
1440: || !ScannerUtilities.isCSSHexadecimalCharacter(gc1)
1441: || !ScannerUtilities.isCSSHexadecimalCharacter(gc2)
1442: || !ScannerUtilities.isCSSHexadecimalCharacter(bc1)
1443: || !ScannerUtilities.isCSSHexadecimalCharacter(bc2)) {
1444: throw createCSSParseException("rgb.color");
1445: }
1446: r = (rc1 >= '0' && rc1 <= '9') ? rc1 - '0' : rc1 - 'a' + 10;
1447: r <<= 4;
1448: r |= (rc2 >= '0' && rc2 <= '9') ? rc2 - '0'
1449: : rc2 - 'a' + 10;
1450: g = (gc1 >= '0' && gc1 <= '9') ? gc1 - '0' : gc1 - 'a' + 10;
1451: g <<= 4;
1452: g |= (gc2 >= '0' && gc2 <= '9') ? gc2 - '0'
1453: : gc2 - 'a' + 10;
1454: b = (bc1 >= '0' && bc1 <= '9') ? bc1 - '0' : bc1 - 'a' + 10;
1455: b <<= 4;
1456: b |= (bc2 >= '0' && bc2 <= '9') ? bc2 - '0'
1457: : bc2 - 'a' + 10;
1458: params = CSSLexicalUnit.createInteger(r, null);
1459: tmp = CSSLexicalUnit.createSimple(
1460: LexicalUnit.SAC_OPERATOR_COMMA, params);
1461: tmp = CSSLexicalUnit.createInteger(g, tmp);
1462: tmp = CSSLexicalUnit.createSimple(
1463: LexicalUnit.SAC_OPERATOR_COMMA, tmp);
1464: tmp = CSSLexicalUnit.createInteger(b, tmp);
1465: break;
1466: default:
1467: throw createCSSParseException("rgb.color",
1468: new Object[] { val });
1469: }
1470: nextIgnoreSpaces();
1471: return CSSLexicalUnit.createPredefinedFunction(
1472: LexicalUnit.SAC_RGBCOLOR, params, prev);
1473: }
1474:
1475: /**
1476: * Creates a scanner, given an InputSource.
1477: */
1478: protected Scanner createScanner(InputSource source) {
1479: documentURI = source.getURI();
1480: if (documentURI == null) {
1481: documentURI = "";
1482: }
1483:
1484: Reader r = source.getCharacterStream();
1485: if (r != null) {
1486: return new Scanner(r);
1487: }
1488:
1489: InputStream is = source.getByteStream();
1490: if (is != null) {
1491: return new Scanner(is, source.getEncoding());
1492: }
1493:
1494: String uri = source.getURI();
1495: if (uri == null) {
1496: throw new CSSException(formatMessage("empty.source", null));
1497: }
1498:
1499: try {
1500: ParsedURL purl = new ParsedURL(uri);
1501: is = purl.openStreamRaw(CSSConstants.CSS_MIME_TYPE);
1502: return new Scanner(is, source.getEncoding());
1503: } catch (IOException e) {
1504: throw new CSSException(e);
1505: }
1506: }
1507:
1508: /**
1509: * Skips the white spaces.
1510: */
1511: protected int skipSpaces() {
1512: int lex = scanner.getType();
1513: while (lex == LexicalUnits.SPACE) {
1514: lex = next();
1515: }
1516: return lex;
1517: }
1518:
1519: /**
1520: * Skips the white spaces and CDO/CDC units.
1521: */
1522: protected int skipSpacesAndCDOCDC() {
1523: loop: for (;;) {
1524: switch (current) {
1525: default:
1526: break loop;
1527: case LexicalUnits.COMMENT:
1528: case LexicalUnits.SPACE:
1529: case LexicalUnits.CDO:
1530: case LexicalUnits.CDC:
1531: }
1532: scanner.clearBuffer();
1533: next();
1534: }
1535: return current;
1536: }
1537:
1538: /**
1539: * Converts the current lexical unit to a float.
1540: */
1541: protected float number(boolean positive) {
1542: try {
1543: float sgn = (positive) ? 1 : -1;
1544: String val = scanner.getStringValue();
1545: nextIgnoreSpaces();
1546: return sgn * Float.parseFloat(val);
1547: } catch (NumberFormatException e) {
1548: throw createCSSParseException("number.format");
1549: }
1550: }
1551:
1552: /**
1553: * Converts the current lexical unit to a dimension.
1554: */
1555: protected LexicalUnit dimension(boolean positive, LexicalUnit prev) {
1556: try {
1557: float sgn = (positive) ? 1 : -1;
1558: String val = scanner.getStringValue();
1559: int i;
1560: loop: for (i = 0; i < val.length(); i++) {
1561: switch (val.charAt(i)) {
1562: default:
1563: break loop;
1564: case '0':
1565: case '1':
1566: case '2':
1567: case '3':
1568: case '4':
1569: case '5':
1570: case '6':
1571: case '7':
1572: case '8':
1573: case '9':
1574: case '.':
1575: }
1576: }
1577: nextIgnoreSpaces();
1578: return CSSLexicalUnit.createDimension(sgn
1579: * Float.parseFloat(val.substring(0, i)), val
1580: .substring(i), prev);
1581: } catch (NumberFormatException e) {
1582: throw createCSSParseException("number.format");
1583: }
1584: }
1585:
1586: /**
1587: * Advances to the next token, ignoring comments.
1588: */
1589: protected int next() {
1590: try {
1591: for (;;) {
1592: scanner.clearBuffer();
1593: current = scanner.next();
1594: if (current == LexicalUnits.COMMENT) {
1595: documentHandler.comment(scanner.getStringValue());
1596: } else {
1597: break;
1598: }
1599: }
1600: return current;
1601: } catch (ParseException e) {
1602: reportError(e.getMessage());
1603: return current;
1604: }
1605: }
1606:
1607: /**
1608: * Advances to the next token and skip the spaces, ignoring comments.
1609: */
1610: protected int nextIgnoreSpaces() {
1611: try {
1612: loop: for (;;) {
1613: scanner.clearBuffer();
1614: current = scanner.next();
1615: switch (current) {
1616: case LexicalUnits.COMMENT:
1617: documentHandler.comment(scanner.getStringValue());
1618: break;
1619: default:
1620: break loop;
1621: case LexicalUnits.SPACE:
1622: }
1623: }
1624: return current;
1625: } catch (ParseException e) {
1626: errorHandler.error(createCSSParseException(e.getMessage()));
1627: return current;
1628: }
1629: }
1630:
1631: /**
1632: * Reports a parsing error.
1633: */
1634: protected void reportError(String key) {
1635: reportError(key, null);
1636: }
1637:
1638: /**
1639: * Reports a parsing error.
1640: */
1641: protected void reportError(String key, Object[] params) {
1642: reportError(createCSSParseException(key, params));
1643: }
1644:
1645: /**
1646: * Reports a parsing error.
1647: */
1648: protected void reportError(CSSParseException e) {
1649: errorHandler.error(e);
1650:
1651: int cbraces = 1;
1652: for (;;) {
1653: switch (current) {
1654: case LexicalUnits.EOF:
1655: return;
1656: case LexicalUnits.SEMI_COLON:
1657: case LexicalUnits.RIGHT_CURLY_BRACE:
1658: if (--cbraces == 0) {
1659: nextIgnoreSpaces();
1660: return;
1661: }
1662: case LexicalUnits.LEFT_CURLY_BRACE:
1663: cbraces++;
1664: }
1665: nextIgnoreSpaces();
1666: }
1667: }
1668:
1669: /**
1670: * Creates a parse exception.
1671: */
1672: protected CSSParseException createCSSParseException(String key) {
1673: return createCSSParseException(key, null);
1674: }
1675:
1676: /**
1677: * Creates a parse exception.
1678: */
1679: protected CSSParseException createCSSParseException(String key,
1680: Object[] params) {
1681: return new CSSParseException(formatMessage(key, params),
1682: documentURI, scanner.getLine(), scanner.getColumn());
1683: }
1684:
1685: // -----------------------------------------------------------------------
1686: // Extended methods
1687: // -----------------------------------------------------------------------
1688:
1689: /**
1690: * Implements {@link ExtendedParser#parseStyleDeclaration(String)}.
1691: */
1692: public void parseStyleDeclaration(String source)
1693: throws CSSException, IOException {
1694: scanner = new Scanner(source);
1695: parseStyleDeclarationInternal();
1696: }
1697:
1698: /**
1699: * Implements {@link ExtendedParser#parseRule(String)}.
1700: */
1701: public void parseRule(String source) throws CSSException,
1702: IOException {
1703: scanner = new Scanner(source);
1704: parseRuleInternal();
1705: }
1706:
1707: /**
1708: * Implements {@link ExtendedParser#parseSelectors(String)}.
1709: */
1710: public SelectorList parseSelectors(String source)
1711: throws CSSException, IOException {
1712: scanner = new Scanner(source);
1713: return parseSelectorsInternal();
1714: }
1715:
1716: /**
1717: * Implements {@link ExtendedParser#parsePropertyValue(String)}.
1718: */
1719: public LexicalUnit parsePropertyValue(String source)
1720: throws CSSException, IOException {
1721: scanner = new Scanner(source);
1722: return parsePropertyValueInternal();
1723: }
1724:
1725: /**
1726: * Implements {@link ExtendedParser#parsePriority(String)}.
1727: */
1728: public boolean parsePriority(String source) throws CSSException,
1729: IOException {
1730: scanner = new Scanner(source);
1731: return parsePriorityInternal();
1732: }
1733:
1734: /**
1735: * Implements {@link ExtendedParser#parseMedia(String)}.
1736: */
1737: public SACMediaList parseMedia(String mediaText)
1738: throws CSSException, IOException {
1739: CSSSACMediaList result = new CSSSACMediaList();
1740: if (!"all".equalsIgnoreCase(mediaText)) {
1741: StringTokenizer st = new StringTokenizer(mediaText, " ,");
1742: while (st.hasMoreTokens()) {
1743: result.append(st.nextToken());
1744: }
1745: }
1746: return result;
1747: }
1748: }
|