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