0001 /* 0002 0003 ============================================================================ 0004 The Apache Software License, Version 1.1 0005 ============================================================================ 0006 0007 Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. 0008 0009 Redistribution and use in source and binary forms, with or without modifica- 0010 tion, are permitted provided that the following conditions are met: 0011 0012 1. Redistributions of source code must retain the above copyright notice, 0013 this list of conditions and the following disclaimer. 0014 0015 2. Redistributions in binary form must reproduce the above copyright notice, 0016 this list of conditions and the following disclaimer in the documentation 0017 and/or other materials provided with the distribution. 0018 0019 3. The end-user documentation included with the redistribution, if any, must 0020 include the following acknowledgment: "This product includes software 0021 developed by the Apache Software Foundation (http://www.apache.org/)." 0022 Alternately, this acknowledgment may appear in the software itself, if 0023 and wherever such third-party acknowledgments normally appear. 0024 0025 4. The names "Batik" and "Apache Software Foundation" must not be 0026 used to endorse or promote products derived from this software without 0027 prior written permission. For written permission, please contact 0028 apache@apache.org. 0029 0030 5. Products derived from this software may not be called "Apache", nor may 0031 "Apache" appear in their name, without prior written permission of the 0032 Apache Software Foundation. 0033 0034 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, 0035 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 0036 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 0037 APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 0038 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- 0039 DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 0040 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 0041 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0042 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0043 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0044 0045 This software consists of voluntary contributions made by many individuals 0046 on behalf of the Apache Software Foundation. For more information on the 0047 Apache Software Foundation, please see <http://www.apache.org/>. 0048 0049 */ 0050 0051 package org.apache.batik.css.parser; 0052 0053 import java.io.IOException; 0054 import java.io.InputStream; 0055 import java.io.Reader; 0056 0057 import org.apache.batik.util.io.NormalizingReader; 0058 import org.apache.batik.util.io.StreamNormalizingReader; 0059 import org.apache.batik.util.io.StringNormalizingReader; 0060 0061 /** 0062 * This class represents a CSS scanner - an object which decodes CSS lexical 0063 * units. 0064 * 0065 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a> 0066 * @version $Id: Scanner.java,v 1.14 2004/02/16 16:33:54 hillion Exp $ 0067 */ 0068 public class Scanner { 0069 0070 /** 0071 * The reader. 0072 */ 0073 protected NormalizingReader reader; 0074 0075 /** 0076 * The current char. 0077 */ 0078 protected int current; 0079 0080 /** 0081 * The recording buffer. 0082 */ 0083 protected char[] buffer = new char[128]; 0084 0085 /** 0086 * The current position in the buffer. 0087 */ 0088 protected int position; 0089 0090 /** 0091 * The type of the current lexical unit. 0092 */ 0093 protected int type; 0094 0095 /** 0096 * The start offset of the last lexical unit. 0097 */ 0098 protected int start; 0099 0100 /** 0101 * The end offset of the last lexical unit. 0102 */ 0103 protected int end; 0104 0105 /** 0106 * The characters to skip to create the string which represents the 0107 * current token. 0108 */ 0109 protected int blankCharacters; 0110 0111 /** 0112 * Creates a new Scanner object. 0113 * @param r The reader to scan. 0114 */ 0115 public Scanner(Reader r) throws ParseException { 0116 try { 0117 reader = new StreamNormalizingReader(r); Rate0118 current = nextChar(); 0119 } catch (IOException e) { 0120 throw new ParseException(e); 0121 } 0122 } 0123 0124 /** 0125 * Creates a new Scanner object. 0126 * @param is The input stream to scan. 0127 * @param enc The encoding to use to decode the input stream, or null. 0128 */ 0129 public Scanner(InputStream is, String enc) throws ParseException { 0130 try { 0131 reader = new StreamNormalizingReader(is, enc); Rate0132 current = nextChar(); 0133 } catch (IOException e) { 0134 throw new ParseException(e); 0135 } 0136 } 0137 0138 /** 0139 * Creates a new Scanner object. 0140 * @param r The reader to scan. 0141 */ 0142 public Scanner(String s) throws ParseException { 0143 try { 0144 reader = new StringNormalizingReader(s); Rate0145 current = nextChar(); 0146 } catch (IOException e) { 0147 throw new ParseException(e); 0148 } 0149 } 0150 0151 /** 0152 * Returns the current line. 0153 */ 0154 public int getLine() { 0155 return reader.getLine(); 0156 } 0157 0158 /** 0159 * Returns the current column. 0160 */ 0161 public int getColumn() { 0162 return reader.getColumn(); 0163 } 0164 0165 /** 0166 * Returns the buffer used to store the chars. 0167 */ 0168 public char[] getBuffer() { 0169 return buffer; 0170 } 0171 0172 /** 0173 * Returns the start offset of the last lexical unit. 0174 */ 0175 public int getStart() { 0176 return start; 0177 } 0178 0179 /** 0180 * Returns the end offset of the last lexical unit. 0181 */ 0182 public int getEnd() { 0183 return end; 0184 } 0185 0186 /** 0187 * Clears the buffer. 0188 */ 0189 public void clearBuffer() { 0190 if (position <= 0) { 0191 position = 0; 0192 } else { 0193 buffer[0] = buffer[position-1]; 0194 position = 1; 0195 } 0196 } 0197 0198 /** 0199 * The current lexical unit type like defined in LexicalUnits. 0200 */ 0201 public int getType() { 0202 return type; 0203 } 0204 0205 /** 0206 * Returns the string representation of the current lexical unit. 0207 */ 0208 public String getStringValue() { 0209 return new String(buffer, start, end - start); 0210 } 0211 0212 /** 0213 * Scans a @rule value. This method assumes that the current 0214 * lexical unit is a at keyword. 0215 */ 0216 public void scanAtRule() throws ParseException { 0217 try { 0218 // waiting for EOF, ';' or '{' 0219 loop: for (;;) { 0220 switch (current) { 0221 case '{': 0222 int brackets = 1; 0223 for (;;) { Rate0224 nextChar(); 0225 switch (current) { 0226 case '}': 0227 if (--brackets > 0) { 0228 break; 0229 } 0230 case -1: 0231 break loop; 0232 case '{': 0233 brackets++; 0234 } 0235 } 0236 case -1: 0237 case ';': 0238 break loop; 0239 } Rate0240 nextChar(); 0241 } 0242 end = position; 0243 } catch (IOException e) { 0244 throw new ParseException(e); 0245 } 0246 } 0247 0248 /** 0249 * Returns the next token. 0250 */ 0251 public int next() throws ParseException { 0252 blankCharacters = 0; 0253 start = position - 1; 0254 nextToken(); 0255 end = position - endGap(); 0256 return type; 0257 } 0258 0259 /** 0260 * Returns the end gap of the current lexical unit. 0261 */ 0262 protected int endGap() { 0263 int result = (current == -1) ? 0 : 1; 0264 switch (type) { 0265 case LexicalUnits.FUNCTION: 0266 case LexicalUnits.STRING: 0267 case LexicalUnits.S: 0268 case LexicalUnits.PERCENTAGE: 0269 result += 1; 0270 break; 0271 case LexicalUnits.COMMENT: 0272 case LexicalUnits.HZ: 0273 case LexicalUnits.EM: 0274 case LexicalUnits.EX: 0275 case LexicalUnits.PC: 0276 case LexicalUnits.PT: 0277 case LexicalUnits.PX: 0278 case LexicalUnits.CM: 0279 case LexicalUnits.MM: 0280 case LexicalUnits.IN: 0281 case LexicalUnits.MS: 0282 result += 2; 0283 break; 0284 case LexicalUnits.KHZ: 0285 case LexicalUnits.DEG: 0286 case LexicalUnits.RAD: 0287 result += 3; 0288 break; 0289 case LexicalUnits.GRAD: 0290 result += 4; 0291 } 0292 return result + blankCharacters; 0293 } 0294 0295 /** 0296 * Returns the next token. 0297 */ 0298 protected void nextToken() throws ParseException { 0299 try { 0300 switch (current) { 0301 case -1: 0302 type = LexicalUnits.EOF; 0303 return; 0304 case '{': Rate0305 nextChar(); 0306 type = LexicalUnits.LEFT_CURLY_BRACE; 0307 return; 0308 case '}': Rate0309 nextChar(); 0310 type = LexicalUnits.RIGHT_CURLY_BRACE; 0311 return; 0312 case '=': Rate0313 nextChar(); 0314 type = LexicalUnits.EQUAL; 0315 return; 0316 case '+': Rate0317 nextChar(); 0318 type = LexicalUnits.PLUS; 0319 return; 0320 case ',': Rate0321 nextChar(); 0322 type = LexicalUnits.COMMA; 0323 return; 0324 case ';': Rate0325 nextChar(); 0326 type = LexicalUnits.SEMI_COLON; 0327 return; 0328 case '>': Rate0329 nextChar(); 0330 type = LexicalUnits.PRECEDE; 0331 return; 0332 case '[': Rate0333 nextChar(); 0334 type = LexicalUnits.LEFT_BRACKET; 0335 return; 0336 case ']': Rate0337 nextChar(); 0338 type = LexicalUnits.RIGHT_BRACKET; 0339 return; 0340 case '*': Rate0341 nextChar(); 0342 type = LexicalUnits.ANY; 0343 return; 0344 case '(': Rate0345 nextChar(); 0346 type = LexicalUnits.LEFT_BRACE; 0347 return; 0348 case ')': Rate0349 nextChar(); 0350 type = LexicalUnits.RIGHT_BRACE; 0351 return; 0352 case ':': Rate0353 nextChar(); 0354 type = LexicalUnits.COLON; 0355 return; 0356 case ' ': 0357 case '\t': 0358 case '\r': 0359 case '\n': 0360 case '\f': 0361 do { Rate0362 nextChar(); 0363 } while (ScannerUtilities.isCSSSpace((char)current)); 0364 type = LexicalUnits.SPACE; 0365 return; 0366 case '/': Rate0367 nextChar(); 0368 if (current != '*') { 0369 type = LexicalUnits.DIVIDE; 0370 return; 0371 } 0372 // Comment Rate0373 nextChar(); 0374 start = position - 1; 0375 do { 0376 while (current != -1 && current != '*') { Rate0377 nextChar(); 0378 } 0379 do { Rate0380 nextChar(); 0381 } while (current != -1 && current == '*'); 0382 } while (current != -1 && current != '/'); 0383 if (current == -1) { 0384 throw new ParseException("eof", 0385 reader.getLine(), 0386 reader.getColumn()); 0387 } Rate0388 nextChar(); 0389 type = LexicalUnits.COMMENT; 0390 return; 0391 case '\'': // String1 0392 type = string1(); 0393 return; 0394 case '"': // String2 0395 type = string2(); 0396 return; 0397 case '<': Rate0398 nextChar(); 0399 if (current != '!') { 0400 throw new ParseException("character", 0401 reader.getLine(), 0402 reader.getColumn()); 0403 } Rate0404 nextChar(); 0405 if (current == '-') { Rate0406 nextChar(); 0407 if (current == '-') { Rate0408 nextChar(); 0409 type = LexicalUnits.CDO; 0410 return; 0411 } 0412 } 0413 throw new ParseException("character", 0414 reader.getLine(), 0415 reader.getColumn()); 0416 case '-': Rate0417 nextChar(); 0418 if (current != '-') { 0419 type = LexicalUnits.MINUS; 0420 return; 0421 } Rate0422 nextChar(); 0423 if (current == '>') { Rate0424 nextChar(); 0425 type = LexicalUnits.CDC; 0426 return; 0427 } 0428 throw new ParseException("character", 0429 reader.getLine(), 0430 reader.getColumn()); 0431 case '|': Rate0432 nextChar(); 0433 if (current == '=') { Rate0434 nextChar(); 0435 type = LexicalUnits.DASHMATCH; 0436 return; 0437 } 0438 throw new ParseException("character", 0439 reader.getLine(), 0440 reader.getColumn()); 0441 case '~': Rate0442 nextChar(); 0443 if (current == '=') { Rate0444 nextChar(); 0445 type = LexicalUnits.INCLUDES; 0446 return; 0447 } 0448 throw new ParseException("character", 0449 reader.getLine(), 0450 reader.getColumn()); 0451 case '#': Rate0452 nextChar(); 0453 if (ScannerUtilities.isCSSNameCharacter((char)current)) { 0454 start = position - 1; 0455 do { Rate0456 nextChar(); 0457 if (current == '\\') { Rate0458 nextChar(); 0459 escape(); 0460 } 0461 } while (current != -1 && 0462 ScannerUtilities.isCSSNameCharacter 0463 ((char)current)); 0464 type = LexicalUnits.HASH; 0465 return; 0466 } 0467 throw new ParseException("character", 0468 reader.getLine(), 0469 reader.getColumn()); 0470 case '@': Rate0471 nextChar(); 0472 switch (current) { 0473 case 'c': 0474 case 'C': 0475 start = position - 1; Rate0476 if (isEqualIgnoreCase(nextChar(), 'h') && 0477 isEqualIgnoreCase(nextChar(), 'a') && 0478 isEqualIgnoreCase(nextChar(), 'r') && 0479 isEqualIgnoreCase(nextChar(), 's') && 0480 isEqualIgnoreCase(nextChar(), 'e') && 0481 isEqualIgnoreCase(nextChar(), 't')) { Rate0482 nextChar(); 0483 type = LexicalUnits.CHARSET_SYMBOL; 0484 return; 0485 } 0486 break; 0487 case 'f': 0488 case 'F': 0489 start = position - 1; Rate0490 if (isEqualIgnoreCase(nextChar(), 'o') && 0491 isEqualIgnoreCase(nextChar(), 'n') && 0492 isEqualIgnoreCase(nextChar(), 't') && 0493 isEqualIgnoreCase(nextChar(), '-') && 0494 isEqualIgnoreCase(nextChar(), 'f') && 0495 isEqualIgnoreCase(nextChar(), 'a') && 0496 isEqualIgnoreCase(nextChar(), 'c') && 0497 isEqualIgnoreCase(nextChar(), 'e')) { Rate0498 nextChar(); 0499 type = LexicalUnits.FONT_FACE_SYMBOL; 0500 return; 0501 } 0502 break; 0503 case 'i': 0504 case 'I': 0505 start = position - 1; Rate0506 if (isEqualIgnoreCase(nextChar(), 'm') && 0507 isEqualIgnoreCase(nextChar(), 'p') && 0508 isEqualIgnoreCase(nextChar(), 'o') && 0509 isEqualIgnoreCase(nextChar(), 'r') && 0510 isEqualIgnoreCase(nextChar(), 't')) { Rate0511 nextChar(); 0512 type = LexicalUnits.IMPORT_SYMBOL; 0513 return; 0514 } 0515 break; 0516 case 'm': 0517 case 'M': 0518 start = position - 1; Rate0519 if (isEqualIgnoreCase(nextChar(), 'e') && 0520 isEqualIgnoreCase(nextChar(), 'd') && 0521 isEqualIgnoreCase(nextChar(), 'i') && 0522 isEqualIgnoreCase(nextChar(), 'a')) { Rate0523 nextChar(); 0524 type = LexicalUnits.MEDIA_SYMBOL; 0525 return; 0526 } 0527 break; 0528 case 'p': 0529 case 'P': 0530 start = position - 1; Rate0531 if (isEqualIgnoreCase(nextChar(), 'a') && 0532 isEqualIgnoreCase(nextChar(), 'g') && 0533 isEqualIgnoreCase(nextChar(), 'e')) { Rate0534 nextChar(); 0535 type = LexicalUnits.PAGE_SYMBOL; 0536 return; 0537 } 0538 break; 0539 default: 0540 if (!ScannerUtilities.isCSSIdentifierStartCharacter 0541 ((char)current)) { 0542 throw new ParseException("identifier.character", 0543 reader.getLine(), 0544 reader.getColumn()); 0545 } 0546 start = position - 1; 0547 } 0548 do { Rate0549 nextChar(); 0550 if (current == '\\') { Rate0551 nextChar(); 0552 escape(); 0553 } 0554 } while (current != -1 && 0555 ScannerUtilities.isCSSNameCharacter((char)current)); 0556 type = LexicalUnits.AT_KEYWORD; 0557 return; 0558 case '!': 0559 do { Rate0560 nextChar(); 0561 } while (current != -1 && 0562 ScannerUtilities.isCSSSpace((char)current)); Rate0563 if (isEqualIgnoreCase(current, 'i') && 0564 isEqualIgnoreCase(nextChar(), 'm') && 0565 isEqualIgnoreCase(nextChar(), 'p') && 0566 isEqualIgnoreCase(nextChar(), 'o') && 0567 isEqualIgnoreCase(nextChar(), 'r') && 0568 isEqualIgnoreCase(nextChar(), 't') && 0569 isEqualIgnoreCase(nextChar(), 'a') && 0570 isEqualIgnoreCase(nextChar(), 'n') && 0571 isEqualIgnoreCase(nextChar(), 't')) { Rate0572 nextChar(); 0573 type = LexicalUnits.IMPORTANT_SYMBOL; 0574 return; 0575 } 0576 if (current == -1) { 0577 throw new ParseException("eof", 0578 reader.getLine(), 0579 reader.getColumn()); 0580 } else { 0581 throw new ParseException("character", 0582 reader.getLine(), 0583 reader.getColumn()); 0584 } 0585 case '0': case '1': case '2': case '3': case '4': 0586 case '5': case '6': case '7': case '8': case '9': 0587 type = number(); 0588 return; 0589 case '.': Rate0590 switch (nextChar()) { 0591 case '0': case '1': case '2': case '3': case '4': 0592 case '5': case '6': case '7': case '8': case '9': 0593 type = dotNumber(); 0594 return; 0595 default: 0596 type = LexicalUnits.DOT; 0597 return; 0598 } 0599 case 'u': 0600 case 'U': Rate0601 nextChar(); 0602 switch (current) { 0603 case '+': 0604 boolean range = false; 0605 for (int i = 0; i < 6; i++) { Rate0606 nextChar(); 0607 switch (current) { 0608 case '?': 0609 range = true; 0610 break; 0611 default: 0612 if (range && 0613 !ScannerUtilities.isCSSHexadecimalCharacter 0614 ((char)current)) { 0615 throw new ParseException("character", 0616 reader.getLine(), 0617 reader.getColumn()); 0618 } 0619 } 0620 } Rate0621 nextChar(); 0622 if (range) { 0623 type = LexicalUnits.UNICODE_RANGE; 0624 return; 0625 } 0626 if (current == '-') { Rate0627 nextChar(); 0628 if (!ScannerUtilities.isCSSHexadecimalCharacter 0629 ((char)current)) { 0630 throw new ParseException("character", 0631 reader.getLine(), 0632 reader.getColumn()); 0633 } Rate0634 nextChar(); 0635 if (!ScannerUtilities.isCSSHexadecimalCharacter 0636 ((char)current)) { 0637 type = LexicalUnits.UNICODE_RANGE; 0638 return; 0639 } Rate0640 nextChar(); 0641 if (!ScannerUtilities.isCSSHexadecimalCharacter 0642 ((char)current)) { 0643 type = LexicalUnits.UNICODE_RANGE; 0644 return; 0645 } Rate0646 nextChar(); 0647 if (!ScannerUtilities.isCSSHexadecimalCharacter 0648 ((char)current)) { 0649 type = LexicalUnits.UNICODE_RANGE; 0650 return; 0651 } Rate0652 nextChar(); 0653 if (!ScannerUtilities.isCSSHexadecimalCharacter 0654 ((char)current)) { 0655 type = LexicalUnits.UNICODE_RANGE; 0656 return; 0657 } Rate0658 nextChar(); 0659 if (!ScannerUtilities.isCSSHexadecimalCharacter 0660 ((char)current)) { 0661 type = LexicalUnits.UNICODE_RANGE; 0662 return; 0663 } Rate0664 nextChar(); 0665 type = LexicalUnits.UNICODE_RANGE; 0666 return; 0667 } 0668 case 'r': 0669 case 'R': Rate0670 nextChar(); 0671 switch (current) { 0672 case 'l': 0673 case 'L': Rate0674 nextChar(); 0675 switch (current) { 0676 case '(': 0677 do { Rate0678 nextChar(); 0679 } while (current != -1 && 0680 ScannerUtilities.isCSSSpace 0681 ((char)current)); 0682 switch (current) { 0683 case '\'': 0684 string1(); 0685 blankCharacters += 2; 0686 while (current != -1 && 0687 ScannerUtilities.isCSSSpace 0688 ((char)current)) { 0689 blankCharacters++; Rate0690 nextChar(); 0691 } 0692 if (current == -1) { 0693 throw new ParseException 0694 ("eof", 0695 reader.getLine(), 0696 reader.getColumn()); 0697 } 0698 if (current != ')') { 0699 throw new ParseException 0700 ("character", 0701 reader.getLine(), 0702 reader.getColumn()); 0703 } Rate0704 nextChar(); 0705 type = LexicalUnits.URI; 0706 return; 0707 case '"': 0708 string2(); 0709 blankCharacters += 2; 0710 while (current != -1 && 0711 ScannerUtilities.isCSSSpace 0712 ((char)current)) { 0713 blankCharacters++; Rate0714 nextChar(); 0715 } 0716 if (current == -1) { 0717 throw new ParseException 0718 ("eof", 0719 reader.getLine(), 0720 reader.getColumn()); 0721 } 0722 if (current != ')') { 0723 throw new ParseException 0724 ("character", 0725 reader.getLine(), 0726 reader.getColumn()); 0727 } Rate0728 nextChar(); 0729 type = LexicalUnits.URI; 0730 return; 0731 case ')': 0732 throw new ParseException("character", 0733 reader.getLine(), 0734 reader.getColumn()); 0735 default: 0736 if (!ScannerUtilities.isCSSURICharacter 0737 ((char)current)) { 0738 throw new ParseException 0739 ("character", 0740 reader.getLine(), 0741 reader.getColumn()); 0742 } 0743 start = position - 1; 0744 do { Rate0745 nextChar(); 0746 } while (current != -1 && 0747 ScannerUtilities.isCSSURICharacter 0748 ((char)current)); 0749 blankCharacters++; 0750 while (current != -1 && 0751 ScannerUtilities.isCSSSpace 0752 ((char)current)) { 0753 blankCharacters++; Rate0754 nextChar(); 0755 } 0756 if (current == -1) { 0757 throw new ParseException 0758 ("eof", 0759 reader.getLine(), 0760 reader.getColumn()); 0761 } 0762 if (current != ')') { 0763 throw new ParseException 0764 ("character", 0765 reader.getLine(), 0766 reader.getColumn()); 0767 } Rate0768 nextChar(); 0769 type = LexicalUnits.URI; 0770 return; 0771 } 0772 } 0773 } 0774 } 0775 while (current != -1 && 0776 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate0777 nextChar(); 0778 } 0779 if (current == '(') { Rate0780 nextChar(); 0781 type = LexicalUnits.FUNCTION; 0782 return; 0783 } 0784 type = LexicalUnits.IDENTIFIER; 0785 return; 0786 default: 0787 if (ScannerUtilities.isCSSIdentifierStartCharacter 0788 ((char)current)) { 0789 // Identifier 0790 do { Rate0791 nextChar(); 0792 if (current == '\\') { Rate0793 nextChar(); 0794 escape(); 0795 } 0796 } while (current != -1 && 0797 ScannerUtilities.isCSSNameCharacter 0798 ((char)current)); 0799 if (current == '(') { Rate0800 nextChar(); 0801 type = LexicalUnits.FUNCTION; 0802 return; 0803 } 0804 type = LexicalUnits.IDENTIFIER; 0805 return; 0806 } Rate0807 nextChar(); 0808 throw new ParseException("identifier.character", 0809 reader.getLine(), 0810 reader.getColumn()); 0811 } 0812 } catch (IOException e) { 0813 throw new ParseException(e); 0814 } 0815 } 0816 0817 /** 0818 * Scans a single quoted string. 0819 */ 0820 protected int string1() throws IOException { Rate0821 nextChar(); 0822 start = position - 1; 0823 loop: for (;;) { Rate0824 switch (nextChar()) { 0825 case -1: 0826 throw new ParseException("eof", 0827 reader.getLine(), 0828 reader.getColumn()); 0829 case '\'': 0830 break loop; 0831 case '"': 0832 break; 0833 case '\\': Rate0834 switch (nextChar()) { 0835 case '\n': 0836 case '\f': 0837 break; 0838 default: 0839 escape(); 0840 } 0841 break; 0842 default: 0843 if (!ScannerUtilities.isCSSStringCharacter((char)current)) { 0844 throw new ParseException("character", 0845 reader.getLine(), 0846 reader.getColumn()); 0847 } 0848 } 0849 } Rate0850 nextChar(); 0851 return LexicalUnits.STRING; 0852 } 0853 0854 /** 0855 * Scans a double quoted string. 0856 */ 0857 protected int string2() throws IOException { Rate0858 nextChar(); 0859 start = position - 1; 0860 loop: for (;;) { Rate0861 switch (nextChar()) { 0862 case -1: 0863 throw new ParseException("eof", 0864 reader.getLine(), 0865 reader.getColumn()); 0866 case '\'': 0867 break; 0868 case '"': 0869 break loop; 0870 case '\\': Rate0871 switch (nextChar()) { 0872 case '\n': 0873 case '\f': 0874 break; 0875 default: 0876 escape(); 0877 } 0878 break; 0879 default: 0880 if (!ScannerUtilities.isCSSStringCharacter((char)current)) { 0881 throw new ParseException("character", 0882 reader.getLine(), 0883 reader.getColumn()); 0884 } 0885 } 0886 } Rate0887 nextChar(); 0888 return LexicalUnits.STRING; 0889 } 0890 0891 /** 0892 * Scans a number. 0893 */ 0894 protected int number() throws IOException { 0895 loop: for (;;) { Rate0896 switch (nextChar()) { 0897 case '.': Rate0898 switch (nextChar()) { 0899 case '0': case '1': case '2': case '3': case '4': 0900 case '5': case '6': case '7': case '8': case '9': 0901 return dotNumber(); 0902 } 0903 throw new ParseException("character", 0904 reader.getLine(), 0905 reader.getColumn()); 0906 default: 0907 break loop; 0908 case '0': case '1': case '2': case '3': case '4': 0909 case '5': case '6': case '7': case '8': case '9': 0910 } 0911 } 0912 return numberUnit(true); 0913 } 0914 0915 /** 0916 * Scans the decimal part of a number. 0917 */ 0918 protected int dotNumber() throws IOException { 0919 loop: for (;;) { Rate0920 switch (nextChar()) { 0921 default: 0922 break loop; 0923 case '0': case '1': case '2': case '3': case '4': 0924 case '5': case '6': case '7': case '8': case '9': 0925 } 0926 } 0927 return numberUnit(false); 0928 } 0929 0930 /** 0931 * Scans the unit of a number. 0932 */ 0933 protected int numberUnit(boolean integer) throws IOException { 0934 switch (current) { 0935 case '%': Rate0936 nextChar(); 0937 return LexicalUnits.PERCENTAGE; 0938 case 'c': 0939 case 'C': Rate0940 switch(nextChar()) { 0941 case 'm': 0942 case 'M': Rate0943 nextChar(); 0944 if (current != -1 && 0945 ScannerUtilities.isCSSNameCharacter((char)current)) { 0946 do { Rate0947 nextChar(); 0948 } while (current != -1 && 0949 ScannerUtilities.isCSSNameCharacter 0950 ((char)current)); 0951 return LexicalUnits.DIMENSION; 0952 } 0953 return LexicalUnits.CM; 0954 default: 0955 while (current != -1 && 0956 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate0957 nextChar(); 0958 } 0959 return LexicalUnits.DIMENSION; 0960 } 0961 case 'd': 0962 case 'D': Rate0963 switch(nextChar()) { 0964 case 'e': 0965 case 'E': Rate0966 switch(nextChar()) { 0967 case 'g': 0968 case 'G': Rate0969 nextChar(); 0970 if (current != -1 && 0971 ScannerUtilities.isCSSNameCharacter((char)current)) { 0972 do { Rate0973 nextChar(); 0974 } while (current != -1 && 0975 ScannerUtilities.isCSSNameCharacter 0976 ((char)current)); 0977 return LexicalUnits.DIMENSION; 0978 } 0979 return LexicalUnits.DEG; 0980 } 0981 default: 0982 while (current != -1 && 0983 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate0984 nextChar(); 0985 } 0986 return LexicalUnits.DIMENSION; 0987 } 0988 case 'e': 0989 case 'E': Rate0990 switch(nextChar()) { 0991 case 'm': 0992 case 'M': Rate0993 nextChar(); 0994 if (current != -1 && 0995 ScannerUtilities.isCSSNameCharacter((char)current)) { 0996 do { Rate0997 nextChar(); 0998 } while (current != -1 && 0999 ScannerUtilities.isCSSNameCharacter 1000 ((char)current)); 1001 return LexicalUnits.DIMENSION; 1002 } 1003 return LexicalUnits.EM; 1004 case 'x': 1005 case 'X': Rate1006 nextChar(); 1007 if (current != -1 && 1008 ScannerUtilities.isCSSNameCharacter((char)current)) { 1009 do { Rate1010 nextChar(); 1011 } while (current != -1 && 1012 ScannerUtilities.isCSSNameCharacter 1013 ((char)current)); 1014 return LexicalUnits.DIMENSION; 1015 } 1016 return LexicalUnits.EX; 1017 default: 1018 while (current != -1 && 1019 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate1020 nextChar(); 1021 } 1022 return LexicalUnits.DIMENSION; 1023 } 1024 case 'g': 1025 case 'G': Rate1026 switch(nextChar()) { 1027 case 'r': 1028 case 'R': Rate1029 switch(nextChar()) { 1030 case 'a': 1031 case 'A': Rate1032 switch(nextChar()) { 1033 case 'd': 1034 case 'D': Rate1035 nextChar(); 1036 if (current != -1 && 1037 ScannerUtilities.isCSSNameCharacter 1038 ((char)current)) { 1039 do { Rate1040 nextChar(); 1041 } while (current != -1 && 1042 ScannerUtilities.isCSSNameCharacter 1043 ((char)current)); 1044 return LexicalUnits.DIMENSION; 1045 } 1046 return LexicalUnits.GRAD; 1047 } 1048 } 1049 default: 1050 while (current != -1 && 1051 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate1052 nextChar(); 1053 } 1054 return LexicalUnits.DIMENSION; 1055 } 1056 case 'h': 1057 case 'H': Rate1058 nextChar(); 1059 switch(current) { 1060 case 'z': 1061 case 'Z': Rate1062 nextChar(); 1063 if (current != -1 && 1064 ScannerUtilities.isCSSNameCharacter((char)current)) { 1065 do { Rate1066 nextChar(); 1067 } while (current != -1 && 1068 ScannerUtilities.isCSSNameCharacter 1069 ((char)current)); 1070 return LexicalUnits.DIMENSION; 1071 } 1072 return LexicalUnits.HZ; 1073 default: 1074 while (current != -1 && 1075 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate1076 nextChar(); 1077 } 1078 return LexicalUnits.DIMENSION; 1079 } 1080 case 'i': 1081 case 'I': Rate1082 switch(nextChar()) { 1083 case 'n': 1084 case 'N': Rate1085 nextChar(); 1086 if (current != -1 && 1087 ScannerUtilities.isCSSNameCharacter((char)current)) { 1088 do { Rate1089 nextChar(); 1090 } while (current != -1 && 1091 ScannerUtilities.isCSSNameCharacter 1092 ((char)current)); 1093 return LexicalUnits.DIMENSION; 1094 } 1095 return LexicalUnits.IN; 1096 default: 1097 while (current != -1 && 1098 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate1099 nextChar(); 1100 } 1101 return LexicalUnits.DIMENSION; 1102 } 1103 case 'k': 1104 case 'K': Rate1105 switch(nextChar()) { 1106 case 'h': 1107 case 'H': Rate1108 switch(nextChar()) { 1109 case 'z': 1110 case 'Z': Rate1111 nextChar(); 1112 if (current != -1 && 1113 ScannerUtilities.isCSSNameCharacter((char)current)) { 1114 do { Rate1115 nextChar(); 1116 } while (current != -1 && 1117 ScannerUtilities.isCSSNameCharacter 1118 ((char)current)); 1119 return LexicalUnits.DIMENSION; 1120 } 1121 return LexicalUnits.KHZ; 1122 } 1123 default: 1124 while (current != -1 && 1125 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate1126 nextChar(); 1127 } 1128 return LexicalUnits.DIMENSION; 1129 } 1130 case 'm': 1131 case 'M': Rate1132 switch(nextChar()) { 1133 case 'm': 1134 case 'M': Rate1135 nextChar(); 1136 if (current != -1 && 1137 ScannerUtilities.isCSSNameCharacter((char)current)) { 1138 do { Rate1139 nextChar(); 1140 } while (current != -1 && 1141 ScannerUtilities.isCSSNameCharacter 1142 ((char)current)); 1143 return LexicalUnits.DIMENSION; 1144 } 1145 return LexicalUnits.MM; 1146 case 's': 1147 case 'S': Rate1148 nextChar(); 1149 if (current != -1 && 1150 ScannerUtilities.isCSSNameCharacter((char)current)) { 1151 do { Rate1152 nextChar(); 1153 } while (current != -1 && 1154 ScannerUtilities.isCSSNameCharacter 1155 ((char)current)); 1156 return LexicalUnits.DIMENSION; 1157 } 1158 return LexicalUnits.MS; 1159 default: 1160 while (current != -1 && 1161 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate1162 nextChar(); 1163 } 1164 return LexicalUnits.DIMENSION; 1165 } 1166 case 'p': 1167 case 'P': Rate1168 switch(nextChar()) { 1169 case 'c': 1170 case 'C': Rate1171 nextChar(); 1172 if (current != -1 && 1173 ScannerUtilities.isCSSNameCharacter((char)current)) { 1174 do { Rate1175 nextChar(); 1176 } while (current != -1 && 1177 ScannerUtilities.isCSSNameCharacter 1178 ((char)current)); 1179 return LexicalUnits.DIMENSION; 1180 } 1181 return LexicalUnits.PC; 1182 case 't': 1183 case 'T': Rate1184 nextChar(); 1185 if (current != -1 && 1186 ScannerUtilities.isCSSNameCharacter((char)current)) { 1187 do { Rate1188 nextChar(); 1189 } while (current != -1 && 1190 ScannerUtilities.isCSSNameCharacter 1191 ((char)current)); 1192 return LexicalUnits.DIMENSION; 1193 } 1194 return LexicalUnits.PT; 1195 case 'x': 1196 case 'X': Rate1197 nextChar(); 1198 if (current != -1 && 1199 ScannerUtilities.isCSSNameCharacter((char)current)) { 1200 do { Rate1201 nextChar(); 1202 } while (current != -1 && 1203 ScannerUtilities.isCSSNameCharacter 1204 ((char)current)); 1205 return LexicalUnits.DIMENSION; 1206 } 1207 return LexicalUnits.PX; 1208 default: 1209 while (current != -1 && 1210 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate1211 nextChar(); 1212 } 1213 return LexicalUnits.DIMENSION; 1214 } 1215 case 'r': 1216 case 'R': Rate1217 switch(nextChar()) { 1218 case 'a': 1219 case 'A': Rate1220 switch(nextChar()) { 1221 case 'd': 1222 case 'D': Rate1223 nextChar(); 1224 if (current != -1 && 1225 ScannerUtilities.isCSSNameCharacter((char)current)) { 1226 do { Rate1227 nextChar(); 1228 } while (current != -1 && 1229 ScannerUtilities.isCSSNameCharacter 1230 ((char)current)); 1231 return LexicalUnits.DIMENSION; 1232 } 1233 return LexicalUnits.RAD; 1234 } 1235 default: 1236 while (current != -1 && 1237 ScannerUtilities.isCSSNameCharacter((char)current)) { Rate1238 nextChar(); 1239 } 1240 return LexicalUnits.DIMENSION; 1241 } 1242 case 's': 1243 case 'S': Rate1244 nextChar(); 1245 return LexicalUnits.S; 1246 default: 1247 if (current != -1 && 1248 ScannerUtilities.isCSSIdentifierStartCharacter 1249 ((char)current)) { 1250 do { Rate1251 nextChar(); 1252 } while (current != -1 && 1253 ScannerUtilities.isCSSNameCharacter((char)current)); 1254 return LexicalUnits.DIMENSION; 1255 } 1256 return (integer) ? LexicalUnits.INTEGER : LexicalUnits.REAL; 1257 } 1258 } 1259 1260 /** 1261 * Scans an escape sequence, if one. 1262 */ 1263 protected void escape() throws IOException { 1264 if (ScannerUtilities.isCSSHexadecimalCharacter((char)current)) { Rate1265 nextChar(); 1266 if (!ScannerUtilities.isCSSHexadecimalCharacter((char)current)) { 1267 if (ScannerUtilities.isCSSSpace((char)current)) { Rate1268 nextChar(); 1269 } 1270 return; 1271 } Rate1272 nextChar(); 1273 if (!ScannerUtilities.isCSSHexadecimalCharacter((char)current)) { 1274 if (ScannerUtilities.isCSSSpace((char)current)) { Rate1275 nextChar(); 1276 } 1277 return; 1278 } Rate1279 nextChar(); 1280 if (!ScannerUtilities.isCSSHexadecimalCharacter((char)current)) { 1281 if (ScannerUtilities.isCSSSpace((char)current)) { Rate1282 nextChar(); 1283 } 1284 return; 1285 } Rate1286 nextChar(); 1287 if (!ScannerUtilities.isCSSHexadecimalCharacter((char)current)) { 1288 if (ScannerUtilities.isCSSSpace((char)current)) { Rate1289 nextChar(); 1290 } 1291 return; 1292 } Rate1293 nextChar(); 1294 if (!ScannerUtilities.isCSSHexadecimalCharacter((char)current)) { 1295 if (ScannerUtilities.isCSSSpace((char)current)) { Rate1296 nextChar(); 1297 } 1298 return; 1299 } 1300 } 1301 if ((current >= ' ' && current <= '~') || current >= 128) { Rate1302 nextChar(); 1303 return; 1304 } 1305 throw new ParseException("character", 1306 reader.getLine(), 1307 reader.getColumn()); 1308 } 1309 1310 /** 1311 * Compares the given int with the given character, ignoring case. 1312 */ 1313 protected static boolean isEqualIgnoreCase(int i, char c) { 1314 return (i == -1) ? false : Character.toLowerCase((char)i) == c; 1315 } 1316 1317 /** 1318 * Sets the value of the current char to the next character or -1 if the 1319 * end of stream has been reached. 1320 */ 1321 protected int nextChar() throws IOException { 1322 current = reader.read(); 1323 1324 if (current == -1) { 1325 return current; 1326 } 1327 1328 if (position == buffer.length) { 1329 char[] t = new char[position * 3 / 2]; 1330 for (int i = 0; i < position; i++) { 1331 t[i] = buffer[i]; 1332 } 1333 buffer = t; 1334 } 1335 1336 return buffer[position++] = (char)current; 1337 } 1338 }
| Example Line |
Rating (found useful by...) |
|---|---|
| 118 | 0% of 0 |
| 132 | 0% of 0 |
| 145 | 0% of 0 |
| 224 | 0% of 0 |
| 240 | 0% of 0 |
| 305 | 0% of 0 |
| 309 | 0% of 0 |
| 313 | 0% of 0 |
| 317 | 0% of 0 |
| 321 | 0% of 0 |
| 325 | 0% of 0 |
| 329 | 0% of 0 |
| 333 | 0% of 0 |
| 337 | 0% of 0 |
| 341 | 0% of 0 |
| 345 | 0% of 0 |
| 349 | 0% of 0 |
| 353 | 0% of 0 |
| 362 | 0% of 0 |
| 367 | 0% of 0 |
| 373 | 0% of 0 |
| 377 | 0% of 0 |
| 380 | 0% of 0 |
| 388 | 0% of 0 |
| 398 | 0% of 0 |
| 404 | 0% of 0 |
| 406 | 0% of 0 |
| 408 | 0% of 0 |
| 417 | 0% of 0 |
| 422 | 0% of 0 |
| 424 | 0% of 0 |
| 432 | 0% of 0 |
| 434 | 0% of 0 |
| 442 | 0% of 0 |
| 444 | 0% of 0 |
| 452 | 0% of 0 |
| 456 | 0% of 0 |
| 458 | 0% of 0 |
| 471 | 0% of 0 |
| 476 | 0% of 0 |
| 482 | 0% of 0 |
| 490 | 0% of 0 |
| 498 | 0% of 0 |
| 506 | 0% of 0 |
| 511 | 0% of 0 |
| 519 | 0% of 0 |
| 523 | 0% of 0 |
| 531 | 0% of 0 |
| 534 | 0% of 0 |
| 549 | 0% of 0 |
| 551 | 0% of 0 |
| 560 | 0% of 0 |
| 563 | 0% of 0 |
| 572 | 0% of 0 |
| 590 | 0% of 0 |
| 601 | 0% of 0 |
| 606 | 0% of 0 |
| 621 | 0% of 0 |
| 627 | 0% of 0 |
| 634 | 0% of 0 |
| 640 | 0% of 0 |
| 646 | 0% of 0 |
| 652 | 0% of 0 |
| 658 | 0% of 0 |
| 664 | 0% of 0 |
| 670 | 0% of 0 |
| 674 | 0% of 0 |
| 678 | 0% of 0 |
| 690 | 0% of 0 |
| 704 | 0% of 0 |
| 714 | 0% of 0 |
| 728 | 0% of 0 |
| 745 | 0% of 0 |
| 754 | 0% of 0 |
| 768 | 0% of 0 |
| 777 | 0% of 0 |
| 780 | 0% of 0 |
| 791 | 0% of 0 |
| 793 | 0% of 0 |
| 800 | 0% of 0 |
| 807 | 0% of 0 |
| 821 | 0% of 0 |
| 824 | 0% of 0 |
| 834 | 0% of 0 |
| 850 | 0% of 0 |
| 858 | 0% of 0 |
| 861 | 0% of 0 |
| 871 | 0% of 0 |
| 887 | 0% of 0 |
| 896 | 0% of 0 |
| 898 | 0% of 0 |
| 920 | 0% of 0 |
| 936 | 0% of 0 |
| 940 | 0% of 0 |
| 943 | 0% of 0 |
| 947 | 0% of 0 |
| 957 | 0% of 0 |
| 963 | 0% of 0 |
| 966 | 0% of 1 |
| 969 | 0% of 0 |
| 973 | 0% of 0 |
| 984 | 0% of 0 |
| 990 | 0% of 0 |
| 993 | 0% of 0 |
| 997 | 0% of 0 |
| 1006 | 0% of 0 |
| 1010 | 0% of 0 |
| 1020 | 0% of 0 |
| 1026 | 0% of 0 |
| 1029 | 0% of 0 |
| 1032 | 0% of 0 |
| 1035 | 0% of 0 |
| 1040 | 0% of 0 |
| 1052 | 0% of 0 |
| 1058 | 0% of 0 |
| 1062 | 0% of 0 |
| 1066 | 0% of 0 |
| 1076 | 0% of 0 |
| 1082 | 0% of 0 |
| 1085 | 0% of 0 |
| 1089 | 0% of 0 |
| 1099 | 0% of 0 |
| 1105 | 0% of 0 |
| 1108 | 0% of 0 |
| 1111 | 0% of 0 |
| 1115 | 0% of 0 |
| 1126 | 0% of 0 |
| 1132 | 0% of 0 |
| 1135 | 0% of 0 |
| 1139 | 0% of 0 |
| 1148 | 0% of 0 |
| 1152 | 0% of 0 |
| 1162 | 0% of 0 |
| 1168 | 0% of 0 |
| 1171 | 0% of 0 |
| 1175 | 0% of 0 |
| 1184 | 0% of 0 |
| 1188 | 0% of 0 |
| 1197 | 0% of 0 |
| 1201 | 0% of 0 |
| 1211 | 0% of 0 |
| 1217 | 0% of 0 |
| 1220 | 0% of 0 |
| 1223 | 0% of 0 |
| 1227 | 0% of 0 |
| 1238 | 0% of 0 |
| 1244 | 0% of 0 |
| 1251 | 0% of 0 |
| 1265 | 0% of 0 |
| 1268 | 0% of 0 |
| 1272 | 0% of 0 |
| 1275 | 0% of 0 |
| 1279 | 0% of 0 |
| 1282 | 0% of 0 |
| 1286 | 0% of 0 |
| 1289 | 0% of 0 |
| 1293 | 0% of 0 |
| 1296 | 0% of 0 |
| 1302 | 0% of 0 |