KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > css > parser > Parser


1 /*
2
3    Copyright 2000-2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.css.parser;
19
20 import java.io.IOException JavaDoc;
21 import java.io.InputStream JavaDoc;
22 import java.io.Reader JavaDoc;
23 import java.util.Locale JavaDoc;
24 import java.util.MissingResourceException JavaDoc;
25 import java.util.StringTokenizer JavaDoc;
26
27 import org.apache.batik.i18n.Localizable;
28 import org.apache.batik.i18n.LocalizableSupport;
29 import org.apache.batik.util.CSSConstants;
30 import org.apache.batik.util.ParsedURL;
31 import org.w3c.css.sac.CSSException;
32 import org.w3c.css.sac.CSSParseException;
33 import org.w3c.css.sac.Condition;
34 import org.w3c.css.sac.ConditionFactory;
35 import org.w3c.css.sac.DocumentHandler;
36 import org.w3c.css.sac.ErrorHandler;
37 import org.w3c.css.sac.InputSource;
38 import org.w3c.css.sac.LexicalUnit;
39 import org.w3c.css.sac.SACMediaList;
40 import org.w3c.css.sac.Selector;
41 import org.w3c.css.sac.SelectorFactory;
42 import org.w3c.css.sac.SelectorList;
43 import org.w3c.css.sac.SimpleSelector;
44
45 /**
46  * This class implements the {@link org.w3c.css.sac.Parser} interface.
47  *
48  * @author <a HREF="mailto:stephane@hillion.org">Stephane Hillion</a>
49  * @version $Id: Parser.java,v 1.28 2005/03/27 08:58:31 cam Exp $
50  */

51 public class Parser implements ExtendedParser, Localizable {
52
53     /**
54      * The default resource bundle base name.
55      */

56     public final static String JavaDoc BUNDLE_CLASSNAME =
57         "org.apache.batik.css.parser.resources.Messages";
58
59     /**
60      * The localizable support.
61      */

62     protected LocalizableSupport localizableSupport =
63         new LocalizableSupport(BUNDLE_CLASSNAME,
64                                Parser.class.getClassLoader());
65
66     /**
67      * The scanner used to scan the input source.
68      */

69     protected Scanner scanner;
70
71     /**
72      * The current lexical unit.
73      */

74     protected int current;
75
76     /**
77      * The document handler.
78      */

79     protected DocumentHandler documentHandler =
80         DefaultDocumentHandler.INSTANCE;
81
82     /**
83      * The selector factory.
84      */

85     protected SelectorFactory selectorFactory =
86         DefaultSelectorFactory.INSTANCE;
87
88     /**
89      * The condition factory.
90      */

91     protected ConditionFactory conditionFactory =
92         DefaultConditionFactory.INSTANCE;
93
94     /**
95      * The error handler.
96      */

97     protected ErrorHandler errorHandler = DefaultErrorHandler.INSTANCE;
98
99     /**
100      * To store the current pseudo element.
101      */

102     protected String JavaDoc pseudoElement;
103
104     /**
105      * The document URI.
106      */

107     protected String JavaDoc documentURI;
108
109     /**
110      * <b>SAC</b>: Implements {@link
111      * org.w3c.css.sac.Parser#getParserVersion()}.
112      * @return "http://www.w3.org/TR/REC-CSS2".
113      */

114     public String JavaDoc getParserVersion() {
115         return "http://www.w3.org/TR/REC-CSS2";
116     }
117     
118     /**
119      * <b>SAC</b>: Implements {@link org.w3c.css.sac.Parser#setLocale(Locale)}.
120      */

121     public void setLocale(Locale JavaDoc locale) throws CSSException {
122         localizableSupport.setLocale(locale);
123     }
124     
125     /**
126      * Implements {@link org.apache.batik.i18n.Localizable#getLocale()}.
127      */

128     public Locale JavaDoc getLocale() {
129         return localizableSupport.getLocale();
130     }
131
132     /**
133      * Implements {@link
134      * org.apache.batik.i18n.Localizable#formatMessage(String,Object[])}.
135      */

136     public String JavaDoc formatMessage(String JavaDoc key, Object JavaDoc[] args)
137         throws MissingResourceException JavaDoc {
138         return localizableSupport.formatMessage(key, args);
139     }
140
141     /**
142      * <b>SAC</b>: Implements {@link
143      * org.w3c.css.sac.Parser#setDocumentHandler(DocumentHandler)}.
144      */

145     public void setDocumentHandler(DocumentHandler handler) {
146         documentHandler = handler;
147     }
148
149     /**
150      * <b>SAC</b>: Implements {@link
151      * org.w3c.css.sac.Parser#setSelectorFactory(SelectorFactory)}.
152      */

153     public void setSelectorFactory(SelectorFactory factory) {
154         selectorFactory = factory;
155     }
156
157     /**
158      * <b>SAC</b>: Implements {@link
159      * org.w3c.css.sac.Parser#setConditionFactory(ConditionFactory)}.
160      */

161     public void setConditionFactory(ConditionFactory factory) {
162         conditionFactory = factory;
163     }
164     
165     /**
166      * <b>SAC</b>: Implements {@link
167      * org.w3c.css.sac.Parser#setErrorHandler(ErrorHandler)}.
168      */

169     public void setErrorHandler(ErrorHandler handler) {
170         errorHandler = handler;
171     }
172     
173     /**
174      * <b>SAC</b>: Implements {@link
175      * org.w3c.css.sac.Parser#parseStyleSheet(InputSource)}.
176      */

177     public void parseStyleSheet(InputSource source)
178         throws CSSException, IOException JavaDoc {
179         scanner = createScanner(source);
180
181         try {
182             documentHandler.startDocument(source);
183
184             current = scanner.next();
185             switch (current) {
186             case LexicalUnits.CHARSET_SYMBOL:
187                 if (nextIgnoreSpaces() != LexicalUnits.STRING) {
188                     reportError("charset.string");
189                 } else {
190                     if (nextIgnoreSpaces() != LexicalUnits.SEMI_COLON) {
191                         reportError("semicolon");
192                     }
193                     next();
194                 }
195                 break;
196             case LexicalUnits.COMMENT:
197                 documentHandler.comment(scanner.getStringValue());
198             }
199
200             skipSpacesAndCDOCDC();
201             for (;;) {
202                 if (current == LexicalUnits.IMPORT_SYMBOL) {
203                     nextIgnoreSpaces();
204                     parseImportRule();
205                     nextIgnoreSpaces();
206                 } else {
207                     break;
208                 }
209             }
210             
211             loop: for (;;) {
212                 switch (current) {
213                 case LexicalUnits.PAGE_SYMBOL:
214                     nextIgnoreSpaces();
215                     parsePageRule();
216                     break;
217                 case LexicalUnits.MEDIA_SYMBOL:
218                     nextIgnoreSpaces();
219                     parseMediaRule();
220                     break;
221                 case LexicalUnits.FONT_FACE_SYMBOL:
222                     nextIgnoreSpaces();
223                     parseFontFaceRule();
224                     break;
225                 case LexicalUnits.AT_KEYWORD:
226                     nextIgnoreSpaces();
227                     parseAtRule();
228                     break;
229                 case LexicalUnits.EOF:
230                     break loop;
231                 default:
232                     parseRuleSet();
233                 }
234                 skipSpacesAndCDOCDC();
235             }
236         } finally {
237             documentHandler.endDocument(source);
238             scanner = null;
239         }
240     }
241
242     /**
243      * <b>SAC</b>: Implements {@link
244      * org.w3c.css.sac.Parser#parseStyleSheet(String)}.
245      */

246     public void parseStyleSheet(String JavaDoc uri) throws CSSException, IOException JavaDoc {
247         parseStyleSheet(new InputSource(uri));
248     }
249
250     /**
251      * <b>SAC</b>: Implements {@link
252      * org.w3c.css.sac.Parser#parseStyleDeclaration(InputSource)}.
253      */

254     public void parseStyleDeclaration(InputSource source)
255         throws CSSException, IOException JavaDoc {
256
257         scanner = createScanner(source);
258     parseStyleDeclarationInternal();
259     }
260
261     /**
262      * Parses a style declaration using the current scanner.
263      */

264     protected void parseStyleDeclarationInternal()
265     throws CSSException, IOException JavaDoc {
266         nextIgnoreSpaces();
267         try {
268             parseStyleDeclaration(false);
269         } catch (CSSParseException e) {
270             reportError(e);
271         } finally {
272             scanner = null;
273         }
274     }
275
276     /**
277      * <b>SAC</b>: Implements {@link
278      * org.w3c.css.sac.Parser#parseRule(InputSource)}.
279      */

280     public void parseRule(InputSource source)
281     throws CSSException, IOException JavaDoc {
282         scanner = createScanner(source);
283     parseRuleInternal();
284     }
285
286     /**
287      * Parses a rule using the current scanner.
288      */

289     protected void parseRuleInternal() throws CSSException, IOException JavaDoc {
290         nextIgnoreSpaces();
291         parseRule();
292         scanner = null;
293     }
294
295     /**
296      * <b>SAC</b>: Implements {@link
297      * org.w3c.css.sac.Parser#parseSelectors(InputSource)}.
298      */

299     public SelectorList parseSelectors(InputSource source)
300         throws CSSException, IOException JavaDoc {
301         scanner = createScanner(source);
302     return parseSelectorsInternal();
303     }
304
305     /**
306      * Parses selectors using the current scanner.
307      */

308     protected SelectorList parseSelectorsInternal()
309     throws CSSException, IOException JavaDoc {
310         nextIgnoreSpaces();
311         SelectorList ret = parseSelectorList();
312         scanner = null;
313         return ret;
314     }
315
316     /**
317      * <b>SAC</b>: Implements
318      * {@link org.w3c.css.sac.Parser#parsePropertyValue(InputSource)}.
319      */

320     public LexicalUnit parsePropertyValue(InputSource source)
321         throws CSSException, IOException JavaDoc {
322         scanner = createScanner(source);
323     return parsePropertyValueInternal();
324     }
325
326     /**
327      * Parses property value using the current scanner.
328      */

329     protected LexicalUnit parsePropertyValueInternal()
330     throws CSSException, IOException JavaDoc {
331         nextIgnoreSpaces();
332         
333         LexicalUnit exp = null;
334
335         try {
336             exp = parseExpression(false);
337         } catch (CSSParseException e) {
338             reportError(e);
339             throw e;
340         }
341
342         CSSParseException exception = null;
343         if (current != LexicalUnits.EOF)
344             exception = createCSSParseException("eof.expected");
345
346         scanner = null;
347
348         if (exception != null) {
349             errorHandler.fatalError(exception);
350         }
351         return exp;
352     }
353     
354     /**
355      * <b>SAC</b>: Implements
356      * {@link org.w3c.css.sac.Parser#parsePriority(InputSource)}.
357      */

358     public boolean parsePriority(InputSource source)
359         throws CSSException, IOException JavaDoc {
360         scanner = createScanner(source);
361     return parsePriorityInternal();
362     }
363
364     /**
365      * Parses the priority using the current scanner.
366      */

367     protected boolean parsePriorityInternal()
368         throws CSSException, IOException JavaDoc {
369         nextIgnoreSpaces();
370
371         scanner = null;
372
373         switch (current) {
374         case LexicalUnits.EOF:
375             return false;
376         case LexicalUnits.IMPORT_SYMBOL:
377             return true;
378         default:
379             reportError("token", new Object JavaDoc[] { new Integer JavaDoc(current) });
380             return false;
381         }
382     }
383
384     /**
385      * Parses a rule.
386      */

387     protected void parseRule() {
388         switch (scanner.getType()) {
389         case LexicalUnits.IMPORT_SYMBOL:
390             nextIgnoreSpaces();
391             parseImportRule();
392             break;
393         case LexicalUnits.AT_KEYWORD:
394             nextIgnoreSpaces();
395             parseAtRule();
396             break;
397         case LexicalUnits.FONT_FACE_SYMBOL:
398             nextIgnoreSpaces();
399             parseFontFaceRule();
400             break;
401         case LexicalUnits.MEDIA_SYMBOL:
402             nextIgnoreSpaces();
403             parseMediaRule();
404             break;
405         case LexicalUnits.PAGE_SYMBOL:
406             nextIgnoreSpaces();
407             parsePageRule();
408             break;
409         default:
410             parseRuleSet();
411         }
412     }
413
414     /**
415      * Parses an unknown rule.
416      */

417     protected void parseAtRule() {
418         scanner.scanAtRule();
419         documentHandler.ignorableAtRule(scanner.getStringValue());
420         nextIgnoreSpaces();
421     }
422
423     /**
424      * Parses an import rule. Assumes the current token is '@import'.
425      */

426     protected void parseImportRule() {
427         String JavaDoc uri = null;
428         switch (current) {
429         default:
430             reportError("string.or.uri");
431             return;
432         case LexicalUnits.STRING:
433         case LexicalUnits.URI:
434             uri = scanner.getStringValue();
435             nextIgnoreSpaces();
436         }
437
438         CSSSACMediaList ml;
439         if (current != LexicalUnits.IDENTIFIER) {
440             ml = new CSSSACMediaList();
441             ml.append("all");
442         } else {
443             ml = parseMediaList();
444         }
445
446         documentHandler.importStyle(uri, ml, null);
447
448         if (current != LexicalUnits.SEMI_COLON) {
449             reportError("semicolon");
450         } else {
451             next();
452         }
453     }
454
455     /**
456      * Parses a media list.
457      */

458     protected CSSSACMediaList parseMediaList() {
459         CSSSACMediaList result = new CSSSACMediaList();
460         result.append(scanner.getStringValue());
461         nextIgnoreSpaces();
462         
463         while (current == LexicalUnits.COMMA) {
464             nextIgnoreSpaces();
465
466             switch (current) {
467             default:
468                 reportError("identifier");
469                 break;
470             case LexicalUnits.IDENTIFIER:
471                 result.append(scanner.getStringValue());
472                 nextIgnoreSpaces();
473             }
474         }
475         return result;
476     }
477
478     /**
479      * Parses a font-face rule.
480      */

481     protected void parseFontFaceRule() {
482         try {
483             documentHandler.startFontFace();
484
485             if (current != LexicalUnits.LEFT_CURLY_BRACE) {
486                 reportError("left.curly.brace");
487             } else {
488                 nextIgnoreSpaces();
489         
490                 try {
491                     parseStyleDeclaration(true);
492                 } catch (CSSParseException e) {
493                     reportError(e);
494                 }
495             }
496         } finally {
497             documentHandler.endFontFace();
498         }
499     }
500
501     /**
502      * Parses a page rule.
503      */

504     protected void parsePageRule() {
505         String JavaDoc page = null;
506         String JavaDoc ppage = null;
507
508         if (current == LexicalUnits.IDENTIFIER) {
509             page = scanner.getStringValue();
510             nextIgnoreSpaces();
511
512             if (current == LexicalUnits.COLON) {
513                 nextIgnoreSpaces();
514
515                 if (current != LexicalUnits.IDENTIFIER) {
516                     reportError("identifier");
517                     return;
518                 }
519                 ppage = scanner.getStringValue();
520                 nextIgnoreSpaces();
521             }
522         }
523
524         try {
525             documentHandler.startPage(page, ppage);
526             
527             if (current != LexicalUnits.LEFT_CURLY_BRACE) {
528                 reportError("left.curly.brace");
529             } else {
530                 nextIgnoreSpaces();
531         
532                 try {
533                     parseStyleDeclaration(true);
534                 } catch (CSSParseException e) {
535                     reportError(e);
536                 }
537             }
538         } finally {
539             documentHandler.endPage(page, ppage);
540         }
541     }
542     
543     /**
544      * Parses a media rule.
545      */

546     protected void parseMediaRule() {
547         if (current != LexicalUnits.IDENTIFIER) {
548             reportError("identifier");
549             return;
550         }
551
552         CSSSACMediaList ml = parseMediaList();
553         try {
554             documentHandler.startMedia(ml);
555
556             if (current != LexicalUnits.LEFT_CURLY_BRACE) {
557                 reportError("left.curly.brace");
558             } else {
559                 nextIgnoreSpaces();
560             
561                 loop: for (;;) {
562                     switch (current) {
563                     case LexicalUnits.EOF:
564                     case LexicalUnits.RIGHT_CURLY_BRACE:
565                         break loop;
566                     default:
567                         parseRuleSet();
568                     }
569                 }
570
571                 nextIgnoreSpaces();
572             }
573         } finally {
574             documentHandler.endMedia(ml);
575         }
576     }
577
578     /**
579      * Parses a ruleset.
580      */

581     protected void parseRuleSet() {
582         SelectorList sl = null;
583
584         try {
585             sl = parseSelectorList();
586         } catch (CSSParseException e) {
587             reportError(e);
588             return;
589         }
590
591         try {
592             documentHandler.startSelector(sl);
593
594             if (current != LexicalUnits.LEFT_CURLY_BRACE) {
595                 reportError("left.curly.brace");
596                 if (current == LexicalUnits.RIGHT_CURLY_BRACE) {
597                     nextIgnoreSpaces();
598                 }
599             } else {
600                 nextIgnoreSpaces();
601         
602                 try {
603                     parseStyleDeclaration(true);
604                 } catch (CSSParseException e) {
605                     reportError(e);
606                 }
607             }
608         } finally {
609             documentHandler.endSelector(sl);
610         }
611     }
612
613     /**
614      * Parses a selector list
615      */

616     protected SelectorList parseSelectorList() {
617         CSSSelectorList result = new CSSSelectorList();
618         result.append(parseSelector());
619
620         for (;;) {
621             if (current != LexicalUnits.COMMA) {
622                 return result;
623             }
624             nextIgnoreSpaces();
625             result.append(parseSelector());
626         }
627     }
628
629     /**
630      * Parses a selector.
631      */

632     protected Selector parseSelector() {
633         SimpleSelector ss = parseSimpleSelector();
634         Selector result = ss;
635
636         pseudoElement = null;
637
638         loop: for (;;) {
639             switch (current) {
640             default:
641                 break loop;
642             case LexicalUnits.IDENTIFIER:
643             case LexicalUnits.ANY:
644             case LexicalUnits.HASH:
645             case LexicalUnits.DOT:
646             case LexicalUnits.LEFT_BRACKET:
647             case LexicalUnits.COLON:
648                 result = selectorFactory.createDescendantSelector
649                     (result,
650                      parseSimpleSelector());
651                 break;
652             case LexicalUnits.PLUS:
653                 nextIgnoreSpaces();
654                 result = selectorFactory.createDirectAdjacentSelector
655                     ((short)1,
656                      result,
657                      parseSimpleSelector());
658                 break;
659             case LexicalUnits.PRECEDE:
660                 nextIgnoreSpaces();
661                 result = selectorFactory.createChildSelector
662                     (result,
663                      parseSimpleSelector());
664              }
665         }
666         if (pseudoElement != null) {
667             result = selectorFactory.createChildSelector
668                 (result,
669                  selectorFactory.createPseudoElementSelector
670                  (null, pseudoElement));
671         }
672         return result;
673     }
674
675     /**
676      * Parses a simple selector.
677      */

678     protected SimpleSelector parseSimpleSelector() {
679         SimpleSelector result;
680
681         switch (current) {
682         case LexicalUnits.IDENTIFIER:
683             result = selectorFactory.createElementSelector
684                 (null, scanner.getStringValue());
685             next();
686             break;
687         case LexicalUnits.ANY:
688             next();
689         default:
690             result = selectorFactory.createElementSelector(null, null);
691         }
692         Condition cond = null;
693         loop: for (;;) {
694             Condition c = null;
695             switch (current) {
696             case LexicalUnits.HASH:
697                 c = conditionFactory.createIdCondition
698                     (scanner.getStringValue());
699                 next();
700                 break;
701             case LexicalUnits.DOT:
702                 if (next() != LexicalUnits.IDENTIFIER) {
703                     throw createCSSParseException("identifier");
704                 }
705                 c = conditionFactory.createClassCondition
706                     (null, scanner.getStringValue());
707                 next();
708                 break;
709             case LexicalUnits.LEFT_BRACKET:
710                 if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) {
711                     throw createCSSParseException("identifier");
712                 }
713                 String JavaDoc name = scanner.getStringValue();
714                 int op = nextIgnoreSpaces();
715                 switch (op) {
716                 default:
717                     throw createCSSParseException("right.bracket");
718                 case LexicalUnits.RIGHT_BRACKET:
719                     nextIgnoreSpaces();
720                     c = conditionFactory.createAttributeCondition
721                         (name, null, false, null);
722                     break;
723                 case LexicalUnits.EQUAL:
724                 case LexicalUnits.INCLUDES:
725                 case LexicalUnits.DASHMATCH:
726                     String JavaDoc val = null;
727                     switch (nextIgnoreSpaces()) {
728                     default:
729                         throw createCSSParseException("identifier.or.string");
730                     case LexicalUnits.STRING:
731                     case LexicalUnits.IDENTIFIER:
732                         val = scanner.getStringValue();
733                         nextIgnoreSpaces();
734                     }
735                     if (current != LexicalUnits.RIGHT_BRACKET) {
736                         throw createCSSParseException("right.bracket");
737                     }
738                     next();
739                     switch (op) {
740                     case LexicalUnits.EQUAL:
741                         c = conditionFactory.createAttributeCondition
742                             (name, null, false, val);
743                         break;
744                     case LexicalUnits.INCLUDES:
745                         c = conditionFactory.createOneOfAttributeCondition
746                             (name, null, false, val);
747                         break;
748                     default:
749                         c = conditionFactory.
750                             createBeginHyphenAttributeCondition
751                             (name, null, false, val);
752                     }
753                 }
754                 break;
755             case LexicalUnits.COLON:
756                 switch (nextIgnoreSpaces()) {
757                 case LexicalUnits.IDENTIFIER:
758                     String JavaDoc val = scanner.getStringValue();
759                     if (isPseudoElement(val)) {
760                         if (pseudoElement != null) {
761                             throw createCSSParseException
762                                 ("duplicate.pseudo.element");
763                         }
764                         pseudoElement = val;
765                     } else {
766                         c = conditionFactory.createPseudoClassCondition
767                             (null, val);
768                     }
769                     next();
770                     break;
771                 case LexicalUnits.FUNCTION:
772                     String JavaDoc func = scanner.getStringValue();
773                     if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) {
774                         throw createCSSParseException("identifier");
775                     }
776                     String JavaDoc lang = scanner.getStringValue();
777                     if (nextIgnoreSpaces() != LexicalUnits.RIGHT_BRACE) {
778                         throw createCSSParseException("right.brace");
779                     }
780
781                     if (!func.equalsIgnoreCase("lang")) {
782                         throw createCSSParseException("pseudo.function");
783                     }
784
785                     c = conditionFactory.createLangCondition(lang);
786
787                     next();
788                     break;
789                 default:
790                     throw createCSSParseException("identifier");
791                 }
792                 break;
793             default:
794                 break loop;
795             }
796             if (c != null) {
797                 if (cond == null) {
798                     cond = c;
799                 } else {
800                     cond = conditionFactory.createAndCondition(cond, c);
801                 }
802             }
803         }
804         skipSpaces();
805         if (cond != null) {
806             result = selectorFactory.createConditionalSelector(result, cond);
807         }
808         return result;
809     }
810
811     /**
812      * Tells whether or not the given string represents a pseudo-element.
813      */

814     protected boolean isPseudoElement(String JavaDoc s) {
815         switch (s.charAt(0)) {
816         case 'a':
817         case 'A':
818             return s.equalsIgnoreCase("after");
819         case 'b':
820         case 'B':
821             return s.equalsIgnoreCase("before");
822         case 'f':
823         case 'F':
824             return s.equalsIgnoreCase("first-letter") ||
825                    s.equalsIgnoreCase("first-line");
826         }
827         return false;
828     }
829
830     /**
831      * Parses the given reader.
832      */

833     protected void parseStyleDeclaration(boolean inSheet)
834         throws CSSException {
835         for (;;) {
836             switch (current) {
837             case LexicalUnits.EOF:
838                 if (inSheet) {
839                     throw createCSSParseException("eof");
840                 }
841                 return;
842             case LexicalUnits.RIGHT_CURLY_BRACE:
843                 if (!inSheet) {
844                     throw createCSSParseException("eof.expected");
845                 }
846                 nextIgnoreSpaces();
847                 return;
848             case LexicalUnits.SEMI_COLON:
849                 nextIgnoreSpaces();
850                 continue;
851             default:
852                 throw createCSSParseException("identifier");
853             case LexicalUnits.IDENTIFIER:
854             }
855
856             String JavaDoc name = scanner.getStringValue();
857         
858             if (nextIgnoreSpaces() != LexicalUnits.COLON) {
859                 throw createCSSParseException("colon");
860             }
861             nextIgnoreSpaces();
862         
863             LexicalUnit exp = null;
864             
865             try {
866                 exp = parseExpression(false);
867             } catch (CSSParseException e) {
868                 reportError(e);
869             }
870
871             if (exp != null) {
872                 boolean important = false;
873                 if (current == LexicalUnits.IMPORTANT_SYMBOL) {
874                     important = true;
875                     nextIgnoreSpaces();
876                 }
877                 documentHandler.property(name, exp, important);
878             }
879         }
880     }
881
882     /**
883      * Parses a CSS2 expression.
884      * @param param whether the expression to be parsed is a function parameter
885      */

886     protected LexicalUnit parseExpression(boolean param) {
887         LexicalUnit result = parseTerm(null);
888         LexicalUnit curr = result;
889
890         for (;;) {
891             boolean op = false;
892             switch (current) {
893             case LexicalUnits.COMMA:
894                 op = true;
895                 curr = CSSLexicalUnit.createSimple
896                     (LexicalUnit.SAC_OPERATOR_COMMA, curr);
897                 nextIgnoreSpaces();
898                 break;
899             case LexicalUnits.DIVIDE:
900                 op = true;
901                 curr = CSSLexicalUnit.createSimple
902                     (LexicalUnit.SAC_OPERATOR_SLASH, curr);
903                 nextIgnoreSpaces();
904             }
905             if (param) {
906                 if (current == LexicalUnits.RIGHT_BRACE) {
907                     if (op) {
908                         throw createCSSParseException
909                             ("token", new Object JavaDoc[] { new Integer JavaDoc(current) });
910                     }
911                     return result;
912                 }
913                 curr = parseTerm(curr);
914             } else {
915                 switch (current) {
916                 case LexicalUnits.IMPORTANT_SYMBOL:
917                 case LexicalUnits.SEMI_COLON:
918                 case LexicalUnits.RIGHT_CURLY_BRACE:
919                 case LexicalUnits.EOF:
920                     if (op) {
921                         throw createCSSParseException
922                             ("token", new Object JavaDoc[] { new Integer JavaDoc(current) });
923                     }
924                     return result;
925                 default:
926                     curr = parseTerm(curr);
927                 }
928             }
929         }
930     }
931
932     /**
933      * Parses a CSS2 term.
934      */

935     protected LexicalUnit parseTerm(LexicalUnit prev) {
936         boolean plus = true;
937         boolean sgn = false;
938
939         switch (current) {
940         case LexicalUnits.MINUS:
941             plus = false;
942         case LexicalUnits.PLUS:
943             next();
944             sgn = true;
945         default:
946             switch (current) {
947             case LexicalUnits.INTEGER:
948                 String JavaDoc sval = scanner.getStringValue();
949                 if (!plus) sval = "-"+sval;
950                 int val = Integer.parseInt(sval);
951                 nextIgnoreSpaces();
952                 return CSSLexicalUnit.createInteger(val, prev);
953             case LexicalUnits.REAL:
954                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_REAL,
955                                                   number(plus), prev);
956             case LexicalUnits.PERCENTAGE:
957                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_PERCENTAGE,
958                                                   number(plus), prev);
959             case LexicalUnits.PT:
960                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_POINT,
961                                                   number(plus), prev);
962             case LexicalUnits.PC:
963                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_PICA,
964                                                   number(plus), prev);
965             case LexicalUnits.PX:
966                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_PIXEL,
967                                                   number(plus), prev);
968             case LexicalUnits.CM:
969                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_CENTIMETER,
970                                                   number(plus), prev);
971             case LexicalUnits.MM:
972                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_MILLIMETER,
973                                                   number(plus), prev);
974             case LexicalUnits.IN:
975                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_INCH,
976                                                   number(plus), prev);
977             case LexicalUnits.EM:
978                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_EM,
979                                                   number(plus), prev);
980             case LexicalUnits.EX:
981                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_EX,
982                                                   number(plus), prev);
983             case LexicalUnits.DEG:
984                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_DEGREE,
985                                                   number(plus), prev);
986             case LexicalUnits.RAD:
987                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_RADIAN,
988                                                   number(plus), prev);
989             case LexicalUnits.GRAD:
990                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_GRADIAN,
991                                                   number(plus), prev);
992             case LexicalUnits.S:
993                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_SECOND,
994                                                   number(plus), prev);
995             case LexicalUnits.MS:
996                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_MILLISECOND,
997                                                   number(plus), prev);
998             case LexicalUnits.HZ:
999                 return CSSLexicalUnit.createFloat(LexicalUnit.SAC_HERTZ,
1000                                                  number(plus), prev);
1001            case LexicalUnits.KHZ:
1002                return CSSLexicalUnit.createFloat(LexicalUnit.SAC_KILOHERTZ,
1003                                                  number(plus), prev);
1004            case LexicalUnits.DIMENSION:
1005                return dimension(plus, prev);
1006            case LexicalUnits.FUNCTION:
1007                return parseFunction(plus, prev);
1008            }
1009            if (sgn) {
1010                throw createCSSParseException
1011                    ("token",
1012                     new Object JavaDoc[] { new Integer JavaDoc(current) });
1013            }
1014        }
1015        switch (current) {
1016        case LexicalUnits.STRING:
1017            String JavaDoc val = scanner.getStringValue();
1018            nextIgnoreSpaces();
1019            return CSSLexicalUnit.createString(LexicalUnit.SAC_STRING_VALUE,
1020                                               val, prev);
1021        case LexicalUnits.IDENTIFIER:
1022            val = scanner.getStringValue();
1023            nextIgnoreSpaces();
1024            if (val.equalsIgnoreCase("inherit")) {
1025                return CSSLexicalUnit.createSimple(LexicalUnit.SAC_INHERIT,
1026                                                   prev);
1027            } else {
1028                return CSSLexicalUnit.createString(LexicalUnit.SAC_IDENT,
1029                                                   val, prev);
1030            }
1031        case LexicalUnits.URI:
1032            val = scanner.getStringValue();
1033            nextIgnoreSpaces();
1034            return CSSLexicalUnit.createString(LexicalUnit.SAC_URI,
1035                                               val, prev);
1036        case LexicalUnits.HASH:
1037            return hexcolor(prev);
1038        default:
1039            throw createCSSParseException
1040                ("token",
1041                 new Object JavaDoc[] { new Integer JavaDoc(current) });
1042        }
1043    }
1044
1045    /**
1046     * Parses a CSS2 function.
1047     */

1048    protected LexicalUnit parseFunction(boolean positive, LexicalUnit prev) {
1049        String JavaDoc name = scanner.getStringValue();
1050        nextIgnoreSpaces();
1051        
1052        LexicalUnit params = parseExpression(true);
1053
1054        if (current != LexicalUnits.RIGHT_BRACE) {
1055            throw createCSSParseException
1056                ("token",
1057                 new Object JavaDoc[] { new Integer JavaDoc(current) });
1058        }
1059        nextIgnoreSpaces();
1060
1061        predefined: switch (name.charAt(0)) {
1062        case 'r':
1063        case 'R':
1064            LexicalUnit lu;
1065            if (name.equalsIgnoreCase("rgb")) {
1066                lu = params;
1067                if (lu == null) {
1068                    break;
1069                }
1070                switch (lu.getLexicalUnitType()) {
1071                default:
1072                    break predefined;
1073                case LexicalUnit.SAC_INTEGER:
1074                case LexicalUnit.SAC_PERCENTAGE:
1075                    lu = lu.getNextLexicalUnit();
1076                }
1077                if (lu == null) {
1078                    break;
1079                }
1080                switch (lu.getLexicalUnitType()) {
1081                default:
1082                    break predefined;
1083                case LexicalUnit.SAC_OPERATOR_COMMA:
1084                    lu = lu.getNextLexicalUnit();
1085                }
1086                if (lu == null) {
1087                    break;
1088                }
1089                switch (lu.getLexicalUnitType()) {
1090                default:
1091                    break predefined;
1092                case LexicalUnit.SAC_INTEGER:
1093                case LexicalUnit.SAC_PERCENTAGE:
1094                    lu = lu.getNextLexicalUnit();
1095                }
1096                if (lu == null) {
1097                    break;
1098                }
1099                switch (lu.getLexicalUnitType()) {
1100                default:
1101                    break predefined;
1102                case LexicalUnit.SAC_OPERATOR_COMMA:
1103                    lu = lu.getNextLexicalUnit();
1104                }
1105                if (lu == null) {
1106                    break;
1107                }
1108                switch (lu.getLexicalUnitType()) {
1109                default:
1110                    break predefined;
1111                case LexicalUnit.SAC_INTEGER:
1112                case LexicalUnit.SAC_PERCENTAGE:
1113                    lu = lu.getNextLexicalUnit();
1114                }
1115                if (lu != null) {
1116                    break;
1117                }
1118                return CSSLexicalUnit.createPredefinedFunction
1119                    (LexicalUnit.SAC_RGBCOLOR, params, prev);
1120            } else if (name.equalsIgnoreCase("rect")) {
1121                lu = params;
1122                if (lu == null) {
1123                    break;
1124                }
1125                switch (lu.getLexicalUnitType()) {
1126                default:
1127                    break predefined;
1128                case LexicalUnit.SAC_INTEGER:
1129                    if (lu.getIntegerValue() != 0) {
1130                        break predefined;
1131                    }
1132                    lu = lu.getNextLexicalUnit();
1133                    break;
1134                case LexicalUnit.SAC_IDENT:
1135                    if (!lu.getStringValue().equalsIgnoreCase("auto")) {
1136                        break predefined;
1137                    }
1138                    lu = lu.getNextLexicalUnit();
1139                    break;
1140                case LexicalUnit.SAC_EM:
1141                case LexicalUnit.SAC_EX:
1142                case LexicalUnit.SAC_PIXEL:
1143                case LexicalUnit.SAC_CENTIMETER:
1144                case LexicalUnit.SAC_MILLIMETER:
1145                case LexicalUnit.SAC_INCH:
1146                case LexicalUnit.SAC_POINT:
1147                case LexicalUnit.SAC_PICA:
1148                case LexicalUnit.SAC_PERCENTAGE:
1149                    lu = lu.getNextLexicalUnit();
1150                }
1151                if (lu == null) {
1152                    break;
1153                }
1154                switch (lu.getLexicalUnitType()) {
1155                default:
1156                    break predefined;
1157                case LexicalUnit.SAC_OPERATOR_COMMA:
1158                    lu = lu.getNextLexicalUnit();
1159                }
1160                if (lu == null) {
1161                    break;
1162                }
1163                switch (lu.getLexicalUnitType()) {
1164                default:
1165                    break predefined;
1166                case LexicalUnit.SAC_INTEGER:
1167                    if (lu.getIntegerValue() != 0) {
1168                        break predefined;
1169                    }
1170                    lu = lu.getNextLexicalUnit();
1171                    break;
1172                case LexicalUnit.SAC_IDENT:
1173                    if (!lu.getStringValue().equalsIgnoreCase("auto")) {
1174                        break predefined;
1175                    }
1176                    lu = lu.getNextLexicalUnit();
1177                    break;
1178                case LexicalUnit.SAC_EM:
1179                case LexicalUnit.SAC_EX:
1180                case LexicalUnit.SAC_PIXEL:
1181                case LexicalUnit.SAC_CENTIMETER:
1182                case LexicalUnit.SAC_MILLIMETER:
1183                case LexicalUnit.SAC_INCH:
1184                case LexicalUnit.SAC_POINT:
1185                case LexicalUnit.SAC_PICA:
1186                case LexicalUnit.SAC_PERCENTAGE:
1187                    lu = lu.getNextLexicalUnit();
1188                }
1189                if (lu == null) {
1190                    break;
1191                }
1192                switch (lu.getLexicalUnitType()) {
1193                default:
1194                    break predefined;
1195                case LexicalUnit.SAC_OPERATOR_COMMA:
1196                    lu = lu.getNextLexicalUnit();
1197                }
1198                if (lu == null) {
1199                    break;
1200                }
1201                switch (lu.getLexicalUnitType()) {
1202                default:
1203                    break predefined;
1204                case LexicalUnit.SAC_INTEGER:
1205                    if (lu.getIntegerValue() != 0) {
1206                        break predefined;
1207                    }
1208                    lu = lu.getNextLexicalUnit();
1209                    break;
1210                case LexicalUnit.SAC_IDENT:
1211                    if (!lu.getStringValue().equalsIgnoreCase("auto")) {
1212                        break predefined;
1213                    }
1214                    lu = lu.getNextLexicalUnit();
1215                    break;
1216                case LexicalUnit.SAC_EM:
1217                case LexicalUnit.SAC_EX:
1218                case LexicalUnit.SAC_PIXEL:
1219                case LexicalUnit.SAC_CENTIMETER:
1220                case LexicalUnit.SAC_MILLIMETER:
1221                case LexicalUnit.SAC_INCH:
1222                case LexicalUnit.SAC_POINT:
1223                case LexicalUnit.SAC_PICA:
1224                case LexicalUnit.SAC_PERCENTAGE:
1225                    lu = lu.getNextLexicalUnit();
1226                }
1227                if (lu == null) {
1228                    break;
1229                }
1230                switch (lu.getLexicalUnitType()) {
1231                default:
1232                    break predefined;
1233                case LexicalUnit.SAC_OPERATOR_COMMA:
1234                    lu = lu.getNextLexicalUnit();
1235                }
1236                if (lu == null) {
1237                    break;
1238                }
1239                switch (lu.getLexicalUnitType()) {
1240                default:
1241                    break predefined;
1242                case LexicalUnit.SAC_INTEGER:
1243                    if (lu.getIntegerValue() != 0) {
1244                        break predefined;
1245                    }
1246                    lu = lu.getNextLexicalUnit();
1247                    break;
1248                case LexicalUnit.SAC_IDENT:
1249                    if (!lu.getStringValue().equalsIgnoreCase("auto")) {
1250                        break predefined;
1251                    }
1252                    lu = lu.getNextLexicalUnit();
1253                    break;
1254                case LexicalUnit.SAC_EM:
1255                case LexicalUnit.SAC_EX:
1256                case LexicalUnit.SAC_PIXEL:
1257                case LexicalUnit.SAC_CENTIMETER:
1258                case LexicalUnit.SAC_MILLIMETER:
1259                case LexicalUnit.SAC_INCH:
1260                case LexicalUnit.SAC_POINT:
1261                case LexicalUnit.SAC_PICA:
1262                case LexicalUnit.SAC_PERCENTAGE:
1263                    lu = lu.getNextLexicalUnit();
1264                }
1265                if (lu != null) {
1266                    break;
1267                }
1268                return CSSLexicalUnit.createPredefinedFunction
1269                    (LexicalUnit.SAC_RECT_FUNCTION, params, prev);
1270            }
1271            break;
1272        case 'c':
1273        case 'C':
1274            if (name.equalsIgnoreCase("counter")) {
1275                lu = params;
1276                if (lu == null) {
1277                    break;
1278                }
1279                switch (lu.getLexicalUnitType()) {
1280                default:
1281                    break predefined;
1282                case LexicalUnit.SAC_IDENT:
1283                    lu = lu.getNextLexicalUnit();
1284                }
1285                if (lu == null) {
1286                    break;
1287                }
1288                switch (lu.getLexicalUnitType()) {
1289                default:
1290                    break predefined;
1291                case LexicalUnit.SAC_OPERATOR_COMMA:
1292                    lu = lu.getNextLexicalUnit();
1293                }
1294                if (lu == null) {
1295                    break;
1296                }
1297                switch (lu.getLexicalUnitType()) {
1298                default:
1299                    break predefined;
1300                case LexicalUnit.SAC_IDENT:
1301                    lu = lu.getNextLexicalUnit();
1302                }
1303                if (lu != null) {
1304                    break;
1305                }
1306                return CSSLexicalUnit.createPredefinedFunction
1307                    (LexicalUnit.SAC_COUNTER_FUNCTION, params, prev);
1308            } else if (name.equalsIgnoreCase("counters")) {
1309                lu = params;
1310                if (lu == null) {
1311                    break;
1312                }
1313                switch (lu.getLexicalUnitType()) {
1314                default:
1315                    break predefined;
1316                case LexicalUnit.SAC_IDENT:
1317                    lu = lu.getNextLexicalUnit();
1318                }
1319                if (lu == null) {
1320                    break;
1321                }
1322                switch (lu.getLexicalUnitType()) {
1323                default:
1324                    break predefined;
1325                case LexicalUnit.SAC_OPERATOR_COMMA:
1326                    lu = lu.getNextLexicalUnit();
1327                }
1328                if (lu == null) {
1329                    break;
1330                }
1331                switch (lu.getLexicalUnitType()) {
1332                default:
1333                    break predefined;
1334                case LexicalUnit.SAC_STRING_VALUE:
1335                    lu = lu.getNextLexicalUnit();
1336                }
1337                if (lu == null) {
1338                    break;
1339                }
1340                switch (lu.getLexicalUnitType()) {
1341                default:
1342                    break predefined;
1343                case LexicalUnit.SAC_OPERATOR_COMMA:
1344                    lu = lu.getNextLexicalUnit();
1345                }
1346                if (lu == null) {
1347                    break;
1348                }
1349                switch (lu.getLexicalUnitType()) {
1350                default:
1351                    break predefined;
1352                case LexicalUnit.SAC_IDENT:
1353                    lu = lu.getNextLexicalUnit();
1354                }
1355                if (lu != null) {
1356                    break;
1357                }
1358                return CSSLexicalUnit.createPredefinedFunction
1359                    (LexicalUnit.SAC_COUNTERS_FUNCTION, params, prev);
1360            }
1361            break;
1362        case 'a':
1363        case 'A':
1364            if (name.equalsIgnoreCase("attr")) {
1365                lu = params;
1366                if (lu == null) {
1367                    break;
1368                }
1369                switch (lu.getLexicalUnitType()) {
1370                default:
1371                    break predefined;
1372                case LexicalUnit.SAC_IDENT:
1373                    lu = lu.getNextLexicalUnit();
1374                }
1375                if (lu != null) {
1376                    break;
1377                }
1378                return CSSLexicalUnit.createString
1379                    (LexicalUnit.SAC_ATTR, params.getStringValue(), prev);
1380            }
1381        }
1382
1383        return CSSLexicalUnit.createFunction(name, params, prev);
1384    }
1385
1386    /**
1387     * Converts a hash unit to a RGB color.
1388     */

1389    protected LexicalUnit hexcolor(LexicalUnit prev) {
1390        String JavaDoc val = scanner.getStringValue();
1391        int len = val.length();
1392        LexicalUnit params = null;
1393        switch (len) {
1394        case 3:
1395            char rc = Character.toLowerCase(val.charAt(0));
1396            char gc = Character.toLowerCase(val.charAt(1));
1397            char bc = Character.toLowerCase(val.charAt(2));
1398            if (!ScannerUtilities.isCSSHexadecimalCharacter(rc) ||
1399                !ScannerUtilities.isCSSHexadecimalCharacter(gc) ||
1400                !ScannerUtilities.isCSSHexadecimalCharacter(bc)) {
1401                throw createCSSParseException
1402                    ("rgb.color", new Object JavaDoc[] { val });
1403            }
1404            int t;
1405            int r = t = (rc >= '0' && rc <= '9') ? rc - '0' : rc - 'a' + 10;
1406            t <<= 4;
1407            r |= t;
1408            int g = t = (gc >= '0' && gc <= '9') ? gc - '0' : gc - 'a' + 10;
1409            t <<= 4;
1410            g |= t;
1411            int b = t = (bc >= '0' && bc <= '9') ? bc - '0' : bc - 'a' + 10;
1412            t <<= 4;
1413            b |= t;
1414            params = CSSLexicalUnit.createInteger(r, null);
1415            LexicalUnit tmp;
1416            tmp = CSSLexicalUnit.createSimple
1417                (LexicalUnit.SAC_OPERATOR_COMMA, params);
1418            tmp = CSSLexicalUnit.createInteger(g, tmp);
1419            tmp = CSSLexicalUnit.createSimple
1420                (LexicalUnit.SAC_OPERATOR_COMMA, tmp);
1421            tmp = CSSLexicalUnit.createInteger(b, tmp);
1422            break;
1423        case 6:
1424            char rc1 = Character.toLowerCase(val.charAt(0));
1425            char rc2 = Character.toLowerCase(val.charAt(1));
1426            char gc1 = Character.toLowerCase(val.charAt(2));
1427            char gc2 = Character.toLowerCase(val.charAt(3));
1428            char bc1 = Character.toLowerCase(val.charAt(4));
1429            char bc2 = Character.toLowerCase(val.charAt(5));
1430            if (!ScannerUtilities.isCSSHexadecimalCharacter(rc1) ||
1431                !ScannerUtilities.isCSSHexadecimalCharacter(rc2) ||
1432                !ScannerUtilities.isCSSHexadecimalCharacter(gc1) ||
1433                !ScannerUtilities.isCSSHexadecimalCharacter(gc2) ||
1434                !ScannerUtilities.isCSSHexadecimalCharacter(bc1) ||
1435                !ScannerUtilities.isCSSHexadecimalCharacter(bc2)) {
1436                throw createCSSParseException("rgb.color");
1437            }
1438            r = (rc1 >= '0' && rc1 <= '9') ? rc1 - '0' : rc1 - 'a' + 10;
1439            r <<= 4;
1440            r |= (rc2 >= '0' && rc2 <= '9') ? rc2 - '0' : rc2 - 'a' + 10;
1441            g = (gc1 >= '0' && gc1 <= '9') ? gc1 - '0' : gc1 - 'a' + 10;
1442            g <<= 4;
1443            g |= (gc2 >= '0' && gc2 <= '9') ? gc2 - '0' : gc2 - 'a' + 10;
1444            b = (bc1 >= '0' && bc1 <= '9') ? bc1 - '0' : bc1 - 'a' + 10;
1445            b <<= 4;
1446            b |= (bc2 >= '0' && bc2 <= '9') ? bc2 - '0' : bc2 - 'a' + 10;
1447            params = CSSLexicalUnit.createInteger(r, null);
1448            tmp = CSSLexicalUnit.createSimple
1449                (LexicalUnit.SAC_OPERATOR_COMMA, params);
1450            tmp = CSSLexicalUnit.createInteger(g, tmp);
1451            tmp = CSSLexicalUnit.createSimple
1452                (LexicalUnit.SAC_OPERATOR_COMMA, tmp);
1453            tmp = CSSLexicalUnit.createInteger(b, tmp);
1454            break;
1455        default:
1456            throw createCSSParseException("rgb.color", new Object JavaDoc[] { val });
1457        }
1458        nextIgnoreSpaces();
1459        return CSSLexicalUnit.createPredefinedFunction
1460            (LexicalUnit.SAC_RGBCOLOR, params, prev);
1461    }
1462
1463    /**
1464     * Creates a scanner, given an InputSource.
1465     */

1466    protected Scanner createScanner(InputSource source) {
1467        documentURI = source.getURI();
1468        if (documentURI == null) {
1469            documentURI = "";
1470        }
1471
1472        Reader JavaDoc r = source.getCharacterStream();
1473        if (r != null) {
1474            return new Scanner(r);
1475        }
1476
1477        InputStream JavaDoc is = source.getByteStream();
1478        if (is != null) {
1479            return new Scanner(is, source.getEncoding());
1480        }
1481
1482        String JavaDoc uri = source.getURI();
1483        if (uri == null) {
1484            throw new CSSException(formatMessage("empty.source", null));
1485        }
1486
1487        try {
1488            ParsedURL purl = new ParsedURL(uri);
1489            is = purl.openStreamRaw(CSSConstants.CSS_MIME_TYPE);
1490            return new Scanner(is, source.getEncoding());
1491        } catch (IOException JavaDoc e) {
1492            throw new CSSException(e);
1493        }
1494    }
1495
1496    /**
1497     * Skips the white spaces.
1498     */

1499    protected int skipSpaces() {
1500        int lex = scanner.getType();
1501        while (lex == LexicalUnits.SPACE) {
1502            lex = next();
1503        }
1504        return lex;
1505    }
1506
1507    /**
1508     * Skips the white spaces and CDO/CDC units.
1509     */

1510    protected int skipSpacesAndCDOCDC() {
1511        loop: for (;;) {
1512            switch (current) {
1513            default:
1514                break loop;
1515            case LexicalUnits.COMMENT:
1516            case LexicalUnits.SPACE:
1517            case LexicalUnits.CDO:
1518            case LexicalUnits.CDC:
1519            }
1520            scanner.clearBuffer();
1521            next();
1522        }
1523        return current;
1524    }
1525
1526    /**
1527     * Converts the current lexical unit to a float.
1528     */

1529    protected float number(boolean positive) {
1530        try {
1531            float sgn = (positive) ? 1 : -1;
1532            String JavaDoc val = scanner.getStringValue();
1533            nextIgnoreSpaces();
1534            return sgn * Float.parseFloat(val);
1535        } catch (NumberFormatException JavaDoc e) {
1536            throw createCSSParseException("number.format");
1537        }
1538    }
1539
1540    /**
1541     * Converts the current lexical unit to a dimension.
1542     */

1543    protected LexicalUnit dimension(boolean positive, LexicalUnit prev) {
1544        try {
1545            float sgn = (positive) ? 1 : -1;
1546            String JavaDoc val = scanner.getStringValue();
1547            int i;
1548            loop: for (i = 0; i < val.length(); i++) {
1549                switch (val.charAt(i)) {
1550                default:
1551                    break loop;
1552                case '0': case '1': case '2': case '3': case '4':
1553                case '5': case '6': case '7': case '8': case '9':
1554                case '.':
1555                }
1556            }
1557            nextIgnoreSpaces();
1558            return CSSLexicalUnit.createDimension
1559                (sgn * Float.parseFloat(val.substring(0, i)),
1560                 val.substring(i),
1561                 prev);
1562        } catch (NumberFormatException JavaDoc e) {
1563            throw createCSSParseException("number.format");
1564        }
1565    }
1566
1567    /**
1568     * Advances to the next token, ignoring comments.
1569     */

1570    protected int next() {
1571        try {
1572            for (;;) {
1573                scanner.clearBuffer();
1574                current = scanner.next();
1575                if (current == LexicalUnits.COMMENT) {
1576                    documentHandler.comment(scanner.getStringValue());
1577                } else {
1578                    break;
1579                }
1580            }
1581            return current;
1582        } catch (ParseException e) {
1583            reportError(e.getMessage());
1584            return current;
1585        }
1586    }
1587
1588    /**
1589     * Advances to the next token and skip the spaces, ignoring comments.
1590     */

1591    protected int nextIgnoreSpaces() {
1592        try {
1593            loop: for (;;) {
1594                scanner.clearBuffer();
1595                current = scanner.next();
1596                switch (current) {
1597                case LexicalUnits.COMMENT:
1598                    documentHandler.comment(scanner.getStringValue());
1599                    break;
1600                default:
1601                    break loop;
1602                case LexicalUnits.SPACE:
1603                }
1604            }
1605            return current;
1606        } catch (ParseException e) {
1607            errorHandler.error(createCSSParseException(e.getMessage()));
1608            return current;
1609        }
1610    }
1611
1612    /**
1613     * Reports a parsing error.
1614     */

1615    protected void reportError(String JavaDoc key) {
1616        reportError(key, null);
1617    }
1618
1619    /**
1620     * Reports a parsing error.
1621     */

1622    protected void reportError(String JavaDoc key, Object JavaDoc[] params) {
1623        reportError(createCSSParseException(key, params));
1624    }
1625
1626    /**
1627     * Reports a parsing error.
1628     */

1629    protected void reportError(CSSParseException e) {
1630        errorHandler.error(e);
1631
1632        int cbraces = 1;
1633        for (;;) {
1634            switch (current) {
1635            case LexicalUnits.EOF:
1636                return;
1637            case LexicalUnits.SEMI_COLON:
1638            case LexicalUnits.RIGHT_CURLY_BRACE:
1639                if (--cbraces == 0) {
1640                    nextIgnoreSpaces();
1641                    return;
1642                }
1643            case LexicalUnits.LEFT_CURLY_BRACE:
1644                cbraces++;
1645            }
1646            nextIgnoreSpaces();
1647        }
1648    }
1649
1650    /**
1651     * Creates a parse exception.
1652     */

1653    protected CSSParseException createCSSParseException(String JavaDoc key) {
1654        return createCSSParseException(key, null);
1655    }
1656
1657    /**
1658     * Creates a parse exception.
1659     */

1660    protected CSSParseException createCSSParseException(String JavaDoc key,
1661                                                        Object JavaDoc[] params) {
1662        return new CSSParseException(formatMessage(key, params),
1663                                     documentURI,
1664                                     scanner.getLine(),
1665                                     scanner.getColumn());
1666    }
1667
1668    // -----------------------------------------------------------------------
1669
// Extended methods
1670
// -----------------------------------------------------------------------
1671

1672    /**
1673     * Implements {@link ExtendedParser#parseStyleDeclaration(String)}.
1674     */

1675    public void parseStyleDeclaration(String JavaDoc source)
1676    throws CSSException, IOException JavaDoc {
1677        scanner = new Scanner(source);
1678    parseStyleDeclarationInternal();
1679    }
1680
1681    /**
1682     * Implements {@link ExtendedParser#parseRule(String)}.
1683     */

1684    public void parseRule(String JavaDoc source) throws CSSException, IOException JavaDoc {
1685        scanner = new Scanner(source);
1686    parseRuleInternal();
1687    }
1688    
1689    /**
1690     * Implements {@link ExtendedParser#parseSelectors(String)}.
1691     */

1692    public SelectorList parseSelectors(String JavaDoc source)
1693        throws CSSException, IOException JavaDoc {
1694        scanner = new Scanner(source);
1695    return parseSelectorsInternal();
1696    }
1697
1698    /**
1699     * Implements {@link ExtendedParser#parsePropertyValue(String)}.
1700     */

1701    public LexicalUnit parsePropertyValue(String JavaDoc source)
1702        throws CSSException, IOException JavaDoc {
1703        scanner = new Scanner(source);
1704    return parsePropertyValueInternal();
1705    }
1706
1707    /**
1708     * Implements {@link ExtendedParser#parsePriority(String)}.
1709     */

1710    public boolean parsePriority(String JavaDoc source)
1711        throws CSSException, IOException JavaDoc {
1712        scanner = new Scanner(source);
1713    return parsePriorityInternal();
1714    }
1715
1716    /**
1717     * Implements {@link ExtendedParser#parseMedia(String)}.
1718     */

1719    public SACMediaList parseMedia(String JavaDoc mediaText)
1720        throws CSSException, IOException JavaDoc {
1721        CSSSACMediaList result = new CSSSACMediaList();
1722        if (!"all".equalsIgnoreCase(mediaText)) {
1723            StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(mediaText, " ,");
1724            while (st.hasMoreTokens()) {
1725                result.append(st.nextToken());
1726            }
1727        }
1728        return result;
1729    }
1730}
1731
Popular Tags