| /* |
| * 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.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 <a href="http://www.w3.org/TR/REC-xml" |
| * >Extensible Markup Language (XML) 1.0</a> and <a |
| * href="http://www.w3.org/TR/REC-xml-names" >"Namespaces in XML"</a> |
| * specifications. The API supported by the parser are <a |
| * href="http://java.sun.com/aboutJava/communityprocess/final/jsr030/index.html">CLDC |
| * 1.0</a> and <a href="http://www.jcp.org/en/jsr/detail?id=280">JSR-280</a>, a |
| * JavaME subset of <a href="http://java.sun.com/xml/jaxp/index.html">JAXP</a> |
| * and <a href="http://www.saxproject.org/">SAX2</a>. |
| * |
| * @see org.xml.sax.XMLReader |
| */ |
| |
| final class ParserSAX |
| extends Parser implements XMLReader, Locator |
| { |
| public static final String FEATURE_NS = |
| "http://xml.org/sax/features/namespaces"; |
| public static final 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. |
| * |
| * <p>If the application does not register a content handler, all content |
| * events reported by the SAX parser will be silently ignored.</p> |
| * |
| * <p>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.</p> |
| * |
| * @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. |
| * |
| * <p>If the application does not register a DTD handler, all DTD events |
| * reported by the SAX parser will be silently ignored.</p> |
| * |
| * <p>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.</p> |
| * |
| * @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. |
| * |
| * <p>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.</p> |
| * |
| * <p>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.</p> |
| * |
| * @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. |
| * |
| * <p>If the application does not register an entity resolver, the XMLReader |
| * will perform its own default resolution.</p> |
| * |
| * <p>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.</p> |
| * |
| * @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. |
| * |
| * <p>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.</p> |
| * |
| * @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. |
| * |
| * <p>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.</p> |
| * |
| * <p>If the system identifier is a URL, the parser must resolve it fully |
| * before passing it to the application.</p> |
| * |
| * @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). |
| * |
| * <p>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:</p> |
| * |
| * <pre> |
| * parse(new InputSource(systemId)); |
| * </pre> |
| * |
| * <p>If the system identifier is a URL, it must be fully resolved by the |
| * application before it is passed to the parser.</p> |
| * |
| * @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. |
| * |
| * <p>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).</p> |
| * |
| * <p>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.</p> |
| * |
| * <p>During the parse, the XMLReader will provide information about the XML |
| * document through the registered event handlers.</p> |
| * |
| * <p>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.</p> |
| * |
| * @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 | IOException | RuntimeException saxe) { |
| throw saxe; |
| } 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. |
| */ |
| @SuppressWarnings("fallthrough") |
| 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 <code>null</code>. |
| * @param sysid The system identifier of the entity or <code>null</code>. |
| */ |
| 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 ( |
| * <code>mPref.name</code>) being declared and the Namespace URI ( |
| * <code>mPref.value</code>) 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 |
| * <code>InputSource</code> for specified entity or |
| * <code>null</code>. |
| * |
| * @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 |
| * copying 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 copying 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) { |
| throw new UnsupportedOperationException("Not supported yet."); |
| } |
| |
| public void setFeature(String name, boolean value) { |
| throw new UnsupportedOperationException("Not supported yet."); |
| } |
| |
| public Object getProperty(String name) { |
| throw new UnsupportedOperationException("Not supported yet."); |
| } |
| |
| public void setProperty(String name, Object value) { |
| throw new UnsupportedOperationException("Not supported yet."); |
| } |
| } |