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;) and left angle bracket (&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 + -
显示快捷键?