--- /dev/null 2012-12-05 14:31:29.000000000 +0000 +++ new/src/share/classes/jdk/internal/util/xml/impl/ParserSAX.java 2012-12-05 14:31:28.000000000 +0000 @@ -0,0 +1,709 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.util.xml.impl; + +import java.io.IOException; +import java.io.InputStream; +import jdk.internal.org.xml.sax.ContentHandler; +import jdk.internal.org.xml.sax.DTDHandler; +import jdk.internal.org.xml.sax.EntityResolver; +import jdk.internal.org.xml.sax.ErrorHandler; +import jdk.internal.org.xml.sax.InputSource; +import jdk.internal.org.xml.sax.Locator; +import jdk.internal.org.xml.sax.SAXException; +import jdk.internal.org.xml.sax.SAXNotRecognizedException; +import jdk.internal.org.xml.sax.SAXNotSupportedException; +import jdk.internal.org.xml.sax.SAXParseException; +import jdk.internal.org.xml.sax.XMLReader; +import jdk.internal.org.xml.sax.helpers.DefaultHandler; + +/** + * XML non-validating push parser. + * + * This non-validating parser conforms to Extensible Markup Language (XML) 1.0 and "Namespaces in XML" + * specifications. The API supported by the parser are CLDC + * 1.0 and JSR-280, a + * JavaME subset of JAXP + * and SAX2. + * + * @see org.xml.sax.XMLReader + */ + +/* pkg */ final class ParserSAX + extends Parser + implements XMLReader, Locator { + + public final static String FEATURE_NS = + "http://xml.org/sax/features/namespaces"; + public final static String FEATURE_PREF = + "http://xml.org/sax/features/namespace-prefixes"; + // SAX feature flags + private boolean mFNamespaces; + private boolean mFPrefixes; + // SAX handlers + private DefaultHandler mHand; // the default handler + private ContentHandler mHandCont; // the content handler + private DTDHandler mHandDtd; // the DTD handler + private ErrorHandler mHandErr; // the error handler + private EntityResolver mHandEnt; // the entity resolver + + /** + * Constructor. + */ + public ParserSAX() { + super(); + + // SAX feature defaut values + mFNamespaces = true; + mFPrefixes = false; + + // Default handler which will be used in case the application + // do not set one of handlers. + mHand = new DefaultHandler(); + mHandCont = mHand; + mHandDtd = mHand; + mHandErr = mHand; + mHandEnt = mHand; + } + + /** + * Return the current content handler. + * + * @return The current content handler, or null if none has been registered. + * @see #setContentHandler + */ + public ContentHandler getContentHandler() { + return (mHandCont != mHand) ? mHandCont : null; + } + + /** + * Allow an application to register a content event handler. + * + *

If the application does not register a content handler, all content + * events reported by the SAX parser will be silently ignored.

+ * + *

Applications may register a new or different handler in the middle of + * a parse, and the SAX parser must begin using the new handler + * immediately.

+ * + * @param handler The content handler. + * @exception java.lang.NullPointerException If the handler argument is + * null. + * @see #getContentHandler + */ + public void setContentHandler(ContentHandler handler) { + if (handler == null) { + throw new NullPointerException(); + } + mHandCont = handler; + } + + /** + * Return the current DTD handler. + * + * @return The current DTD handler, or null if none has been registered. + * @see #setDTDHandler + */ + public DTDHandler getDTDHandler() { + return (mHandDtd != mHand) ? mHandDtd : null; + } + + /** + * Allow an application to register a DTD event handler. + * + *

If the application does not register a DTD handler, all DTD events + * reported by the SAX parser will be silently ignored.

+ * + *

Applications may register a new or different handler in the middle of + * a parse, and the SAX parser must begin using the new handler + * immediately.

+ * + * @param handler The DTD handler. + * @exception java.lang.NullPointerException If the handler argument is + * null. + * @see #getDTDHandler + */ + public void setDTDHandler(DTDHandler handler) { + if (handler == null) { + throw new NullPointerException(); + } + mHandDtd = handler; + } + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none has been registered. + * @see #setErrorHandler + */ + public ErrorHandler getErrorHandler() { + return (mHandErr != mHand) ? mHandErr : null; + } + + /** + * Allow an application to register an error event handler. + * + *

If the application does not register an error handler, all error + * events reported by the SAX parser will be silently ignored; however, + * normal processing may not continue. It is highly recommended that all SAX + * applications implement an error handler to avoid unexpected bugs.

+ * + *

Applications may register a new or different handler in the middle of + * a parse, and the SAX parser must begin using the new handler + * immediately.

+ * + * @param handler The error handler. + * @exception java.lang.NullPointerException If the handler argument is + * null. + * @see #getErrorHandler + */ + public void setErrorHandler(ErrorHandler handler) { + if (handler == null) { + throw new NullPointerException(); + } + mHandErr = handler; + } + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none has been registered. + * @see #setEntityResolver + */ + public EntityResolver getEntityResolver() { + return (mHandEnt != mHand) ? mHandEnt : null; + } + + /** + * Allow an application to register an entity resolver. + * + *

If the application does not register an entity resolver, the XMLReader + * will perform its own default resolution.

+ * + *

Applications may register a new or different resolver in the middle of + * a parse, and the SAX parser must begin using the new resolver + * immediately.

+ * + * @param resolver The entity resolver. + * @exception java.lang.NullPointerException If the resolver argument is + * null. + * @see #getEntityResolver + */ + public void setEntityResolver(EntityResolver resolver) { + if (resolver == null) { + throw new NullPointerException(); + } + mHandEnt = resolver; + } + + /** + * Return the public identifier for the current document event. + * + *

The return value is the public identifier of the document entity or of + * the external parsed entity in which the markup triggering the event + * appears.

+ * + * @return A string containing the public identifier, or null if none is + * available. + * + * @see #getSystemId + */ + public String getPublicId() { + return (mInp != null) ? mInp.pubid : null; + } + + /** + * Return the system identifier for the current document event. + * + *

The return value is the system identifier of the document entity or of + * the external parsed entity in which the markup triggering the event + * appears.

+ * + *

If the system identifier is a URL, the parser must resolve it fully + * before passing it to the application.

+ * + * @return A string containing the system identifier, or null if none is + * available. + * + * @see #getPublicId + */ + public String getSystemId() { + return (mInp != null) ? mInp.sysid : null; + } + + /** + * Return the line number where the current document event ends. + * + * @return Always returns -1 indicating the line number is not available. + * + * @see #getColumnNumber + */ + public int getLineNumber() { + return -1; + } + + /** + * Return the column number where the current document event ends. + * + * @return Always returns -1 indicating the column number is not available. + * + * @see #getLineNumber + */ + public int getColumnNumber() { + return -1; + } + + /** + * Parse an XML document from a system identifier (URI). + * + *

This method is a shortcut for the common case of reading a document + * from a system identifier. It is the exact equivalent of the + * following:

+ * + *
+     * parse(new InputSource(systemId));
+     * 
+ * + *

If the system identifier is a URL, it must be fully resolved by the + * application before it is passed to the parser.

+ * + * @param systemId The system identifier (URI). + * @exception org.xml.sax.SAXException Any SAX exception, possibly wrapping + * another exception. + * @exception java.io.IOException An IO exception from the parser, possibly + * from a byte stream or character stream supplied by the application. + * @see #parse(org.xml.sax.InputSource) + */ + public void parse(String systemId) + throws IOException, SAXException { + parse(new InputSource(systemId)); + } + + /** + * Parse an XML document. + * + *

The application can use this method to instruct the XML reader to + * begin parsing an XML document from any valid input source (a character + * stream, a byte stream, or a URI).

+ * + *

Applications may not invoke this method while a parse is in progress + * (they should create a new XMLReader instead for each nested XML + * document). Once a parse is complete, an application may reuse the same + * XMLReader object, possibly with a different input source.

+ * + *

During the parse, the XMLReader will provide information about the XML + * document through the registered event handlers.

+ * + *

This method is synchronous: it will not return until parsing has + * ended. If a client application wants to terminate parsing early, it + * should throw an exception.

+ * + * @param is The input source for the top-level of the XML document. + * @exception org.xml.sax.SAXException Any SAX exception, possibly wrapping + * another exception. + * @exception java.io.IOException An IO exception from the parser, possibly + * from a byte stream or character stream supplied by the application. + * @see org.xml.sax.InputSource + * @see #parse(java.lang.String) + * @see #setEntityResolver + * @see #setDTDHandler + * @see #setContentHandler + * @see #setErrorHandler + */ + public void parse(InputSource is) + throws IOException, SAXException { + if (is == null) { + throw new IllegalArgumentException(""); + } + // Set up the document + mInp = new Input(BUFFSIZE_READER); + mPh = PH_BEFORE_DOC; // before parsing + try { + setinp(is); + } catch (SAXException saxe) { + throw saxe; + } catch (IOException ioe) { + throw ioe; + } catch (RuntimeException rte) { + throw rte; + } catch (Exception e) { + panic(e.toString()); + } + parse(); + } + + /** + * Parse the content of the given {@link java.io.InputStream} instance as + * XML using the specified {@link org.xml.sax.helpers.DefaultHandler}. + * + * @param src InputStream containing the content to be parsed. + * @param handler The SAX DefaultHandler to use. + * @exception IOException If any IO errors occur. + * @exception IllegalArgumentException If the given InputStream or handler + * is null. + * @exception SAXException If the underlying parser throws a SAXException + * while parsing. + * @see org.xml.sax.helpers.DefaultHandler + */ + public void parse(InputStream src, DefaultHandler handler) + throws SAXException, IOException { + if ((src == null) || (handler == null)) { + throw new IllegalArgumentException(""); + } + parse(new InputSource(src), handler); + } + + /** + * Parse the content given {@link org.xml.sax.InputSource} as XML using the + * specified {@link org.xml.sax.helpers.DefaultHandler}. + * + * @param is The InputSource containing the content to be parsed. + * @param handler The SAX DefaultHandler to use. + * @exception IOException If any IO errors occur. + * @exception IllegalArgumentException If the InputSource or handler is + * null. + * @exception SAXException If the underlying parser throws a SAXException + * while parsing. + * @see org.xml.sax.helpers.DefaultHandler + */ + public void parse(InputSource is, DefaultHandler handler) + throws SAXException, IOException { + if ((is == null) || (handler == null)) { + throw new IllegalArgumentException(""); + } + // Set up the handler + mHandCont = handler; + mHandDtd = handler; + mHandErr = handler; + mHandEnt = handler; + // Set up the document + mInp = new Input(BUFFSIZE_READER); + mPh = PH_BEFORE_DOC; // before parsing + try { + setinp(is); + } catch (SAXException saxe) { + throw saxe; + } catch (IOException ioe) { + throw ioe; + } catch (RuntimeException rte) { + throw rte; + } catch (Exception e) { + panic(e.toString()); + } + parse(); + } + + /** + * Parse the XML document content using specified handlers and an input + * source. + * + * @exception IOException If any IO errors occur. + * @exception SAXException If the underlying parser throws a SAXException + * while parsing. + */ + private void parse() + throws SAXException, IOException { + + init(); + try { + mHandCont.setDocumentLocator(this); + mHandCont.startDocument(); + + if (mPh != PH_MISC_DTD) { + mPh = PH_MISC_DTD; // misc before DTD + } + int evt = EV_NULL; + // XML document prolog + do { + wsskip(); + switch (evt = step()) { + case EV_ELM: + case EV_ELMS: + mPh = PH_DOCELM; + break; + + case EV_COMM: + case EV_PI: + break; + + case EV_DTD: + if (mPh >= PH_DTD_MISC) { + panic(FAULT); + } + mPh = PH_DTD_MISC; // misc after DTD + break; + + default: + panic(FAULT); + } + } while (mPh < PH_DOCELM); // misc before DTD + // XML document starting with document's element + do { + switch (evt) { + case EV_ELM: + case EV_ELMS: + // Report the element + if (mIsNSAware == true) { + mHandCont.startElement( + mElm.value, + mElm.name, + "", + mAttrs); + } else { + mHandCont.startElement( + "", + "", + mElm.name, + mAttrs); + } + if (evt == EV_ELMS) { + evt = step(); + break; + } + + case EV_ELME: + // Report the end of element + if (mIsNSAware == true) { + mHandCont.endElement(mElm.value, mElm.name, ""); + } else { + mHandCont.endElement("", "", mElm.name); + } + // Restore the top of the prefix stack + while (mPref.list == mElm) { + mHandCont.endPrefixMapping(mPref.name); + mPref = del(mPref); + } + // Remove the top element tag + mElm = del(mElm); + if (mElm == null) { + mPh = PH_DOCELM_MISC; + } else { + evt = step(); + } + break; + + case EV_TEXT: + case EV_WSPC: + case EV_CDAT: + case EV_COMM: + case EV_PI: + case EV_ENT: + evt = step(); + break; + + default: + panic(FAULT); + } + } while (mPh == PH_DOCELM); + // Misc after document's element + do { + if (wsskip() == EOS) { + break; + } + + switch (step()) { + case EV_COMM: + case EV_PI: + break; + + default: + panic(FAULT); + } + } while (mPh == PH_DOCELM_MISC); + mPh = PH_AFTER_DOC; // parsing is completed + + } catch (SAXException saxe) { + throw saxe; + } catch (IOException ioe) { + throw ioe; + } catch (RuntimeException rte) { + throw rte; + } catch (Exception e) { + panic(e.toString()); + } finally { + mHandCont.endDocument(); + cleanup(); + } + } + + /** + * Reports document type. + * + * @param name The name of the entity. + * @param pubid The public identifier of the entity or null. + * @param sysid The system identifier of the entity or null. + */ + protected void docType(String name, String pubid, String sysid) + throws SAXException { + mHandDtd.notationDecl(name, pubid, sysid); + } + + /** + * Reports a comment. + * + * @param text The comment text starting from first charcater. + * @param length The number of characters in comment. + */ + protected void comm(char[] text, int length) { + } + + /** + * Reports a processing instruction. + * + * @param target The processing instruction target name. + * @param body The processing instruction body text. + */ + protected void pi(String target, String body) + throws SAXException { + mHandCont.processingInstruction(target, body); + } + + /** + * Reports new namespace prefix. The Namespace prefix ( + * mPref.name) being declared and the Namespace URI ( + * mPref.value) the prefix is mapped to. An empty string is + * used for the default element namespace, which has no prefix. + */ + protected void newPrefix() + throws SAXException { + mHandCont.startPrefixMapping(mPref.name, mPref.value); + } + + /** + * Reports skipped entity name. + * + * @param name The entity name. + */ + protected void skippedEnt(String name) + throws SAXException { + mHandCont.skippedEntity(name); + } + + /** + * Returns an + * InputSource for specified entity or + * null. + * + * @param name The name of the entity. + * @param pubid The public identifier of the entity. + * @param sysid The system identifier of the entity. + */ + protected InputSource resolveEnt(String name, String pubid, String sysid) + throws SAXException, IOException { + return mHandEnt.resolveEntity(pubid, sysid); + } + + /** + * Reports notation declaration. + * + * @param name The notation's name. + * @param pubid The notation's public identifier, or null if none was given. + * @param sysid The notation's system identifier, or null if none was given. + */ + protected void notDecl(String name, String pubid, String sysid) + throws SAXException { + mHandDtd.notationDecl(name, pubid, sysid); + } + + /** + * Reports unparsed entity name. + * + * @param name The unparsed entity's name. + * @param pubid The entity's public identifier, or null if none was given. + * @param sysid The entity's system identifier. + * @param notation The name of the associated notation. + */ + protected void unparsedEntDecl( + String name, String pubid, String sysid, String notation) + throws SAXException { + mHandDtd.unparsedEntityDecl(name, pubid, sysid, notation); + } + + /** + * Notifies the handler about fatal parsing error. + * + * @param msg The problem description message. + */ + protected void panic(String msg) + throws SAXException { + SAXParseException spe = new SAXParseException(msg, this); + mHandErr.fatalError(spe); + throw spe; // [#1.2] fatal error definition + } + + /** + * Reports characters and empties the parser's buffer. This method is called + * only if parser is going to return control to the main loop. This means + * that this method may use parser buffer to report white space without + * copeing characters to temporary buffer. + */ + protected void bflash() + throws SAXException { + if (mBuffIdx >= 0) { + // Textual data has been read + mHandCont.characters(mBuff, 0, (mBuffIdx + 1)); + mBuffIdx = -1; + } + } + + /** + * Reports white space characters and empties the parser's buffer. This + * method is called only if parser is going to return control to the main + * loop. This means that this method may use parser buffer to report white + * space without copeing characters to temporary buffer. + */ + protected void bflash_ws() + throws SAXException { + if (mBuffIdx >= 0) { + // BUG: With additional info from DTD and xml:space attr [#2.10] + // the following call can be supported: + // mHandCont.ignorableWhitespace(mBuff, 0, (mBuffIdx + 1)); + + // Textual data has been read + mHandCont.characters(mBuff, 0, (mBuffIdx + 1)); + mBuffIdx = -1; + } + } + + public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setProperty(String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { + throw new UnsupportedOperationException("Not supported yet."); + } +}