jspparser.java
来自「RESIN 3.2 最新源码」· Java 代码 · 共 2,239 行 · 第 1/4 页
JAVA
2,239 行
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */package com.caucho.jsp;import com.caucho.java.LineMap;import com.caucho.jsp.java.JspNode;import com.caucho.log.Log;import com.caucho.util.CharBuffer;import com.caucho.util.L10N;import com.caucho.util.LineCompileException;import com.caucho.vfs.Path;import com.caucho.vfs.ReadStream;import com.caucho.xml.QName;import com.caucho.xml.XmlChar;import java.io.IOException;import java.util.ArrayList;import java.util.HashSet;import java.util.logging.Level;import java.util.logging.Logger;/** * Parses the JSP page. Both the XML and JSP tags are understood. However, * escaping is always done using JSP rules. */public class JspParser { static L10N L = new L10N(JspParser.class); static final Logger log = Log.open(JspParser.class); public static final String JSP_NS = "http://java.sun.com/JSP/Page"; public static final String JSTL_CORE_URI = "http://java.sun.com/jsp/jstl/core"; public static final String JSTL_FMT_URI = "http://java.sun.com/jsp/jstl/fmt"; public static final QName PREFIX = new QName("prefix"); public static final QName TAGLIB = new QName("taglib"); public static final QName TAGDIR = new QName("tagdir"); public static final QName URI = new QName("uri"); public static final QName JSP_DECLARATION = new QName("jsp", "declaration", JSP_NS); public static final QName JSP_SCRIPTLET = new QName("jsp", "scriptlet", JSP_NS); public static final QName JSP_EXPRESSION = new QName("jsp", "expression", JSP_NS); public static final QName JSP_DIRECTIVE_PAGE = new QName("jsp", "directive.page", JSP_NS); public static final QName JSP_DIRECTIVE_INCLUDE = new QName("jsp", "directive.include", JSP_NS); public static final QName JSP_DIRECTIVE_CACHE = new QName("jsp", "directive.cache", JSP_NS); public static final QName JSP_DIRECTIVE_TAGLIB = new QName("jsp", "directive.taglib", JSP_NS); public static final QName JSP_DIRECTIVE_ATTRIBUTE = new QName("jsp", "directive.attribute", JSP_NS); public static final QName JSP_DIRECTIVE_VARIABLE = new QName("jsp", "directive.variable", JSP_NS); public static final QName JSP_DIRECTIVE_TAG = new QName("jsp", "directive.tag", JSP_NS); public static final QName JSTL_CORE_OUT = new QName("resin-c", "out", "urn:jsptld:" + JSTL_CORE_URI); public static final QName JSTL_CORE_CHOOSE = new QName("resin-c", "choose", "urn:jsptld:" + JSTL_CORE_URI); public static final QName JSTL_CORE_WHEN = new QName("resin-c", "when", "urn:jsptld:" + JSTL_CORE_URI); public static final QName JSTL_CORE_OTHERWISE = new QName("resin-c", "otherwise", "urn:jsptld:" + JSTL_CORE_URI); public static final QName JSTL_CORE_FOREACH = new QName("resin-c", "forEach", "urn:jsptld:" + JSTL_CORE_URI); private static final int TAG_UNKNOWN = 0; private static final int TAG_JSP = 1; private static final int TAG_RAW = 2; private ParseState _parseState; private JspBuilder _jspBuilder; private ParseTagManager _tagManager; private LineMap _lineMap; private ArrayList<String> _preludeList = new ArrayList<String>(); private ArrayList<String> _codaList = new ArrayList<String>(); private ArrayList<Include> _includes = new ArrayList<Include>(); private HashSet<String> _prefixes = new HashSet<String>(); private Path _jspPath; private ReadStream _stream; private String _uriPwd; private String _contextPath = ""; private String _filename = ""; private int _line; private int _lineStart; private int _charCount; private int _startText; private int _peek = -1; private boolean _seenCr = false; private Namespace _namespaces = new Namespace(null, "jsp", JSP_NS); private boolean _isXml; private boolean _isTop = true; private CharBuffer _tag = new CharBuffer(); private CharBuffer _value = new CharBuffer(); private CharBuffer _text = new CharBuffer(); /** * Sets the JSP builder, which receives the SAX-like events from * JSP parser. */ void setJspBuilder(JspBuilder builder) { _jspBuilder = builder; } /** * Sets the context path for error messages. */ void setContextPath(String contextPath) { _contextPath = contextPath; } /** * Sets the parse state, which stores state information for the parsing. */ void setParseState(ParseState parseState) { _parseState = parseState; } /** * Sets the parse state, which stores state information for the parsing. */ ParseState getParseState() { return _parseState; } /** * Sets the tag manager */ void setTagManager(ParseTagManager manager) { _tagManager = manager; } /** * Returns true if JSP EL expressions are enabled. */ private boolean isELIgnored() { return _parseState.isELIgnored(); } /** * Returns true if Velocity-style statements are enabled. */ private boolean isVelocity() { return _parseState.isVelocityEnabled(); } /** * Returns true if JSP EL expressions are enabled. */ private boolean isDeferredSyntaxAllowedAsLiteral() { return _parseState.isDeferredSyntaxAllowedAsLiteral(); } /** * Adds a prelude. */ public void addPrelude(String prelude) { _preludeList.add(prelude); } /** * Adds a coda. */ public void addCoda(String coda) { _codaList.add(coda); } /** * Starts parsing the JSP page. * * @param path the JSP source file * @param uri the URI for the JSP source file. */ void parse(Path path, String uri) throws Exception { _parseState.pushNamespace("jsp", JSP_NS); _isXml = _parseState.isXml(); _filename = _contextPath + uri; if (uri != null) { int p = uri.lastIndexOf('/'); _uriPwd = p <= 0 ? "/" : uri.substring(0, p + 1); } else { _uriPwd = "/"; } _parseState.setUriPwd(_uriPwd); ReadStream is = path.openRead(); path.setUserPath(uri); try { parseJsp(is); } finally { is.close(); for (int i = 0; i < _includes.size(); i++) { Include inc = _includes.get(i); inc._stream.close(); } } } /** * Starts parsing the JSP page as a tag. * * @param path the JSP source file * @param uri the URI for the JSP source file. */ void parseTag(Path path, String uri) throws Exception { _parseState.setTag(true); parse(path, uri); } /** * Top-level JSP parser. * * @param stream the read stream containing the JSP file * * @return an XML DOM containing the JSP. */ private void parseJsp(ReadStream stream) throws Exception { _text.clear(); _includes.clear(); String uriPwd = _uriPwd; for (int i = _codaList.size() - 1; i >= 0; i--) pushInclude(_codaList.get(i), true); addInclude(stream, uriPwd); for (int i = _preludeList.size() - 1; i >= 0; i--) pushInclude(_preludeList.get(i), true); setLocation(); _jspBuilder.startDocument(); String pageEncoding = _parseState.getPageEncoding(); int ch; if (pageEncoding != null) { _parseState.setPageEncoding(pageEncoding); stream.setEncoding(pageEncoding); } switch ((ch = stream.read())) { case 0xfe: if ((ch = stream.read()) != 0xff) { throw error(L.l("Expected 0xff in UTF-16 header. UTF-16 pages with the initial byte 0xfe expect 0xff immediately following. The 0xfe 0xff sequence is used by some application to suggest UTF-16 encoding without a directive.")); } else { //_parseState.setContentType("text/html; charset=UTF-16BE"); _parseState.setPageEncoding("UTF-16BE"); stream.setEncoding("UTF-16BE"); } break; case 0xff: if ((ch = stream.read()) != 0xfe) { throw error(L.l("Expected 0xfe in UTF-16 header. UTF-16 pages with the initial byte 0xff expect 0xfe immediately following. The 0xff 0xfe sequence is used by some application to suggest UTF-16 encoding without a directive.")); } else { //_parseState.setContentType("text/html; charset=UTF-16LE"); _parseState.setPageEncoding("UTF-16LE"); stream.setEncoding("UTF-16LE"); } break; case 0xef: if ((ch = stream.read()) != 0xbb) { stream.unread(); stream.unread(); } else if ((ch = stream.read()) != 0xbf) { throw error(L.l("Expected 0xbf in UTF-8 header. UTF-8 pages with the initial byte 0xbb expect 0xbf immediately following. The 0xbb 0xbf sequence is used by some application to suggest UTF-8 encoding without a directive.")); } else { _parseState.setContentType("text/html; charset=UTF-8"); _parseState.setPageEncoding("UTF-8"); stream.setEncoding("UTF-8"); } break; case -1: break; default: stream.unread(); break; } ch = read(); ch = parseXmlDeclaration(ch); try { parseNode(ch); } finally { for (int i = 0; i < _includes.size(); i++) { Include inc = _includes.get(i); inc._stream.close(); } } setLocation(); _jspBuilder.endDocument(); } private int parseXmlDeclaration(int ch) throws IOException, JspParseException { if (ch != '<') return ch; else if ((ch = read()) != '?') { unread(ch); return '<'; } else if ((ch = read()) != 'x') { addText("<?"); return ch; } else if ((ch = read()) != 'm') { addText("<?x"); return ch; } else if ((ch = read()) != 'l') { addText("<?xm"); return ch; } else if (! XmlChar.isWhitespace((ch = read()))) { addText("<?xml"); return ch; } String encoding = null; addText("<?xml "); ch = skipWhitespace(ch); while (XmlChar.isNameStart(ch)) { ch = readName(ch); String name = _tag.toString(); addText(name); if (XmlChar.isWhitespace(ch)) addText(' '); ch = skipWhitespace(ch); if (ch != '=') return ch; readValue(name, ch, true); String value = _value.toString(); addText("=\""); addText(value); addText("\""); if (name.equals("encoding")) encoding = value; ch = read(); if (XmlChar.isWhitespace(ch)) addText(' '); ch = skipWhitespace(ch); } if (ch != '?') return ch; else if ((ch = read()) != '>') { addText('?'); return ch; } else { addText("?>"); if (encoding != null) { _stream.setEncoding(encoding); _parseState.setPageEncoding(encoding); } return read(); } } private void parseNode(int ch) throws IOException, JspParseException { while (ch != -1) { switch (ch) { case '<': { switch ((ch = read())) { case '%': if (_isXml) throw error(L.l("'<%' syntax is not allowed in JSP/XML syntax.")); parseScriptlet(); _startText = _charCount; // escape '\\' after scriptlet at end of line if ((ch = read()) == '\\') { if ((ch = read()) == '\n') { ch = read(); } else if (ch == '\r') { if ((ch = read()) == '\n') ch = read(); } else addText('\\'); } break; case '/': ch = parseCloseTag(); break; case '\\': if ((ch = read()) == '%') { addText("<%"); ch = read(); } else addText("<\\"); break; case '!': if (! _isXml) addText("<!"); else if ((ch = read()) == '[') parseCdata(); else if (ch == '-' && (ch = read()) == '-') parseXmlComment(); else throw error(L.l("'{0}' was not expected after '<!'. In the XML syntax, only <!-- ... --> and <![CDATA[ ... ]> are legal. You can use '&!' to escape '<!'.", badChar(ch))); ch = read(); break; default: if (! XmlChar.isNameStart(ch)) { addText('<'); break; } ch = readName(ch); String name = _tag.toString(); int tagCode = getTag(name); if (! _isXml && tagCode == TAG_UNKNOWN) { addText("<"); addText(name); break; } if (_isTop && name.equals("jsp:root")) { if (_parseState.isForbidXml()) throw error(L.l("jsp:root must be in a JSP (XML) document, not a plain JSP.")); _text.clear(); _isXml = true; _parseState.setELIgnoredDefault(false); _parseState.setXml(true); } _isTop = false; parseOpenTag(name, ch, tagCode == TAG_UNKNOWN); ch = read(); // escape '\\' after scriptlet at end of line if (! _isXml && ch == '\\') { if ((ch = read()) == '\n') { ch = read(); } else if (ch == '\r') { if ((ch = read()) == '\n') ch = read(); } } } break; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?