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 '&amp;!' 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 + -
显示快捷键?