1 18 package org.apache.batik.css.parser; 19 20 import java.io.IOException ; 21 import java.io.InputStream ; 22 import java.io.Reader ; 23 import java.util.Locale ; 24 import java.util.MissingResourceException ; 25 import java.util.StringTokenizer ; 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 51 public class Parser implements ExtendedParser, Localizable { 52 53 56 public final static String BUNDLE_CLASSNAME = 57 "org.apache.batik.css.parser.resources.Messages"; 58 59 62 protected LocalizableSupport localizableSupport = 63 new LocalizableSupport(BUNDLE_CLASSNAME, 64 Parser.class.getClassLoader()); 65 66 69 protected Scanner scanner; 70 71 74 protected int current; 75 76 79 protected DocumentHandler documentHandler = 80 DefaultDocumentHandler.INSTANCE; 81 82 85 protected SelectorFactory selectorFactory = 86 DefaultSelectorFactory.INSTANCE; 87 88 91 protected ConditionFactory conditionFactory = 92 DefaultConditionFactory.INSTANCE; 93 94 97 protected ErrorHandler errorHandler = DefaultErrorHandler.INSTANCE; 98 99 102 protected String pseudoElement; 103 104 107 protected String documentURI; 108 109 114 public String getParserVersion() { 115 return "http://www.w3.org/TR/REC-CSS2"; 116 } 117 118 121 public void setLocale(Locale locale) throws CSSException { 122 localizableSupport.setLocale(locale); 123 } 124 125 128 public Locale getLocale() { 129 return localizableSupport.getLocale(); 130 } 131 132 136 public String formatMessage(String key, Object [] args) 137 throws MissingResourceException { 138 return localizableSupport.formatMessage(key, args); 139 } 140 141 145 public void setDocumentHandler(DocumentHandler handler) { 146 documentHandler = handler; 147 } 148 149 153 public void setSelectorFactory(SelectorFactory factory) { 154 selectorFactory = factory; 155 } 156 157 161 public void setConditionFactory(ConditionFactory factory) { 162 conditionFactory = factory; 163 } 164 165 169 public void setErrorHandler(ErrorHandler handler) { 170 errorHandler = handler; 171 } 172 173 177 public void parseStyleSheet(InputSource source) 178 throws CSSException, IOException { 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 246 public void parseStyleSheet(String uri) throws CSSException, IOException { 247 parseStyleSheet(new InputSource(uri)); 248 } 249 250 254 public void parseStyleDeclaration(InputSource source) 255 throws CSSException, IOException { 256 257 scanner = createScanner(source); 258 parseStyleDeclarationInternal(); 259 } 260 261 264 protected void parseStyleDeclarationInternal() 265 throws CSSException, IOException { 266 nextIgnoreSpaces(); 267 try { 268 parseStyleDeclaration(false); 269 } catch (CSSParseException e) { 270 reportError(e); 271 } finally { 272 scanner = null; 273 } 274 } 275 276 280 public void parseRule(InputSource source) 281 throws CSSException, IOException { 282 scanner = createScanner(source); 283 parseRuleInternal(); 284 } 285 286 289 protected void parseRuleInternal() throws CSSException, IOException { 290 nextIgnoreSpaces(); 291 parseRule(); 292 scanner = null; 293 } 294 295 299 public SelectorList parseSelectors(InputSource source) 300 throws CSSException, IOException { 301 scanner = createScanner(source); 302 return parseSelectorsInternal(); 303 } 304 305 308 protected SelectorList parseSelectorsInternal() 309 throws CSSException, IOException { 310 nextIgnoreSpaces(); 311 SelectorList ret = parseSelectorList(); 312 scanner = null; 313 return ret; 314 } 315 316 320 public LexicalUnit parsePropertyValue(InputSource source) 321 throws CSSException, IOException { 322 scanner = createScanner(source); 323 return parsePropertyValueInternal(); 324 } 325 326 329 protected LexicalUnit parsePropertyValueInternal() 330 throws CSSException, IOException { 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 358 public boolean parsePriority(InputSource source) 359 throws CSSException, IOException { 360 scanner = createScanner(source); 361 return parsePriorityInternal(); 362 } 363 364 367 protected boolean parsePriorityInternal() 368 throws CSSException, IOException { 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 [] { new Integer (current) }); 380 return false; 381 } 382 } 383 384 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 417 protected void parseAtRule() { 418 scanner.scanAtRule(); 419 documentHandler.ignorableAtRule(scanner.getStringValue()); 420 nextIgnoreSpaces(); 421 } 422 423 426 protected void parseImportRule() { 427 String 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 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 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 504 protected void parsePageRule() { 505 String page = null; 506 String 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 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 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 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 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 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 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 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 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 func = scanner.getStringValue(); 773 if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) { 774 throw createCSSParseException("identifier"); 775 } 776 String 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 814 protected boolean isPseudoElement(String 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 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 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 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 [] { new Integer (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 [] { new Integer (current) }); 923 } 924 return result; 925 default: 926 curr = parseTerm(curr); 927 } 928 } 929 } 930 } 931 932 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 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 [] { new Integer (current) }); 1013 } 1014 } 1015 switch (current) { 1016 case LexicalUnits.STRING: 1017 String 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 [] { new Integer (current) }); 1042 } 1043 } 1044 1045 1048 protected LexicalUnit parseFunction(boolean positive, LexicalUnit prev) { 1049 String 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 [] { new Integer (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 1389 protected LexicalUnit hexcolor(LexicalUnit prev) { 1390 String 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 [] { 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 [] { val }); 1457 } 1458 nextIgnoreSpaces(); 1459 return CSSLexicalUnit.createPredefinedFunction 1460 (LexicalUnit.SAC_RGBCOLOR, params, prev); 1461 } 1462 1463 1466 protected Scanner createScanner(InputSource source) { 1467 documentURI = source.getURI(); 1468 if (documentURI == null) { 1469 documentURI = ""; 1470 } 1471 1472 Reader r = source.getCharacterStream(); 1473 if (r != null) { 1474 return new Scanner(r); 1475 } 1476 1477 InputStream is = source.getByteStream(); 1478 if (is != null) { 1479 return new Scanner(is, source.getEncoding()); 1480 } 1481 1482 String 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 e) { 1492 throw new CSSException(e); 1493 } 1494 } 1495 1496 1499 protected int skipSpaces() { 1500 int lex = scanner.getType(); 1501 while (lex == LexicalUnits.SPACE) { 1502 lex = next(); 1503 } 1504 return lex; 1505 } 1506 1507 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 1529 protected float number(boolean positive) { 1530 try { 1531 float sgn = (positive) ? 1 : -1; 1532 String val = scanner.getStringValue(); 1533 nextIgnoreSpaces(); 1534 return sgn * Float.parseFloat(val); 1535 } catch (NumberFormatException e) { 1536 throw createCSSParseException("number.format"); 1537 } 1538 } 1539 1540 1543 protected LexicalUnit dimension(boolean positive, LexicalUnit prev) { 1544 try { 1545 float sgn = (positive) ? 1 : -1; 1546 String 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 e) { 1563 throw createCSSParseException("number.format"); 1564 } 1565 } 1566 1567 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 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 1615 protected void reportError(String key) { 1616 reportError(key, null); 1617 } 1618 1619 1622 protected void reportError(String key, Object [] params) { 1623 reportError(createCSSParseException(key, params)); 1624 } 1625 1626 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 1653 protected CSSParseException createCSSParseException(String key) { 1654 return createCSSParseException(key, null); 1655 } 1656 1657 1660 protected CSSParseException createCSSParseException(String key, 1661 Object [] params) { 1662 return new CSSParseException(formatMessage(key, params), 1663 documentURI, 1664 scanner.getLine(), 1665 scanner.getColumn()); 1666 } 1667 1668 1672 1675 public void parseStyleDeclaration(String source) 1676 throws CSSException, IOException { 1677 scanner = new Scanner(source); 1678 parseStyleDeclarationInternal(); 1679 } 1680 1681 1684 public void parseRule(String source) throws CSSException, IOException { 1685 scanner = new Scanner(source); 1686 parseRuleInternal(); 1687 } 1688 1689 1692 public SelectorList parseSelectors(String source) 1693 throws CSSException, IOException { 1694 scanner = new Scanner(source); 1695 return parseSelectorsInternal(); 1696 } 1697 1698 1701 public LexicalUnit parsePropertyValue(String source) 1702 throws CSSException, IOException { 1703 scanner = new Scanner(source); 1704 return parsePropertyValueInternal(); 1705 } 1706 1707 1710 public boolean parsePriority(String source) 1711 throws CSSException, IOException { 1712 scanner = new Scanner(source); 1713 return parsePriorityInternal(); 1714 } 1715 1716 1719 public SACMediaList parseMedia(String mediaText) 1720 throws CSSException, IOException { 1721 CSSSACMediaList result = new CSSSACMediaList(); 1722 if (!"all".equalsIgnoreCase(mediaText)) { 1723 StringTokenizer st = new StringTokenizer (mediaText, " ,"); 1724 while (st.hasMoreTokens()) { 1725 result.append(st.nextToken()); 1726 } 1727 } 1728 return result; 1729 } 1730} 1731 | Popular Tags |