📄 jspreader.java
字号:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jasper.compiler;
import java.io.CharArrayWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Vector;
import java.util.jar.JarFile;
import java.net.URL;
import java.net.MalformedURLException;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* JspReader is an input buffer for the JSP parser. It should allow
* unlimited lookahead and pushback. It also has a bunch of parsing
* utility methods for understanding htmlesque thingies.
*
* @author Anil K. Vijendran
* @author Anselm Baird-Smith
* @author Harish Prabandham
* @author Rajiv Mordani
* @author Mandar Raje
* @author Danno Ferrin
* @author Kin-man Chung
* @author Shawn Bayern
* @author Mark Roth
*/
class JspReader {
/**
* Logger.
*/
private Log log = LogFactory.getLog(JspReader.class);
/**
* The current spot in the file.
*/
private Mark current;
/**
* What is this?
*/
private String master;
/**
* The list of source files.
*/
private List sourceFiles;
/**
* The current file ID (-1 indicates an error or no file).
*/
private int currFileId;
/**
* Seems redundant.
*/
private int size;
/**
* The compilation context.
*/
private JspCompilationContext context;
/**
* The Jasper error dispatcher.
*/
private ErrorDispatcher err;
/**
* Set to true when using the JspReader on a single file where we read up
* to the end and reset to the beginning many times.
* (as in ParserController.figureOutJspDocument()).
*/
private boolean singleFile;
/**
* Constructor.
*
* @param ctxt The compilation context
* @param fname The file name
* @param encoding The file encoding
* @param jarFile ?
* @param err The error dispatcher
* @throws JasperException If a Jasper-internal error occurs
* @throws FileNotFoundException If the JSP file is not found (or is unreadable)
* @throws IOException If an IO-level error occurs, e.g. reading the file
*/
public JspReader(JspCompilationContext ctxt,
String fname,
String encoding,
JarFile jarFile,
ErrorDispatcher err)
throws JasperException, FileNotFoundException, IOException {
this(ctxt, fname, encoding,
JspUtil.getReader(fname, encoding, jarFile, ctxt, err),
err);
}
/**
* Constructor: same as above constructor but with initialized reader
* to the file given.
*/
public JspReader(JspCompilationContext ctxt,
String fname,
String encoding,
InputStreamReader reader,
ErrorDispatcher err)
throws JasperException, FileNotFoundException {
this.context = ctxt;
this.err = err;
sourceFiles = new Vector();
currFileId = 0;
size = 0;
singleFile = false;
pushFile(fname, encoding, reader);
}
/**
* @return JSP compilation context with which this JspReader is
* associated
*/
JspCompilationContext getJspCompilationContext() {
return context;
}
/**
* Returns the file at the given position in the list.
*
* @param fileid The file position in the list
* @return The file at that position, if found, null otherwise
*/
String getFile(final int fileid) {
return (String) sourceFiles.get(fileid);
}
/**
* Checks if the current file has more input.
*
* @return True if more reading is possible
* @throws JasperException if an error occurs
*/
boolean hasMoreInput() throws JasperException {
if (current.cursor >= current.stream.length) {
if (singleFile) return false;
while (popFile()) {
if (current.cursor < current.stream.length) return true;
}
return false;
}
return true;
}
int nextChar() throws JasperException {
if (!hasMoreInput())
return -1;
int ch = current.stream[current.cursor];
current.cursor++;
if (ch == '\n') {
current.line++;
current.col = 0;
} else {
current.col++;
}
return ch;
}
/**
* Back up the current cursor by one char, assumes current.cursor > 0,
* and that the char to be pushed back is not '\n'.
*/
void pushChar() {
current.cursor--;
current.col--;
}
String getText(Mark start, Mark stop) throws JasperException {
Mark oldstart = mark();
reset(start);
CharArrayWriter caw = new CharArrayWriter();
while (!stop.equals(mark()))
caw.write(nextChar());
caw.close();
reset(oldstart);
return caw.toString();
}
int peekChar() throws JasperException {
if (!hasMoreInput())
return -1;
return current.stream[current.cursor];
}
Mark mark() {
return new Mark(current);
}
void reset(Mark mark) {
current = new Mark(mark);
}
boolean matchesIgnoreCase(String string) throws JasperException {
Mark mark = mark();
int ch = 0;
int i = 0;
do {
ch = nextChar();
if (Character.toLowerCase((char) ch) != string.charAt(i++)) {
reset(mark);
return false;
}
} while (i < string.length());
reset(mark);
return true;
}
/**
* search the stream for a match to a string
* @param string The string to match
* @return <strong>true</strong> is one is found, the current position
* in stream is positioned after the search string, <strong>
* false</strong> otherwise, position in stream unchanged.
*/
boolean matches(String string) throws JasperException {
Mark mark = mark();
int ch = 0;
int i = 0;
do {
ch = nextChar();
if (((char) ch) != string.charAt(i++)) {
reset(mark);
return false;
}
} while (i < string.length());
return true;
}
boolean matchesETag(String tagName) throws JasperException {
Mark mark = mark();
if (!matches("</" + tagName))
return false;
skipSpaces();
if (nextChar() == '>')
return true;
reset(mark);
return false;
}
boolean matchesETagWithoutLessThan(String tagName)
throws JasperException
{
Mark mark = mark();
if (!matches("/" + tagName))
return false;
skipSpaces();
if (nextChar() == '>')
return true;
reset(mark);
return false;
}
/**
* Looks ahead to see if there are optional spaces followed by
* the given String. If so, true is returned and those spaces and
* characters are skipped. If not, false is returned and the
* position is restored to where we were before.
*/
boolean matchesOptionalSpacesFollowedBy( String s )
throws JasperException
{
Mark mark = mark();
skipSpaces();
boolean result = matches( s );
if( !result ) {
reset( mark );
}
return result;
}
int skipSpaces() throws JasperException {
int i = 0;
while (hasMoreInput() && isSpace()) {
i++;
nextChar();
}
return i;
}
/**
* Skip until the given string is matched in the stream.
* When returned, the context is positioned past the end of the match.
*
* @param s The String to match.
* @return A non-null <code>Mark</code> instance (positioned immediately
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -