inputentity.java

来自「java jdk 1.4的源码」· Java 代码 · 共 1,110 行 · 第 1/2 页

JAVA
1,110
字号
/* * $Id: InputEntity.java,v 1.3 2001/09/29 00:44:34 edwingo Exp $ * * The Apache Software License, Version 1.1 * * * Copyright (c) 2000 The Apache Software Foundation.  All rights  * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer.  * * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in *    the documentation and/or other materials provided with the *    distribution. * * 3. The end-user documentation included with the redistribution, *    if any, must include the following acknowledgment:   *       "This product includes software developed by the *        Apache Software Foundation (http://www.apache.org/)." *    Alternately, this acknowledgment may appear in the software itself, *    if and wherever such third-party acknowledgments normally appear. * * 4. The names "Crimson" and "Apache Software Foundation" must *    not be used to endorse or promote products derived from this *    software without prior written permission. For written  *    permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", *    nor may "Apache" appear in their name, without prior written *    permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999, Sun Microsystems, Inc.,  * http://www.sun.com.  For more information on the Apache Software  * Foundation, please see <http://www.apache.org/>. */package org.apache.crimson.parser;import java.io.CharConversionException;import java.io.UnsupportedEncodingException;import java.io.InputStreamReader;import java.io.InputStream;import java.io.IOException;import java.io.Reader;import java.io.File;import java.net.MalformedURLException;import java.net.URL;import java.util.Locale;import org.xml.sax.*;import org.apache.crimson.util.XmlChars;/** * This is how the parser talks to its input entities, of all kinds. * The entities are in a stack. *  * <P> For internal entities, the character arrays are referenced here, * and read from as needed (they're read-only).  External entities have * mutable buffers, that are read into as needed. * * <P> <em>Note:</em> This maps CRLF (and CR) to LF without regard for * whether it's in an external (parsed) entity or not.  The XML 1.0 spec * is inconsistent in explaining EOL handling; this is the sensible way. * * @author David Brownell * @version $Revision: 1.3 $ */final class InputEntity implements Locator{    private int			start, finish;    private char		buf [];    private int			lineNumber = 1;    private boolean		returnedFirstHalf = false;    private boolean		maybeInCRLF = false;    // name of entity (never main document or unnamed DTD PE)    private String		name;    private InputEntity		next;    // for system and public IDs in diagnostics    private InputSource		input;    // this is a buffer; some buffers can be replenished.    private Reader		reader;    private boolean		isClosed;    private ErrorHandler    	errHandler;    private Locale		locale;    private StringBuffer	rememberedText;    private int			startRemember;    // record if this is a PE, so endParsedEntity won't be called    private boolean		isPE;    // InputStreamReader throws an internal per-read exception, so    // we minimize reads.  We also add a byte to compensate for the    // "ungetc" byte we keep, so that our downstream reads are as    // nicely sized as we can make them.    final private static int	BUFSIZ = 8 * 1024 + 1;    final private static char	newline [] = { '\n' };    public static InputEntity getInputEntity (ErrorHandler h, Locale l)    {	InputEntity retval = new InputEntity ();	retval.errHandler = h;	retval.locale = l;	return retval;    }    private InputEntity () { }    //    // predicate:  return true iff this is an internal entity reader,    // and so may safely be "popped" as needed.  external entities have    // syntax to uphold; internal parameter entities have at most validity    // constraints to monitor.  also, only external entities get decent    // location diagnostics.    //    public boolean isInternal () { return reader == null; }    //    // predicate:  return true iff this is the toplevel document    //    public boolean isDocument () { return next == null; }    //    // predicate:  return true iff this is a PE expansion (so that    // LexicalEventListner.endParsedEntity won't be called)    //    public boolean isParameterEntity () { return isPE; }    //    // return name of current entity    //    public String getName () { return name; }    private static String convertToFileURL(String filename) {        // On JDK 1.2 and later, simplify this to:        // "path = file.toURL().toString()".        String path = new File(filename).getAbsolutePath();        if (File.separatorChar != '/') {            path = path.replace(File.separatorChar, '/');        }        if (!path.startsWith("/")) {            path = "/" + path;        }        return "file:" + path;    }    /**     * Use this for an external parsed entity     */    public void init(InputSource in, String name, InputEntity stack,                     boolean isPE)        throws IOException, SAXException    {	input = in;	this.isPE = isPE;	reader = in.getCharacterStream ();	if (reader == null) {	    InputStream		bytes = in.getByteStream ();	    if (bytes == null) {                // When the app first provides an external InputSource, the                // SystemId may not be a valid URI and just be a simple                // filename.  In this case, convert the filename to a                // "file:" URL instead of throwing an exception.  Note:                // this does not strictly conform to the SAX spec but is                // convenient for users.                String systemId = in.getSystemId();                URL url;                try {                    url = new URL(systemId);                } catch (MalformedURLException e) {                    String urlString = convertToFileURL(systemId);                    in.setSystemId(urlString);                    url = new URL(urlString);                }		reader = XmlReader.createReader(url.openStream());	    } else if (in.getEncoding () != null)		reader = XmlReader.createReader (			in.getByteStream (),			in.getEncoding ());	    else		reader = XmlReader.createReader (in.getByteStream ());	}	next = stack;	buf = new char [BUFSIZ];	this.name = name;	checkRecursion (stack);    }    //    // use this for an internal parsed entity; buffer is readonly    //    public void init (char b [], String name,	InputEntity stack, boolean isPE)    throws SAXException    {	next = stack;	buf = b;	finish = b.length;	this.name = name;	this.isPE = isPE;	checkRecursion (stack);    }    private void checkRecursion (InputEntity stack) throws SAXException    {	if (stack == null)	    return;	for (stack = stack.next; stack != null; stack = stack.next) {	    if (stack.name != null && stack.name.equals (name))		fatal ("P-069", new Object [] { name });	}    }    public InputEntity pop () throws IOException    {	// caller has ensured there's nothing left to read	close ();	return next;    }    /** returns true iff there's no more data to consume ... */    public boolean isEOF ()    throws IOException, SAXException    {	// called to ensure WF-ness of included entities and to pop	// input entities appropriately ... EOF is not always legal.	if (start >= finish) {	    fillbuf ();	    return start >= finish;	} else	    return false;    }    /**     * Returns the name of the encoding in use, else null; the name     * returned is in as standard a form as we can get.     */    public String getEncoding ()    {	if (reader == null)	    return null;	if (reader instanceof XmlReader)	    return ((XmlReader)reader).getEncoding ();	// XXX prefer a java2std() call to normalize names...	if (reader instanceof InputStreamReader)	    return ((InputStreamReader)reader).getEncoding ();	return null;    }    /**     * returns the next name char, or NUL ... faster than getc(),     * and the common "name or nmtoken must be next" case won't     * need ungetc().     */    public char getNameChar () throws IOException, SAXException    {	if (finish <= start)	    fillbuf ();	if (finish > start) {	    char c = buf [start++];	    if (XmlChars.isNameChar (c))		return c;	    start--;	}	return 0;    }    /**     * gets the next Java character -- might be part of an XML     * text character represented by a surrogate pair, or be     * the end of the entity.     */    public char getc () throws IOException, SAXException    {	if (finish <= start)	    fillbuf ();	if (finish > start) {	    char c = buf [start++];	    // [2] Char ::= #x0009 | #x000A | #x000D	    //			| [#x0020-#xD7FF]	    //			| [#xE000-#xFFFD]	    // plus surrogate _pairs_ representing [#x10000-#x10ffff]	    if (returnedFirstHalf) {		if (c >= 0xdc00 && c <= 0xdfff) {		    returnedFirstHalf = false;		    return c;		} else		    fatal ("P-070", new Object [] { Integer.toHexString (c) });	    }	    if ((c >= 0x0020 && c <= 0xD7FF)			|| c == 0x0009			// no surrogates!			|| (c >= 0xE000 && c <= 0xFFFD))		return c;	    //	    // CRLF and CR are both line ends; map both to LF, and	    // keep line count correct.	    //	    else if (c == '\r' && !isInternal ()) {		maybeInCRLF = true;		c = getc ();		if (c != '\n')		    ungetc ();		maybeInCRLF = false;		lineNumber++;		return '\n';	    } else if (c == '\n' || c == '\r') { // LF, or 2nd char in CRLF		if (!isInternal () && !maybeInCRLF)		    lineNumber++;		return c;	    }	    // surrogates...	    if (c >= 0xd800 && c < 0xdc00) {		returnedFirstHalf = true;		return c;	    }	    fatal ("P-071", new Object [] { Integer.toHexString (c) });	}	throw new EndOfInputException ();    }    public boolean peekc (char c) throws IOException, SAXException    {	if (finish <= start)	    fillbuf ();	if (finish > start) {	    if (buf [start] == c) {		start++;		return true;	    } else		return false;	}	return false;    }    /**     * two character pushback is guaranteed     */    public void ungetc ()    {	if (start == 0)	    throw new InternalError ("ungetc");	start--;	if (buf [start] == '\n' || buf [start] == '\r') {	    if (!isInternal ())		lineNumber--;	} else if (returnedFirstHalf)	    returnedFirstHalf = false;    }    /**     * optional grammatical whitespace (discarded)     */    public boolean maybeWhitespace ()    throws IOException, SAXException    {	char	c;	boolean	isSpace = false;	boolean	sawCR = false;	// [3] S ::= #20 | #09 | #0D | #0A	for (;;) {	    if (finish <= start)		fillbuf ();	    if (finish <= start)		return isSpace;	    c = buf [start++];	    if (c == 0x20 || c == 0x09 || c == '\n' || c == '\r') {		isSpace = true;		//		// CR, LF are line endings ... CLRF is one, not two!		//		if ((c == '\n' || c == '\r') && !isInternal ()) {		    if (!(c == '\n' && sawCR)) {			lineNumber++;			sawCR = false;		    }		    if (c == '\r')			sawCR = true;		}	    } else {		start--;		return isSpace;	    }	}    }    /**     * normal content; whitespace in markup may be handled     * specially if the parser uses the content model.     *     * <P> content terminates with markup delimiter characters,     * namely ampersand (&amp;amp;) and left angle bracket (&amp;lt;).     *     * <P> the document handler's characters() method is called     * on all the content found     */    public boolean parsedContent (	ContentHandler		contentHandler,	ElementValidator	validator    ) throws IOException, SAXException    {	// [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)	int		first;		// first char to return	int		last;		// last char to return	boolean		sawContent;	// sent any chars?	char		c;	// deliver right out of the buffer, until delimiter, EOF,	// or error, refilling as we go	for (first = last = start, sawContent = false; ; last++) {	    // buffer empty?	    if (last >= finish) {		if (last > first) {		    validator.text ();		    contentHandler.characters (buf, first, last - first);		    sawContent = true;		    start = last;		}		if (isEOF ())	// calls fillbuf		    return sawContent;		first = start;		last = first - 1;	// incremented in loop		continue;	    }	    c = buf [last];	    //	    // pass most chars through ASAP; this inlines the code of	    // [2] !XmlChars.isChar(c) leaving only characters needing	    // special treatment ... line ends, surrogates, and: 	    //	0x0026 == '&'	    //	0x003C == '<'	    //	0x005D == ']'	    // Comparisons ordered for speed on 'typical' text	    //	    if (       (c >  0x005D && c <= 0xD7FF)	// a-z and more		    || (c <  0x0026 && c >= 0x0020)	// space & punct		    || (c >  0x003C && c <  0x005D)	// A-Z & punct		    || (c >  0x0026 && c <  0x003C)	// 0-9 & punct		    ||  c == 0x0009		    || (c >= 0xE000 && c <= 0xFFFD)		    )		continue;	    // terminate on markup delimiters	    if (c == '<' || c == '&')		break;	    // count lines	    if (c == '\n') {	        if (!isInternal ())		    lineNumber++;	        continue;	    }	    // External entities get CR, CRLF --> LF mapping	    // Internal ones got it already, and we can't repeat	    // else we break char ref handling!!	    if (c == '\r') {		if (isInternal ())		    continue;		contentHandler.characters (buf, first, last - first);		contentHandler.characters (newline, 0, 1);		sawContent = true;		lineNumber++;		if (finish > (last + 1)) {		    if (buf [last + 1] == '\n')			last++;		} else {	// CR at end of buffer// XXX case not yet handled:  CRLF here will look like two lines		}		first = start = last + 1;		continue;	    }	    // ']]>' is a WF error -- must fail if we see it	    if (c == ']') {		switch (finish - last) {		  // for suspicious end-of-buffer cases, get more data		  // into the buffer to rule out this sequence.		  case 2:		    if (buf [last + 1] != ']')			continue;		    // FALLTHROUGH		  case 1:		    if (reader == null || isClosed)			continue;		    if (last == first)			throw new InternalError ("fillbuf");		    last--;		    if (last > first) {			validator.text ();			contentHandler.characters (buf, first, last - first);			sawContent = true;			start = last;		    }		    fillbuf ();		    first = last = start;		    continue;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?