1 25 26 package org.apache.jasper.xmlparser; 27 28 import java.io.EOFException ; 29 import java.io.InputStream ; 30 import java.io.InputStreamReader ; 31 import java.io.IOException ; 32 import java.io.Reader ; 33 import java.util.Locale ; 34 import java.util.jar.JarFile ; 35 36 import org.apache.jasper.JasperException; 37 import org.apache.jasper.JspCompilationContext; 38 import org.apache.jasper.compiler.ErrorDispatcher; 39 import org.apache.jasper.compiler.JspUtil; 40 41 public class XMLEncodingDetector { 42 43 private InputStream stream; 44 private String encoding; 45 private boolean isEncodingSetInProlog; 46 private boolean isBomPresent; 47 private Boolean isBigEndian; 48 private Reader reader; 49 50 public static final int DEFAULT_BUFFER_SIZE = 2048; 52 public static final int DEFAULT_XMLDECL_BUFFER_SIZE = 64; 53 private boolean fAllowJavaEncodings; 54 private SymbolTable fSymbolTable; 55 private XMLEncodingDetector fCurrentEntity; 56 private int fBufferSize = DEFAULT_BUFFER_SIZE; 57 58 private int lineNumber = 1; 60 private int columnNumber = 1; 61 private boolean literal; 62 private char[] ch = new char[DEFAULT_BUFFER_SIZE]; 63 private int position; 64 private int count; 65 private boolean mayReadChunks = false; 66 67 private XMLString fString = new XMLString(); 69 private XMLStringBuffer fStringBuffer = new XMLStringBuffer(); 70 private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer(); 71 private final static String fVersionSymbol = "version"; 72 private final static String fEncodingSymbol = "encoding"; 73 private final static String fStandaloneSymbol = "standalone"; 74 75 private int fMarkupDepth = 0; 77 private String [] fStrings = new String [3]; 78 79 private ErrorDispatcher err; 80 81 84 public XMLEncodingDetector() { 85 fSymbolTable = new SymbolTable(); 86 fCurrentEntity = this; 87 } 88 89 102 public static Object [] getEncoding(String fname, JarFile jarFile, 103 JspCompilationContext ctxt, 104 ErrorDispatcher err) 105 throws IOException , JasperException 106 { 107 InputStream inStream = JspUtil.getInputStream(fname, jarFile, ctxt, 108 err); 109 XMLEncodingDetector detector = new XMLEncodingDetector(); 110 Object [] ret = detector.getEncoding(inStream, err); 111 inStream.close(); 112 113 return ret; 114 } 115 116 private Object [] getEncoding(InputStream in, ErrorDispatcher err) 117 throws IOException , JasperException 118 { 119 this.stream = in; 120 this.err=err; 121 createInitialReader(); 122 scanXMLDecl(); 123 124 return new Object [] { this.encoding, 125 new Boolean (this.isEncodingSetInProlog), 126 new Boolean (this.isBomPresent) }; 127 } 128 129 void endEntity() { 131 } 132 133 private void createInitialReader() throws IOException , JasperException { 136 137 stream = new RewindableInputStream(stream); 139 140 if (encoding == null) { 142 final byte[] b4 = new byte[4]; 144 int count = 0; 145 for (; count<4; count++ ) { 146 b4[count] = (byte)stream.read(); 147 } 148 if (count == 4) { 149 Object [] encodingDesc = getEncodingName(b4, count); 150 encoding = (String )(encodingDesc[0]); 151 isBigEndian = (Boolean )(encodingDesc[1]); 152 if (encodingDesc.length > 2) { 153 isBomPresent = (Boolean )(encodingDesc[2]); 154 } else { 155 isBomPresent = true; 156 } 157 158 stream.reset(); 159 if (count > 2 && encoding.equals("UTF-8")) { 163 int b0 = b4[0] & 0xFF; 164 int b1 = b4[1] & 0xFF; 165 int b2 = b4[2] & 0xFF; 166 if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { 167 stream.skip(3); 169 } 170 } 171 reader = createReader(stream, encoding, isBigEndian); 172 } else { 173 reader = createReader(stream, encoding, isBigEndian); 174 } 175 } 176 } 177 178 196 private Reader createReader(InputStream inputStream, String encoding, 197 Boolean isBigEndian) 198 throws IOException , JasperException { 199 200 if (encoding == null) { 202 encoding = "UTF-8"; 203 } 204 205 String ENCODING = encoding.toUpperCase(Locale.ENGLISH); 207 if (ENCODING.equals("UTF-8")) { 208 return new UTF8Reader(inputStream, fBufferSize); 209 } 210 if (ENCODING.equals("US-ASCII")) { 211 return new ASCIIReader(inputStream, fBufferSize); 212 } 213 if (ENCODING.equals("ISO-10646-UCS-4")) { 214 if (isBigEndian != null) { 215 boolean isBE = isBigEndian.booleanValue(); 216 if (isBE) { 217 return new UCSReader(inputStream, UCSReader.UCS4BE); 218 } else { 219 return new UCSReader(inputStream, UCSReader.UCS4LE); 220 } 221 } else { 222 err.jspError("jsp.error.xml.encodingByteOrderUnsupported", 223 encoding); 224 } 225 } 226 if (ENCODING.equals("ISO-10646-UCS-2")) { 227 if (isBigEndian != null) { boolean isBE = isBigEndian.booleanValue(); 229 if (isBE) { 230 return new UCSReader(inputStream, UCSReader.UCS2BE); 231 } else { 232 return new UCSReader(inputStream, UCSReader.UCS2LE); 233 } 234 } else { 235 err.jspError("jsp.error.xml.encodingByteOrderUnsupported", 236 encoding); 237 } 238 } 239 240 boolean validIANA = XMLChar.isValidIANAEncoding(encoding); 242 boolean validJava = XMLChar.isValidJavaEncoding(encoding); 243 if (!validIANA || (fAllowJavaEncodings && !validJava)) { 244 err.jspError("jsp.error.xml.encodingDeclInvalid", encoding); 245 encoding = "ISO-8859-1"; 254 } 255 256 String javaEncoding = EncodingMap.getIANA2JavaMapping(ENCODING); 258 if (javaEncoding == null) { 259 if (fAllowJavaEncodings) { 260 javaEncoding = encoding; 261 } else { 262 err.jspError("jsp.error.xml.encodingDeclInvalid", encoding); 263 javaEncoding = "ISO8859_1"; 265 } 266 } 267 return new InputStreamReader (inputStream, javaEncoding); 268 269 } 271 285 private Object [] getEncodingName(byte[] b4, int count) { 286 287 if (count < 2) { 288 return new Object []{"UTF-8", null, Boolean.FALSE}; 289 } 290 291 int b0 = b4[0] & 0xFF; 293 int b1 = b4[1] & 0xFF; 294 if (b0 == 0xFE && b1 == 0xFF) { 295 return new Object [] {"UTF-16BE", Boolean.TRUE}; 297 } 298 if (b0 == 0xFF && b1 == 0xFE) { 299 return new Object [] {"UTF-16LE", Boolean.FALSE}; 301 } 302 303 if (count < 3) { 306 return new Object [] {"UTF-8", null, Boolean.FALSE}; 307 } 308 309 int b2 = b4[2] & 0xFF; 311 if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { 312 return new Object [] {"UTF-8", null}; 313 } 314 315 if (count < 4) { 318 return new Object [] {"UTF-8", null}; 319 } 320 321 int b3 = b4[3] & 0xFF; 323 if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) { 324 return new Object [] {"ISO-10646-UCS-4", new Boolean (true)}; 326 } 327 if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) { 328 return new Object [] {"ISO-10646-UCS-4", new Boolean (false)}; 330 } 331 if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) { 332 return new Object [] {"ISO-10646-UCS-4", null}; 335 } 336 if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) { 337 return new Object [] {"ISO-10646-UCS-4", null}; 340 } 341 if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { 342 return new Object [] {"UTF-16BE", new Boolean (true)}; 346 } 347 if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { 348 return new Object [] {"UTF-16LE", new Boolean (false)}; 351 } 352 if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) { 353 return new Object [] {"CP037", null}; 356 } 357 358 return new Object [] {"UTF-8", null, Boolean.FALSE}; 360 361 } 362 363 366 public boolean isExternal() { 367 return true; 368 } 369 370 380 public int peekChar() throws IOException { 381 382 if (fCurrentEntity.position == fCurrentEntity.count) { 384 load(0, true); 385 } 386 387 int c = fCurrentEntity.ch[fCurrentEntity.position]; 389 390 if (fCurrentEntity.isExternal()) { 392 return c != '\r' ? c : '\n'; 393 } 394 else { 395 return c; 396 } 397 398 } 400 410 public int scanChar() throws IOException { 411 412 if (fCurrentEntity.position == fCurrentEntity.count) { 414 load(0, true); 415 } 416 417 int c = fCurrentEntity.ch[fCurrentEntity.position++]; 419 boolean external = false; 420 if (c == '\n' || 421 (c == '\r' && (external = fCurrentEntity.isExternal()))) { 422 fCurrentEntity.lineNumber++; 423 fCurrentEntity.columnNumber = 1; 424 if (fCurrentEntity.position == fCurrentEntity.count) { 425 fCurrentEntity.ch[0] = (char)c; 426 load(1, false); 427 } 428 if (c == '\r' && external) { 429 if (fCurrentEntity.ch[fCurrentEntity.position++] != '\n') { 430 fCurrentEntity.position--; 431 } 432 c = '\n'; 433 } 434 } 435 436 fCurrentEntity.columnNumber++; 438 return c; 439 440 } 441 442 460 public String scanName() throws IOException { 461 462 if (fCurrentEntity.position == fCurrentEntity.count) { 464 load(0, true); 465 } 466 467 int offset = fCurrentEntity.position; 469 if (XMLChar.isNameStart(fCurrentEntity.ch[offset])) { 470 if (++fCurrentEntity.position == fCurrentEntity.count) { 471 fCurrentEntity.ch[0] = fCurrentEntity.ch[offset]; 472 offset = 0; 473 if (load(1, false)) { 474 fCurrentEntity.columnNumber++; 475 String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 476 0, 1); 477 return symbol; 478 } 479 } 480 while (XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) { 481 if (++fCurrentEntity.position == fCurrentEntity.count) { 482 int length = fCurrentEntity.position - offset; 483 if (length == fBufferSize) { 484 char[] tmp = new char[fBufferSize * 2]; 486 System.arraycopy(fCurrentEntity.ch, offset, 487 tmp, 0, length); 488 fCurrentEntity.ch = tmp; 489 fBufferSize *= 2; 490 } else { 491 System.arraycopy(fCurrentEntity.ch, offset, 492 fCurrentEntity.ch, 0, length); 493 } 494 offset = 0; 495 if (load(length, false)) { 496 break; 497 } 498 } 499 } 500 } 501 int length = fCurrentEntity.position - offset; 502 fCurrentEntity.columnNumber += length; 503 504 String symbol = null; 506 if (length > 0) { 507 symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length); 508 } 509 return symbol; 510 511 } 512 513 543 public int scanLiteral(int quote, XMLString content) 544 throws IOException { 545 546 if (fCurrentEntity.position == fCurrentEntity.count) { 548 load(0, true); 549 } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { 550 fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; 551 load(1, false); 552 fCurrentEntity.position = 0; 553 } 554 555 int offset = fCurrentEntity.position; 557 int c = fCurrentEntity.ch[offset]; 558 int newlines = 0; 559 boolean external = fCurrentEntity.isExternal(); 560 if (c == '\n' || (c == '\r' && external)) { 561 do { 562 c = fCurrentEntity.ch[fCurrentEntity.position++]; 563 if (c == '\r' && external) { 564 newlines++; 565 fCurrentEntity.lineNumber++; 566 fCurrentEntity.columnNumber = 1; 567 if (fCurrentEntity.position == fCurrentEntity.count) { 568 offset = 0; 569 fCurrentEntity.position = newlines; 570 if (load(newlines, false)) { 571 break; 572 } 573 } 574 if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { 575 fCurrentEntity.position++; 576 offset++; 577 } 578 579 else { 580 newlines++; 581 } 582 583 } 584 else if (c == '\n') { 585 newlines++; 586 fCurrentEntity.lineNumber++; 587 fCurrentEntity.columnNumber = 1; 588 if (fCurrentEntity.position == fCurrentEntity.count) { 589 offset = 0; 590 fCurrentEntity.position = newlines; 591 if (load(newlines, false)) { 592 break; 593 } 594 } 595 602 } 603 else { 604 fCurrentEntity.position--; 605 break; 606 } 607 } while (fCurrentEntity.position < fCurrentEntity.count - 1); 608 for (int i = offset; i < fCurrentEntity.position; i++) { 609 fCurrentEntity.ch[i] = '\n'; 610 } 611 int length = fCurrentEntity.position - offset; 612 if (fCurrentEntity.position == fCurrentEntity.count - 1) { 613 content.setValues(fCurrentEntity.ch, offset, length); 614 return -1; 615 } 616 } 617 618 while (fCurrentEntity.position < fCurrentEntity.count) { 620 c = fCurrentEntity.ch[fCurrentEntity.position++]; 621 if ((c == quote && 622 (!fCurrentEntity.literal || external)) 623 || c == '%' || !XMLChar.isContent(c)) { 624 fCurrentEntity.position--; 625 break; 626 } 627 } 628 int length = fCurrentEntity.position - offset; 629 fCurrentEntity.columnNumber += length - newlines; 630 content.setValues(fCurrentEntity.ch, offset, length); 631 632 if (fCurrentEntity.position != fCurrentEntity.count) { 634 c = fCurrentEntity.ch[fCurrentEntity.position]; 635 if (c == quote && fCurrentEntity.literal) { 639 c = -1; 640 } 641 } 642 else { 643 c = -1; 644 } 645 return c; 646 647 } 648 649 679 public boolean scanData(String delimiter, XMLStringBuffer buffer) 680 throws IOException { 681 682 boolean done = false; 683 int delimLen = delimiter.length(); 684 char charAt0 = delimiter.charAt(0); 685 boolean external = fCurrentEntity.isExternal(); 686 do { 687 688 690 if (fCurrentEntity.position == fCurrentEntity.count) { 691 load(0, true); 692 } 693 else if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) { 694 System.arraycopy(fCurrentEntity.ch, fCurrentEntity.position, 695 fCurrentEntity.ch, 0, fCurrentEntity.count - fCurrentEntity.position); 696 load(fCurrentEntity.count - fCurrentEntity.position, false); 697 fCurrentEntity.position = 0; 698 } 699 if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) { 700 int length = fCurrentEntity.count - fCurrentEntity.position; 703 buffer.append (fCurrentEntity.ch, fCurrentEntity.position, 704 length); 705 fCurrentEntity.columnNumber += fCurrentEntity.count; 706 fCurrentEntity.position = fCurrentEntity.count; 707 load(0,true); 708 return false; 709 } 710 711 int offset = fCurrentEntity.position; 713 int c = fCurrentEntity.ch[offset]; 714 int newlines = 0; 715 if (c == '\n' || (c == '\r' && external)) { 716 do { 717 c = fCurrentEntity.ch[fCurrentEntity.position++]; 718 if (c == '\r' && external) { 719 newlines++; 720 fCurrentEntity.lineNumber++; 721 fCurrentEntity.columnNumber = 1; 722 if (fCurrentEntity.position == fCurrentEntity.count) { 723 offset = 0; 724 fCurrentEntity.position = newlines; 725 if (load(newlines, false)) { 726 break; 727 } 728 } 729 if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { 730 fCurrentEntity.position++; 731 offset++; 732 } 733 734 else { 735 newlines++; 736 } 737 } 738 else if (c == '\n') { 739 newlines++; 740 fCurrentEntity.lineNumber++; 741 fCurrentEntity.columnNumber = 1; 742 if (fCurrentEntity.position == fCurrentEntity.count) { 743 offset = 0; 744 fCurrentEntity.position = newlines; 745 fCurrentEntity.count = newlines; 746 if (load(newlines, false)) { 747 break; 748 } 749 } 750 } 751 else { 752 fCurrentEntity.position--; 753 break; 754 } 755 } while (fCurrentEntity.position < fCurrentEntity.count - 1); 756 for (int i = offset; i < fCurrentEntity.position; i++) { 757 fCurrentEntity.ch[i] = '\n'; 758 } 759 int length = fCurrentEntity.position - offset; 760 if (fCurrentEntity.position == fCurrentEntity.count - 1) { 761 buffer.append(fCurrentEntity.ch, offset, length); 762 return true; 763 } 764 } 765 766 OUTER: while (fCurrentEntity.position < fCurrentEntity.count) { 768 c = fCurrentEntity.ch[fCurrentEntity.position++]; 769 if (c == charAt0) { 770 int delimOffset = fCurrentEntity.position - 1; 772 for (int i = 1; i < delimLen; i++) { 773 if (fCurrentEntity.position == fCurrentEntity.count) { 774 fCurrentEntity.position -= i; 775 break OUTER; 776 } 777 c = fCurrentEntity.ch[fCurrentEntity.position++]; 778 if (delimiter.charAt(i) != c) { 779 fCurrentEntity.position--; 780 break; 781 } 782 } 783 if (fCurrentEntity.position == delimOffset + delimLen) { 784 done = true; 785 break; 786 } 787 } 788 else if (c == '\n' || (external && c == '\r')) { 789 fCurrentEntity.position--; 790 break; 791 } 792 else if (XMLChar.isInvalid(c)) { 793 fCurrentEntity.position--; 794 int length = fCurrentEntity.position - offset; 795 fCurrentEntity.columnNumber += length - newlines; 796 buffer.append(fCurrentEntity.ch, offset, length); 797 return true; 798 } 799 } 800 int length = fCurrentEntity.position - offset; 801 fCurrentEntity.columnNumber += length - newlines; 802 if (done) { 803 length -= delimLen; 804 } 805 buffer.append (fCurrentEntity.ch, offset, length); 806 807 } while (!done); 809 return !done; 810 811 } 812 813 828 public boolean skipChar(int c) throws IOException { 829 830 if (fCurrentEntity.position == fCurrentEntity.count) { 832 load(0, true); 833 } 834 835 int cc = fCurrentEntity.ch[fCurrentEntity.position]; 837 if (cc == c) { 838 fCurrentEntity.position++; 839 if (c == '\n') { 840 fCurrentEntity.lineNumber++; 841 fCurrentEntity.columnNumber = 1; 842 } 843 else { 844 fCurrentEntity.columnNumber++; 845 } 846 return true; 847 } else if (c == '\n' && cc == '\r' && fCurrentEntity.isExternal()) { 848 if (fCurrentEntity.position == fCurrentEntity.count) { 850 fCurrentEntity.ch[0] = (char)cc; 851 load(1, false); 852 } 853 fCurrentEntity.position++; 854 if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { 855 fCurrentEntity.position++; 856 } 857 fCurrentEntity.lineNumber++; 858 fCurrentEntity.columnNumber = 1; 859 return true; 860 } 861 862 return false; 864 865 } 866 867 882 public boolean skipSpaces() throws IOException { 883 884 if (fCurrentEntity.position == fCurrentEntity.count) { 886 load(0, true); 887 } 888 889 int c = fCurrentEntity.ch[fCurrentEntity.position]; 891 if (XMLChar.isSpace(c)) { 892 boolean external = fCurrentEntity.isExternal(); 893 do { 894 boolean entityChanged = false; 895 if (c == '\n' || (external && c == '\r')) { 897 fCurrentEntity.lineNumber++; 898 fCurrentEntity.columnNumber = 1; 899 if (fCurrentEntity.position == fCurrentEntity.count - 1) { 900 fCurrentEntity.ch[0] = (char)c; 901 entityChanged = load(1, true); 902 if (!entityChanged) 903 fCurrentEntity.position = 0; 906 } 907 if (c == '\r' && external) { 908 if (fCurrentEntity.ch[++fCurrentEntity.position] != '\n') { 911 fCurrentEntity.position--; 912 } 913 } 914 922 } 923 else { 924 fCurrentEntity.columnNumber++; 925 } 926 if (!entityChanged) 928 fCurrentEntity.position++; 929 if (fCurrentEntity.position == fCurrentEntity.count) { 930 load(0, true); 931 } 932 } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position])); 933 return true; 934 } 935 936 return false; 938 939 } 940 941 954 public boolean skipString(String s) throws IOException { 955 956 if (fCurrentEntity.position == fCurrentEntity.count) { 958 load(0, true); 959 } 960 961 final int length = s.length(); 963 for (int i = 0; i < length; i++) { 964 char c = fCurrentEntity.ch[fCurrentEntity.position++]; 965 if (c != s.charAt(i)) { 966 fCurrentEntity.position -= i + 1; 967 return false; 968 } 969 if (i < length - 1 && fCurrentEntity.position == fCurrentEntity.count) { 970 System.arraycopy(fCurrentEntity.ch, fCurrentEntity.count - i - 1, fCurrentEntity.ch, 0, i + 1); 971 if (load(i + 1, false)) { 974 fCurrentEntity.position -= i + 1; 975 return false; 976 } 977 } 978 } 979 fCurrentEntity.columnNumber += length; 980 return true; 981 982 } 983 984 1000 final boolean load(int offset, boolean changeEntity) 1001 throws IOException { 1002 1003 int length = fCurrentEntity.mayReadChunks? 1005 (fCurrentEntity.ch.length - offset): 1006 (DEFAULT_XMLDECL_BUFFER_SIZE); 1007 int count = fCurrentEntity.reader.read(fCurrentEntity.ch, offset, 1008 length); 1009 1010 boolean entityChanged = false; 1012 if (count != -1) { 1013 if (count != 0) { 1014 fCurrentEntity.count = count + offset; 1015 fCurrentEntity.position = offset; 1016 } 1017 } 1018 1019 else { 1021 fCurrentEntity.count = offset; 1022 fCurrentEntity.position = offset; 1023 entityChanged = true; 1024 if (changeEntity) { 1025 endEntity(); 1026 if (fCurrentEntity == null) { 1027 throw new EOFException (); 1028 } 1029 if (fCurrentEntity.position == fCurrentEntity.count) { 1031 load(0, false); 1032 } 1033 } 1034 } 1035 1036 return entityChanged; 1037 1038 } 1039 1040 1062 private final class RewindableInputStream extends InputStream { 1063 1064 private InputStream fInputStream; 1065 private byte[] fData; 1066 private int fStartOffset; 1067 private int fEndOffset; 1068 private int fOffset; 1069 private int fLength; 1070 private int fMark; 1071 1072 public RewindableInputStream(InputStream is) { 1073 fData = new byte[DEFAULT_XMLDECL_BUFFER_SIZE]; 1074 fInputStream = is; 1075 fStartOffset = 0; 1076 fEndOffset = -1; 1077 fOffset = 0; 1078 fLength = 0; 1079 fMark = 0; 1080 } 1081 1082 public void setStartOffset(int offset) { 1083 fStartOffset = offset; 1084 } 1085 1086 public void rewind() { 1087 fOffset = fStartOffset; 1088 } 1089 1090 public int read() throws IOException { 1091 int b = 0; 1092 if (fOffset < fLength) { 1093 return fData[fOffset++] & 0xff; 1094 } 1095 if (fOffset == fEndOffset) { 1096 return -1; 1097 } 1098 if (fOffset == fData.length) { 1099 byte[] newData = new byte[fOffset << 1]; 1100 System.arraycopy(fData, 0, newData, 0, fOffset); 1101 fData = newData; 1102 } 1103 b = fInputStream.read(); 1104 if (b == -1) { 1105 fEndOffset = fOffset; 1106 return -1; 1107 } 1108 fData[fLength++] = (byte)b; 1109 fOffset++; 1110 return b & 0xff; 1111 } 1112 1113 public int read(byte[] b, int off, int len) throws IOException { 1114 int bytesLeft = fLength - fOffset; 1115 if (bytesLeft == 0) { 1116 if (fOffset == fEndOffset) { 1117 return -1; 1118 } 1119 if (fCurrentEntity.mayReadChunks) { 1121 return fInputStream.read(b, off, len); 1122 } 1123 int returnedVal = read(); 1124 if (returnedVal == -1) { 1125 fEndOffset = fOffset; 1126 return -1; 1127 } 1128 b[off] = (byte)returnedVal; 1129 return 1; 1130 } 1131 if (len < bytesLeft) { 1132 if (len <= 0) { 1133 return 0; 1134 } 1135 } 1136 else { 1137 len = bytesLeft; 1138 } 1139 if (b != null) { 1140 System.arraycopy(fData, fOffset, b, off, len); 1141 } 1142 fOffset += len; 1143 return len; 1144 } 1145 1146 public long skip(long n) 1147 throws IOException 1148 { 1149 int bytesLeft; 1150 if (n <= 0) { 1151 return 0; 1152 } 1153 bytesLeft = fLength - fOffset; 1154 if (bytesLeft == 0) { 1155 if (fOffset == fEndOffset) { 1156 return 0; 1157 } 1158 return fInputStream.skip(n); 1159 } 1160 if (n <= bytesLeft) { 1161 fOffset += n; 1162 return n; 1163 } 1164 fOffset += bytesLeft; 1165 if (fOffset == fEndOffset) { 1166 return bytesLeft; 1167 } 1168 n -= bytesLeft; 1169 1177 return fInputStream.skip(n) + bytesLeft; 1178 } 1179 1180 public int available() throws IOException { 1181 int bytesLeft = fLength - fOffset; 1182 if (bytesLeft == 0) { 1183 if (fOffset == fEndOffset) { 1184 return -1; 1185 } 1186 return fCurrentEntity.mayReadChunks ? fInputStream.available() 1187 : 0; 1188 } 1189 return bytesLeft; 1190 } 1191 1192 public void mark(int howMuch) { 1193 fMark = fOffset; 1194 } 1195 1196 public void reset() { 1197 fOffset = fMark; 1198 } 1199 1200 public boolean markSupported() { 1201 return true; 1202 } 1203 1204 public void close() throws IOException { 1205 if (fInputStream != null) { 1206 fInputStream.close(); 1207 fInputStream = null; 1208 } 1209 } 1210 } 1212 private void scanXMLDecl() throws IOException , JasperException { 1215 1216 if (skipString("<?xml")) { 1217 fMarkupDepth++; 1218 if (XMLChar.isName(peekChar())) { 1221 fStringBuffer.clear(); 1222 fStringBuffer.append("xml"); 1223 while (XMLChar.isName(peekChar())) { 1224 fStringBuffer.append((char)scanChar()); 1225 } 1226 String target = fSymbolTable.addSymbol(fStringBuffer.ch, 1227 fStringBuffer.offset, 1228 fStringBuffer.length); 1229 scanPIData(target, fString); 1230 } 1231 1232 else { 1234 scanXMLDeclOrTextDecl(false); 1235 } 1236 } 1237 } 1238 1239 1259 private void scanXMLDeclOrTextDecl(boolean scanningTextDecl) 1260 throws IOException , JasperException { 1261 1262 scanXMLDeclOrTextDecl(scanningTextDecl, fStrings); 1264 fMarkupDepth--; 1265 1266 String encodingPseudoAttr = fStrings[1]; 1268 1269 if (encodingPseudoAttr != null) { 1271 isEncodingSetInProlog = true; 1272 encoding = encodingPseudoAttr; 1273 } 1274 } 1275 1276 1302 private void scanXMLDeclOrTextDecl(boolean scanningTextDecl, 1303 String [] pseudoAttributeValues) 1304 throws IOException , JasperException { 1305 1306 String version = null; 1308 String encoding = null; 1309 String standalone = null; 1310 1311 final int STATE_VERSION = 0; 1313 final int STATE_ENCODING = 1; 1314 final int STATE_STANDALONE = 2; 1315 final int STATE_DONE = 3; 1316 int state = STATE_VERSION; 1317 1318 boolean dataFoundForTarget = false; 1319 boolean sawSpace = skipSpaces(); 1320 while (peekChar() != '?') { 1321 dataFoundForTarget = true; 1322 String name = scanPseudoAttribute(scanningTextDecl, fString); 1323 switch (state) { 1324 case STATE_VERSION: { 1325 if (name == fVersionSymbol) { 1326 if (!sawSpace) { 1327 reportFatalError(scanningTextDecl 1328 ? "jsp.error.xml.spaceRequiredBeforeVersionInTextDecl" 1329 : "jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl", 1330 null); 1331 } 1332 version = fString.toString(); 1333 state = STATE_ENCODING; 1334 if (!version.equals("1.0")) { 1335 err.jspError("jsp.error.xml.versionNotSupported", 1339 version); 1340 } 1341 } else if (name == fEncodingSymbol) { 1342 if (!scanningTextDecl) { 1343 err.jspError("jsp.error.xml.versionInfoRequired"); 1344 } 1345 if (!sawSpace) { 1346 reportFatalError(scanningTextDecl 1347 ? "jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl" 1348 : "jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl", 1349 null); 1350 } 1351 encoding = fString.toString(); 1352 state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE; 1353 } else { 1354 if (scanningTextDecl) { 1355 err.jspError("jsp.error.xml.encodingDeclRequired"); 1356 } 1357 else { 1358 err.jspError("jsp.error.xml.versionInfoRequired"); 1359 } 1360 } 1361 break; 1362 } 1363 case STATE_ENCODING: { 1364 if (name == fEncodingSymbol) { 1365 if (!sawSpace) { 1366 reportFatalError(scanningTextDecl 1367 ? "jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl" 1368 : "jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl", 1369 null); 1370 } 1371 encoding = fString.toString(); 1372 state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE; 1373 } else if (!scanningTextDecl && name == fStandaloneSymbol) { 1376 if (!sawSpace) { 1377 err.jspError("jsp.error.xml.spaceRequiredBeforeStandalone"); 1378 } 1379 standalone = fString.toString(); 1380 state = STATE_DONE; 1381 if (!standalone.equals("yes") && !standalone.equals("no")) { 1382 err.jspError("jsp.error.xml.sdDeclInvalid"); 1383 } 1384 } else { 1385 err.jspError("jsp.error.xml.encodingDeclRequired"); 1386 } 1387 break; 1388 } 1389 case STATE_STANDALONE: { 1390 if (name == fStandaloneSymbol) { 1391 if (!sawSpace) { 1392 err.jspError("jsp.error.xml.spaceRequiredBeforeStandalone"); 1393 } 1394 standalone = fString.toString(); 1395 state = STATE_DONE; 1396 if (!standalone.equals("yes") && !standalone.equals("no")) { 1397 err.jspError("jsp.error.xml.sdDeclInvalid"); 1398 } 1399 } else { 1400 err.jspError("jsp.error.xml.encodingDeclRequired"); 1401 } 1402 break; 1403 } 1404 default: { 1405 err.jspError("jsp.error.xml.noMorePseudoAttributes"); 1406 } 1407 } 1408 sawSpace = skipSpaces(); 1409 } 1410 if (scanningTextDecl && state != STATE_DONE) { 1412 err.jspError("jsp.error.xml.morePseudoAttributes"); 1413 } 1414 1415 if (scanningTextDecl) { 1418 if (!dataFoundForTarget && encoding == null) { 1419 err.jspError("jsp.error.xml.encodingDeclRequired"); 1420 } 1421 } else { 1422 if (!dataFoundForTarget && version == null) { 1423 err.jspError("jsp.error.xml.versionInfoRequired"); 1424 } 1425 } 1426 1427 if (!skipChar('?')) { 1429 err.jspError("jsp.error.xml.xmlDeclUnterminated"); 1430 } 1431 if (!skipChar('>')) { 1432 err.jspError("jsp.error.xml.xmlDeclUnterminated"); 1433 1434 } 1435 1436 pseudoAttributeValues[0] = version; 1438 pseudoAttributeValues[1] = encoding; 1439 pseudoAttributeValues[2] = standalone; 1440 } 1441 1442 1459 public String scanPseudoAttribute(boolean scanningTextDecl, 1460 XMLString value) 1461 throws IOException , JasperException { 1462 1463 String name = scanName(); 1464 if (name == null) { 1465 err.jspError("jsp.error.xml.pseudoAttrNameExpected"); 1466 } 1467 skipSpaces(); 1468 if (!skipChar('=')) { 1469 reportFatalError(scanningTextDecl ? 1470 "jsp.error.xml.eqRequiredInTextDecl" 1471 : "jsp.error.xml.eqRequiredInXMLDecl", 1472 name); 1473 } 1474 skipSpaces(); 1475 int quote = peekChar(); 1476 if (quote != '\'' && quote != '"') { 1477 reportFatalError(scanningTextDecl ? 1478 "jsp.error.xml.quoteRequiredInTextDecl" 1479 : "jsp.error.xml.quoteRequiredInXMLDecl" , 1480 name); 1481 } 1482 scanChar(); 1483 int c = scanLiteral(quote, value); 1484 if (c != quote) { 1485 fStringBuffer2.clear(); 1486 do { 1487 fStringBuffer2.append(value); 1488 if (c != -1) { 1489 if (c == '&' || c == '%' || c == '<' || c == ']') { 1490 fStringBuffer2.append((char)scanChar()); 1491 } 1492 else if (XMLChar.isHighSurrogate(c)) { 1493 scanSurrogates(fStringBuffer2); 1494 } 1495 else if (XMLChar.isInvalid(c)) { 1496 String key = scanningTextDecl 1497 ? "jsp.error.xml.invalidCharInTextDecl" 1498 : "jsp.error.xml.invalidCharInXMLDecl"; 1499 reportFatalError(key, Integer.toString(c, 16)); 1500 scanChar(); 1501 } 1502 } 1503 c = scanLiteral(quote, value); 1504 } while (c != quote); 1505 fStringBuffer2.append(value); 1506 value.setValues(fStringBuffer2); 1507 } 1508 if (!skipChar(quote)) { 1509 reportFatalError(scanningTextDecl ? 1510 "jsp.error.xml.closeQuoteMissingInTextDecl" 1511 : "jsp.error.xml.closeQuoteMissingInXMLDecl", 1512 name); 1513 } 1514 1515 return name; 1517 1518 } 1519 1520 1533 private void scanPIData(String target, XMLString data) 1534 throws IOException , JasperException { 1535 1536 if (target.length() == 3) { 1538 char c0 = Character.toLowerCase(target.charAt(0)); 1539 char c1 = Character.toLowerCase(target.charAt(1)); 1540 char c2 = Character.toLowerCase(target.charAt(2)); 1541 if (c0 == 'x' && c1 == 'm' && c2 == 'l') { 1542 err.jspError("jsp.error.xml.reservedPITarget"); 1543 } 1544 } 1545 1546 if (!skipSpaces()) { 1548 if (skipString("?>")) { 1549 data.clear(); 1551 return; 1552 } 1553 else { 1554 err.jspError("jsp.error.xml.spaceRequiredInPI"); 1556 } 1557 } 1558 1559 fStringBuffer.clear(); 1560 if (scanData("?>", fStringBuffer)) { 1562 do { 1563 int c = peekChar(); 1564 if (c != -1) { 1565 if (XMLChar.isHighSurrogate(c)) { 1566 scanSurrogates(fStringBuffer); 1567 } else if (XMLChar.isInvalid(c)) { 1568 err.jspError("jsp.error.xml.invalidCharInPI", 1569 Integer.toHexString(c)); 1570 scanChar(); 1571 } 1572 } 1573 } while (scanData("?>", fStringBuffer)); 1574 } 1575 data.setValues(fStringBuffer); 1576 1577 } 1578 1579 1590 private boolean scanSurrogates(XMLStringBuffer buf) 1591 throws IOException , JasperException { 1592 1593 int high = scanChar(); 1594 int low = peekChar(); 1595 if (!XMLChar.isLowSurrogate(low)) { 1596 err.jspError("jsp.error.xml.invalidCharInContent", 1597 Integer.toString(high, 16)); 1598 return false; 1599 } 1600 scanChar(); 1601 1602 int c = XMLChar.supplemental((char)high, (char)low); 1604 1605 if (!XMLChar.isValid(c)) { 1607 err.jspError("jsp.error.xml.invalidCharInContent", 1608 Integer.toString(c, 16)); 1609 return false; 1610 } 1611 1612 buf.append((char)high); 1614 buf.append((char)low); 1615 1616 return true; 1617 1618 } 1619 1620 1625 private void reportFatalError(String msgId, String arg) 1626 throws JasperException { 1627 err.jspError(msgId, arg); 1628 } 1629 1630} 1631 1632 1633 | Popular Tags |