- /*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 1999-2004 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 "Xerces" 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, International
- * Business Machines, Inc., http://www.apache.org. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- */
-
- package com.sun.org.apache.xerces.internal.impl;
-
- import java.io.IOException;
-
- import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
- import com.sun.org.apache.xerces.internal.util.SymbolTable;
- import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
- import com.sun.org.apache.xerces.internal.util.XMLChar;
- import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
- import com.sun.org.apache.xerces.internal.xni.Augmentations;
- import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
- import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
- import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
- import com.sun.org.apache.xerces.internal.xni.XMLString;
- import com.sun.org.apache.xerces.internal.xni.XNIException;
- import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
- import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
- import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
- import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDScanner;
- import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
-
- /**
- * This class is responsible for scanning the declarations found
- * in the internal and external subsets of a DTD in an XML document.
- * The scanner acts as the sources for the DTD information which is
- * communicated to the DTD handlers.
- * <p>
- * This component requires the following features and properties from the
- * component manager that uses it:
- * <ul>
- * <li>http://xml.org/sax/features/validation</li>
- * <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
- * <li>http://apache.org/xml/properties/internal/symbol-table</li>
- * <li>http://apache.org/xml/properties/internal/error-reporter</li>
- * <li>http://apache.org/xml/properties/internal/entity-manager</li>
- * </ul>
- *
- * @author Arnaud Le Hors, IBM
- * @author Andy Clark, IBM
- * @author Glenn Marcy, IBM
- * @author Eric Ye, IBM
- *
- * @version $Id: XMLDTDScannerImpl.java,v 1.49 2004/02/27 20:36:07 mrglavas Exp $
- */
- public class XMLDTDScannerImpl
- extends XMLScanner
- implements XMLDTDScanner, XMLComponent, XMLEntityHandler {
-
- //
- // Constants
- //
-
- // scanner states
-
- /** Scanner state: end of input. */
- protected static final int SCANNER_STATE_END_OF_INPUT = 0;
-
- /** Scanner state: text declaration. */
- protected static final int SCANNER_STATE_TEXT_DECL = 1;
-
- /** Scanner state: markup declaration. */
- protected static final int SCANNER_STATE_MARKUP_DECL = 2;
-
- // recognized features and properties
-
- /** Recognized features. */
- private static final String[] RECOGNIZED_FEATURES = {
- VALIDATION,
- NOTIFY_CHAR_REFS,
- };
-
- /** Feature defaults. */
- private static final Boolean[] FEATURE_DEFAULTS = {
- null,
- Boolean.FALSE,
- };
-
- /** Recognized properties. */
- private static final String[] RECOGNIZED_PROPERTIES = {
- SYMBOL_TABLE,
- ERROR_REPORTER,
- ENTITY_MANAGER,
- };
-
- /** Property defaults. */
- private static final Object[] PROPERTY_DEFAULTS = {
- null,
- null,
- null,
- };
-
- // debugging
-
- /** Debug scanner state. */
- private static final boolean DEBUG_SCANNER_STATE = false;
-
- //
- // Data
- //
-
- // handlers
-
- /** DTD handler. */
- protected XMLDTDHandler fDTDHandler;
-
- /** DTD content model handler. */
- protected XMLDTDContentModelHandler fDTDContentModelHandler;
-
- // state
-
- /** Scanner state. */
- protected int fScannerState;
-
- /** Standalone. */
- protected boolean fStandalone;
-
- /** Seen external DTD. */
- protected boolean fSeenExternalDTD;
-
- /** Seen external parameter entity. */
- protected boolean fSeenExternalPE;
-
- // private data
-
- /** Start DTD called. */
- private boolean fStartDTDCalled;
-
- /** Default attribute */
- private XMLAttributesImpl fAttributes = new XMLAttributesImpl();
-
- /**
- * Stack of content operators (either '|' or ',') in children
- * content.
- */
- private int[] fContentStack = new int[5];
-
- /** Size of content stack. */
- private int fContentDepth;
-
- /** Parameter entity stack to check well-formedness. */
- private int[] fPEStack = new int[5];
-
-
- /** Parameter entity stack to report start/end entity calls. */
- private boolean[] fPEReport = new boolean[5];
-
- /** Number of opened parameter entities. */
- private int fPEDepth;
-
- /** Markup depth. */
- private int fMarkUpDepth;
-
- /** Number of opened external entities. */
- private int fExtEntityDepth;
-
- /** Number of opened include sections. */
- private int fIncludeSectDepth;
-
- // temporary variables
-
- /** Array of 3 strings. */
- private String[] fStrings = new String[3];
-
- /** String. */
- private XMLString fString = new XMLString();
-
- /** String buffer. */
- private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
-
- /** String buffer. */
- private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
-
- /** Literal text. */
- private XMLString fLiteral = new XMLString();
-
- /** Literal text. */
- private XMLString fLiteral2 = new XMLString();
-
- /** Enumeration values. */
- private String[] fEnumeration = new String[5];
-
- /** Enumeration values count. */
- private int fEnumerationCount;
-
- /** Ignore conditional section buffer. */
- private XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(128);
-
- //
- // Constructors
- //
-
- /** Default constructor. */
- public XMLDTDScannerImpl() {} // <init>()
-
- /** Constructor for he use of non-XMLComponentManagers. */
- public XMLDTDScannerImpl(SymbolTable symbolTable,
- XMLErrorReporter errorReporter, XMLEntityManager entityManager) {
- fSymbolTable = symbolTable;
- fErrorReporter = errorReporter;
- fEntityManager = entityManager;
- entityManager.setProperty(SYMBOL_TABLE, fSymbolTable);
- }
-
- //
- // XMLDTDScanner methods
- //
-
- /**
- * Sets the input source.
- *
- * @param inputSource The input source or null.
- *
- * @throws IOException Thrown on i/o error.
- */
- public void setInputSource(XMLInputSource inputSource) throws IOException {
- if (inputSource == null) {
- // no system id was available
- if (fDTDHandler != null) {
- fDTDHandler.startDTD(null, null);
- fDTDHandler.endDTD(null);
- }
- return;
- }
- fEntityManager.setEntityHandler(this);
- fEntityManager.startDTDEntity(inputSource);
- } // setInputSource(XMLInputSource)
-
- /**
- * Scans the external subset of the document.
- *
- * @param complete True if the scanner should scan the document
- * completely, pushing all events to the registered
- * document handler. A value of false indicates that
- * that the scanner should only scan the next portion
- * of the document and return. A scanner instance is
- * permitted to completely scan a document if it does
- * not support this "pull" scanning model.
- *
- * @return True if there is more to scan, false otherwise.
- */
- public boolean scanDTDExternalSubset(boolean complete)
- throws IOException, XNIException {
-
- fEntityManager.setEntityHandler(this);
- if (fScannerState == SCANNER_STATE_TEXT_DECL) {
- fSeenExternalDTD = true;
- boolean textDecl = scanTextDecl();
- if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
- return false;
- }
- else {
- // next state is markup decls regardless of whether there
- // is a TextDecl or not
- setScannerState(SCANNER_STATE_MARKUP_DECL);
- if (textDecl && !complete) {
- return true;
- }
- }
- }
- // keep dispatching "events"
- do {
- if (!scanDecls(complete)) {
- return false;
- }
- } while (complete);
-
- // return that there is more to scan
- return true;
-
- } // scanDTDExternalSubset(boolean):boolean
-
- /**
- * Scans the internal subset of the document.
- *
- * @param complete True if the scanner should scan the document
- * completely, pushing all events to the registered
- * document handler. A value of false indicates that
- * that the scanner should only scan the next portion
- * of the document and return. A scanner instance is
- * permitted to completely scan a document if it does
- * not support this "pull" scanning model.
- * @param standalone True if the document was specified as standalone.
- * This value is important for verifying certain
- * well-formedness constraints.
- * @param hasExternalDTD True if the document has an external DTD.
- * This allows the scanner to properly notify
- * the handler of the end of the DTD in the
- * absence of an external subset.
- *
- * @return True if there is more to scan, false otherwise.
- */
- public boolean scanDTDInternalSubset(boolean complete, boolean standalone,
- boolean hasExternalSubset)
- throws IOException, XNIException {
- // reset entity scanner
- fEntityScanner = fEntityManager.getEntityScanner();
- fEntityManager.setEntityHandler(this);
- fStandalone = standalone;
- if (fScannerState == SCANNER_STATE_TEXT_DECL) {
- // call handler
- if (fDTDHandler != null) {
- fDTDHandler.startDTD(fEntityScanner, null);
- fStartDTDCalled = true;
- }
- // set starting state for internal subset
- setScannerState(SCANNER_STATE_MARKUP_DECL);
- }
- // keep dispatching "events"
- do {
- if (!scanDecls(complete)) {
- // call handler
- if (fDTDHandler != null && hasExternalSubset == false) {
- fDTDHandler.endDTD(null);
- }
- // we're done, set starting state for external subset
- setScannerState(SCANNER_STATE_TEXT_DECL);
- return false;
- }
- } while (complete);
-
- // return that there is more to scan
- return true;
-
- } // scanDTDInternalSubset(boolean,boolean,boolean):boolean
-
- //
- // XMLComponent methods
- //
-
- /**
- * reset
- *
- * @param componentManager
- */
- public void reset(XMLComponentManager componentManager)
- throws XMLConfigurationException {
-
- super.reset(componentManager);
- init();
-
- } // reset(XMLComponentManager)
-
- // this is made for something like XMLDTDLoader--XMLComponentManager-free operation...
- public void reset() {
- super.reset();
- init();
- }
-
- /**
- * Returns a list of feature identifiers that are recognized by
- * this component. This method may return null if no features
- * are recognized by this component.
- */
- public String[] getRecognizedFeatures() {
- return (String[])(RECOGNIZED_FEATURES.clone());
- } // getRecognizedFeatures():String[]
-
- /**
- * Returns a list of property identifiers that are recognized by
- * this component. This method may return null if no properties
- * are recognized by this component.
- */
- public String[] getRecognizedProperties() {
- return (String[])(RECOGNIZED_PROPERTIES.clone());
- } // getRecognizedProperties():String[]
-
- /**
- * Returns the default state for a feature, or null if this
- * component does not want to report a default value for this
- * feature.
- *
- * @param featureId The feature identifier.
- *
- * @since Xerces 2.2.0
- */
- public Boolean getFeatureDefault(String featureId) {
- for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
- if (RECOGNIZED_FEATURES[i].equals(featureId)) {
- return FEATURE_DEFAULTS[i];
- }
- }
- return null;
- } // getFeatureDefault(String):Boolean
-
- /**
- * Returns the default state for a property, or null if this
- * component does not want to report a default value for this
- * property.
- *
- * @param propertyId The property identifier.
- *
- * @since Xerces 2.2.0
- */
- public Object getPropertyDefault(String propertyId) {
- for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
- if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
- return PROPERTY_DEFAULTS[i];
- }
- }
- return null;
- } // getPropertyDefault(String):Object
-
- //
- // XMLDTDSource methods
- //
-
- /**
- * setDTDHandler
- *
- * @param dtdHandler
- */
- public void setDTDHandler(XMLDTDHandler dtdHandler) {
- fDTDHandler = dtdHandler;
- } // setDTDHandler(XMLDTDHandler)
-
- /**
- * getDTDHandler
- *
- * @return the XMLDTDHandler
- */
- public XMLDTDHandler getDTDHandler() {
- return fDTDHandler;
- } // getDTDHandler(): XMLDTDHandler
-
- //
- // XMLDTDContentModelSource methods
- //
-
- /**
- * setDTDContentModelHandler
- *
- * @param dtdContentModelHandler
- */
- public void setDTDContentModelHandler(XMLDTDContentModelHandler
- dtdContentModelHandler) {
- fDTDContentModelHandler = dtdContentModelHandler;
- } // setDTDContentModelHandler
-
- /**
- * getDTDContentModelHandler
- *
- * @return XMLDTDContentModelHandler
- */
- public XMLDTDContentModelHandler getDTDContentModelHandler() {
- return fDTDContentModelHandler ;
- } // setDTDContentModelHandler
-
- //
- // XMLEntityHandler methods
- //
-
- /**
- * This method notifies of the start of an entity. The DTD has the
- * pseudo-name of "[dtd]" parameter entity names start with '%'; and
- * general entities are just specified by their name.
- *
- * @param name The name of the entity.
- * @param identifier The resource identifier.
- * @param encoding The auto-detected IANA encoding name of the entity
- * stream. This value will be null in those situations
- * where the entity encoding is not auto-detected (e.g.
- * internal entities or a document entity that is
- * parsed from a java.io.Reader).
- * @param augs Additional information that may include infoset augmentations
- *
- * @throws XNIException Thrown by handler to signal an error.
- */
- public void startEntity(String name,
- XMLResourceIdentifier identifier,
- String encoding, Augmentations augs) throws XNIException {
-
- super.startEntity(name, identifier, encoding, augs);
-
- boolean dtdEntity = name.equals("[dtd]");
- if (dtdEntity) {
- // call handler
- if (fDTDHandler != null && !fStartDTDCalled ) {
- fDTDHandler.startDTD(fEntityScanner, null);
- }
- if (fDTDHandler != null) {
- fDTDHandler.startExternalSubset(identifier,null);
- }
- fEntityManager.startExternalSubset();
- fExtEntityDepth++;
- }
- else if (name.charAt(0) == '%') {
- pushPEStack(fMarkUpDepth, fReportEntity);
- if (fEntityScanner.isExternal()) {
- fExtEntityDepth++;
- }
- }
-
- // call handler
- if (fDTDHandler != null && !dtdEntity && fReportEntity) {
- fDTDHandler.startParameterEntity(name, identifier, encoding, augs);
- }
-
- } // startEntity(String,XMLResourceIdentifier,String)
-
- /**
- * This method notifies the end of an entity. The DTD has the pseudo-name
- * of "[dtd]" parameter entity names start with '%'; and general entities
- * are just specified by their name.
- *
- * @param name The name of the entity.
- * @param augs Additional information that may include infoset augmentations
- *
- * @throws XNIException Thrown by handler to signal an error.
- */
- public void endEntity(String name, Augmentations augs)
- throws XNIException {
-
- super.endEntity(name, augs);
-
- // if there is no data after the doctype
- //
- if (fScannerState == SCANNER_STATE_END_OF_INPUT)
- return;
-
- // Handle end of PE
- boolean reportEntity = fReportEntity;
- if (name.startsWith("%")) {
- reportEntity = peekReportEntity();
- // check well-formedness of the enity
- int startMarkUpDepth = popPEStack();
- // throw fatalError if this entity was incomplete and
- // was a freestanding decl
- if(startMarkUpDepth == 0 &&
- startMarkUpDepth < fMarkUpDepth) {
- fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
- "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL",
- new Object[]{ fEntityManager.fCurrentEntity.name},
- XMLErrorReporter.SEVERITY_FATAL_ERROR);
- }
- if (startMarkUpDepth != fMarkUpDepth) {
- reportEntity = false;
- if (fValidation) {
- // Proper nesting of parameter entities is a Validity Constraint
- // and must not be enforced when validation is off
- fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
- "ImproperDeclarationNesting",
- new Object[]{ name },
- XMLErrorReporter.SEVERITY_ERROR);
- }
- }
- if (fEntityScanner.isExternal()) {
- fExtEntityDepth--;
- }
- }
-
- // call handler
- boolean dtdEntity = name.equals("[dtd]");
- if (fDTDHandler != null && !dtdEntity && reportEntity) {
- fDTDHandler.endParameterEntity(name, augs);
- }
-
- // end DTD
- if (dtdEntity) {
- if (fIncludeSectDepth != 0) {
- reportFatalError("IncludeSectUnterminated", null);
- }
- fScannerState = SCANNER_STATE_END_OF_INPUT;
- // call handler
- fEntityManager.endExternalSubset();
- if (fDTDHandler != null) {
- fDTDHandler.endExternalSubset(null);
- fDTDHandler.endDTD(null);
- }
- fExtEntityDepth--;
- }
-
- } // endEntity(String)
-
- // helper methods
-
- /**
- * Sets the scanner state.
- *
- * @param state The new scanner state.
- */
- protected final void setScannerState(int state) {
-
- fScannerState = state;
- if (DEBUG_SCANNER_STATE) {
- System.out.print("### setScannerState: ");
- System.out.print(getScannerStateName(state));
- System.out.println();
- }
-
- } // setScannerState(int)
-
- //
- // Private methods
- //
-
- /** Returns the scanner state name. */
- private static String getScannerStateName(int state) {
-
- if (DEBUG_SCANNER_STATE) {
- switch (state) {
- case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT";
- case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL";
- case SCANNER_STATE_MARKUP_DECL: return "SCANNER_STATE_MARKUP_DECL";
- }
- }
-
- return "??? ("+state+')';
-
- } // getScannerStateName(int):String
-
- protected final boolean scanningInternalSubset() {
- return fExtEntityDepth == 0;
- }
-
- /**
- * start a parameter entity dealing with the textdecl if there is any
- *
- * @param name The name of the parameter entity to start (without the '%')
- * @param literal Whether this is happening within a literal
- */
- protected void startPE(String name, boolean literal)
- throws IOException, XNIException {
- int depth = fPEDepth;
- String pName = "%"+name;
- if (fValidation && !fEntityManager.isDeclaredEntity(pName)) {
- fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared",
- new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR);
- }
- fEntityManager.startEntity(fSymbolTable.addSymbol(pName),
- literal);
- // if we actually got a new entity and it's external
- // parse text decl if there is any
- if (depth != fPEDepth && fEntityScanner.isExternal()) {
- scanTextDecl();
- }
- }
-
- /**
- * Dispatch an XML "event".
- *
- * @param complete True if this method is intended to scan
- * and dispatch as much as possible.
- *
- * @return True if a TextDecl was scanned.
- *
- * @throws IOException Thrown on i/o error.
- * @throws XNIException Thrown on parse error.
- *
- */
- protected final boolean scanTextDecl()
- throws IOException, XNIException {
-
- // scan XMLDecl
- boolean textDecl = false;
- if (fEntityScanner.skipString("<?xml")) {
- fMarkUpDepth++;
- // NOTE: special case where document starts with a PI
- // whose name starts with "xml" (e.g. "xmlfoo")
- if (isValidNameChar(fEntityScanner.peekChar())) {
- fStringBuffer.clear();
- fStringBuffer.append("xml");
- if (fNamespaces) {
- while (isValidNCName(fEntityScanner.peekChar())) {
- fStringBuffer.append((char)fEntityScanner.scanChar());
- }
- }
- else {
- while (isValidNameChar(fEntityScanner.peekChar())) {
- fStringBuffer.append((char)fEntityScanner.scanChar());
- }
- }
- String target =
- fSymbolTable.addSymbol(fStringBuffer.ch,
- fStringBuffer.offset,
- fStringBuffer.length);
- scanPIData(target, fString);
- }
-
- // standard Text declaration
- else {
- // pseudo-attribute values
- String version = null;
- String encoding = null;
-
- scanXMLDeclOrTextDecl(true, fStrings);
- textDecl = true;
- fMarkUpDepth--;
-
- version = fStrings[0];
- encoding = fStrings[1];
-
- fEntityScanner.setEncoding(encoding);
-
- // call handler
- if (fDTDHandler != null) {
- fDTDHandler.textDecl(version, encoding, null);
- }
- }
- }
- fEntityManager.fCurrentEntity.mayReadChunks = true;
-
- return textDecl;
-
- } // scanTextDecl(boolean):boolean
-
- /**
- * Scans a processing data. This is needed to handle the situation
- * where a document starts with a processing instruction whose
- * target name <em>starts with</em> "xml". (e.g. xmlfoo)
- *
- * @param target The PI target
- * @param data The string to fill in with the data
- */
- protected final void scanPIData(String target, XMLString data)
- throws IOException, XNIException {
-
- super.scanPIData(target, data);
- fMarkUpDepth--;
-
- // call handler
- if (fDTDHandler != null) {
- fDTDHandler.processingInstruction(target, data, null);
- }
-
- } // scanPIData(String)
-
- /**
- * Scans a comment.
- * <p>
- * <pre>
- * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
- * </pre>
- * <p>
- * <strong>Note:</strong> Called after scanning past '<!--'
- */
- protected final void scanComment() throws IOException, XNIException {
-
- fReportEntity = false;
- scanComment(fStringBuffer);
- fMarkUpDepth--;
-
- // call handler
- if (fDTDHandler != null) {
- fDTDHandler.comment(fStringBuffer, null);
- }
- fReportEntity = true;
-
- } // scanComment()
-
- /**
- * Scans an element declaration
- * <p>
- * <pre>
- * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
- * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
- * </pre>
- * <p>
- * <strong>Note:</strong> Called after scanning past '<!ELEMENT'
- */
- protected final void scanElementDecl() throws IOException, XNIException {
-
- // spaces
- fReportEntity = false;
- if (!skipSeparator(true, !scanningInternalSubset())) {
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL",
- null);
- }
-
- // element name
- String name = fEntityScanner.scanName();
- if (name == null) {
- reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL",
- null);
- }
-
- // spaces
- if (!skipSeparator(true, !scanningInternalSubset())) {
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL",
- new Object[]{name});
- }
-
- // content model
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.startContentModel(name, null);
- }
- String contentModel = null;
- fReportEntity = true;
- if (fEntityScanner.skipString("EMPTY")) {
- contentModel = "EMPTY";
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.empty(null);
- }
- }
- else if (fEntityScanner.skipString("ANY")) {
- contentModel = "ANY";
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.any(null);
- }
- }
- else {
- if (!fEntityScanner.skipChar('(')) {
- reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
- new Object[]{name});
- }
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.startGroup(null);
- }
- fStringBuffer.clear();
- fStringBuffer.append('(');
- fMarkUpDepth++;
- skipSeparator(false, !scanningInternalSubset());
-
- // Mixed content model
- if (fEntityScanner.skipString("#PCDATA")) {
- scanMixed(name);
- }
- else { // children content
- scanChildren(name);
- }
- contentModel = fStringBuffer.toString();
- }
-
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.endContentModel(null);
- }
-
- fReportEntity = false;
- skipSeparator(false, !scanningInternalSubset());
- // end
- if (!fEntityScanner.skipChar('>')) {
- reportFatalError("ElementDeclUnterminated", new Object[]{name});
- }
- fReportEntity = true;
- fMarkUpDepth--;
-
- // call handler
- if (fDTDHandler != null) {
- fDTDHandler.elementDecl(name, contentModel, null);
- }
-
- } // scanElementDecl()
-
- /**
- * scan Mixed content model
- * This assumes the content model has been parsed up to #PCDATA and
- * can simply append to fStringBuffer.
- * <pre>
- * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
- * | '(' S? '#PCDATA' S? ')'
- * </pre>
- *
- * @param elName The element type name this declaration is about.
- *
- * <strong>Note:</strong> Called after scanning past '(#PCDATA'.
- */
- private final void scanMixed(String elName)
- throws IOException, XNIException {
-
- String childName = null;
-
- fStringBuffer.append("#PCDATA");
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.pcdata(null);
- }
- skipSeparator(false, !scanningInternalSubset());
- while (fEntityScanner.skipChar('|')) {
- fStringBuffer.append('|');
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
- null);
- }
- skipSeparator(false, !scanningInternalSubset());
-
- childName = fEntityScanner.scanName();
- if (childName == null) {
- reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT",
- new Object[]{elName});
- }
- fStringBuffer.append(childName);
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.element(childName, null);
- }
- skipSeparator(false, !scanningInternalSubset());
- }
- // The following check must be done in a single call (as opposed to one
- // for ')' and then one for '*') to guarantee that callbacks are
- // properly nested. We do not want to trigger endEntity too early in
- // case we cross the boundary of an entity between the two characters.
- if (fEntityScanner.skipString(")*")) {
- fStringBuffer.append(")*");
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.endGroup(null);
- fDTDContentModelHandler.occurrence(XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE,
- null);
- }
- }
- else if (childName != null) {
- reportFatalError("MixedContentUnterminated",
- new Object[]{elName});
- }
- else if (fEntityScanner.skipChar(')')){
- fStringBuffer.append(')');
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.endGroup(null);
- }
- }
- else {
- reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
- new Object[]{elName});
- }
- fMarkUpDepth--;
- // we are done
- }
-
- /**
- * scan children content model
- * This assumes it can simply append to fStringBuffer.
- * <pre>
- * [47] children ::= (choice | seq) ('?' | '*' | '+')?
- * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
- * [49] choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')'
- * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
- * </pre>
- *
- * @param elName The element type name this declaration is about.
- *
- * <strong>Note:</strong> Called after scanning past the first open
- * paranthesis.
- */
- private final void scanChildren(String elName)
- throws IOException, XNIException {
-
- fContentDepth = 0;
- pushContentStack(0);
- int currentOp = 0;
- int c;
- while (true) {
- if (fEntityScanner.skipChar('(')) {
- fMarkUpDepth++;
- fStringBuffer.append('(');
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.startGroup(null);
- }
- // push current op on stack and reset it
- pushContentStack(currentOp);
- currentOp = 0;
- skipSeparator(false, !scanningInternalSubset());
- continue;
- }
- skipSeparator(false, !scanningInternalSubset());
- String childName = fEntityScanner.scanName();
- if (childName == null) {
- reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
- new Object[]{elName});
- return;
- }
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.element(childName, null);
- }
- fStringBuffer.append(childName);
- c = fEntityScanner.peekChar();
- if (c == '?' || c == '*' || c == '+') {
- // call handler
- if (fDTDContentModelHandler != null) {
- short oc;
- if (c == '?') {
- oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
- }
- else if (c == '*') {
- oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
- }
- else {
- oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
- }
- fDTDContentModelHandler.occurrence(oc, null);
- }
- fEntityScanner.scanChar();
- fStringBuffer.append((char)c);
- }
- while (true) {
- skipSeparator(false, !scanningInternalSubset());
- c = fEntityScanner.peekChar();
- if (c == ',' && currentOp != '|') {
- currentOp = c;
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE,
- null);
- }
- fEntityScanner.scanChar();
- fStringBuffer.append(',');
- break;
- }
- else if (c == '|' && currentOp != ',') {
- currentOp = c;
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
- null);
- }
- fEntityScanner.scanChar();
- fStringBuffer.append('|');
- break;
- }
- else if (c != ')') {
- reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
- new Object[]{elName});
- }
- // call handler
- if (fDTDContentModelHandler != null) {
- fDTDContentModelHandler.endGroup(null);
- }
- // restore previous op
- currentOp = popContentStack();
- short oc;
- // The following checks must be done in a single call (as
- // opposed to one for ')' and then one for '?', '*', and '+')
- // to guarantee that callbacks are properly nested. We do not
- // want to trigger endEntity too early in case we cross the
- // boundary of an entity between the two characters.
- if (fEntityScanner.skipString(")?")) {
- fStringBuffer.append(")?");
- // call handler
- if (fDTDContentModelHandler != null) {
- oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
- fDTDContentModelHandler.occurrence(oc, null);
- }
- }
- else if (fEntityScanner.skipString(")+")) {
- fStringBuffer.append(")+");
- // call handler
- if (fDTDContentModelHandler != null) {
- oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
- fDTDContentModelHandler.occurrence(oc, null);
- }
- }
- else if (fEntityScanner.skipString(")*")) {
- fStringBuffer.append(")*");
- // call handler
- if (fDTDContentModelHandler != null) {
- oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
- fDTDContentModelHandler.occurrence(oc, null);
- }
- }
- else {
- // no occurrence specified
- fEntityScanner.scanChar();
- fStringBuffer.append(')');
- }
- fMarkUpDepth--;
- if (fContentDepth == 0) {
- return;
- }
- }
- skipSeparator(false, !scanningInternalSubset());
- }
- }
-
- /**
- * Scans an attlist declaration
- * <p>
- * <pre>
- * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
- * [53] AttDef ::= S Name S AttType S DefaultDecl
- * </pre>
- * <p>
- * <strong>Note:</strong> Called after scanning past '<!ATTLIST'
- */
- protected final void scanAttlistDecl() throws IOException, XNIException {
-
- // spaces
- fReportEntity = false;
- if (!skipSeparator(true, !scanningInternalSubset())) {
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL",
- null);
- }
-
- // element name
- String elName = fEntityScanner.scanName();
- if (elName == null) {
- reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL",
- null);
- }
-
- // call handler
- if (fDTDHandler != null) {
- fDTDHandler.startAttlist(elName, null);
- }
-
- // spaces
- if (!skipSeparator(true, !scanningInternalSubset())) {
- // no space, is it the end yet?
- if (fEntityScanner.skipChar('>')) {
- // yes, stop here
- // call handler
- if (fDTDHandler != null) {
- fDTDHandler.endAttlist(null);
- }
- fMarkUpDepth--;
- return;
- }
- else {
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF",
- new Object[]{elName});
- }
- }
-
- // definitions
- while (!fEntityScanner.skipChar('>')) {
- String name = fEntityScanner.scanName();
- if (name == null) {
- reportFatalError("AttNameRequiredInAttDef",
- new Object[]{elName});
- }
- // spaces
- if (!skipSeparator(true, !scanningInternalSubset())) {
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF",
- new Object[]{elName, name});
- }
- // type
- String type = scanAttType(elName, name);
-
- // spaces
- if (!skipSeparator(true, !scanningInternalSubset())) {
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF",
- new Object[]{elName, name});
- }
-
- // default decl
- String defaultType = scanAttDefaultDecl(elName, name,
- type,
- fLiteral, fLiteral2);
- // REVISIT: Should we do anything with the non-normalized
- // default attribute value? -Ac
- // yes--according to bug 5073. - neilg
-
- // call handler
- if (fDTDHandler != null) {
- String[] enumeration = null;
- if (fEnumerationCount != 0) {
- enumeration = new String[fEnumerationCount];
- System.arraycopy(fEnumeration, 0, enumeration,
- 0, fEnumerationCount);
- }
- // Determine whether the default value to be passed should be null.
- // REVISIT: should probably check whether fLiteral.ch is null instead. LM.
- if (defaultType!=null && (defaultType.equals("#REQUIRED") ||
- defaultType.equals("#IMPLIED"))) {
- fDTDHandler.attributeDecl(elName, name, type, enumeration,
- defaultType, null, null, null);
- }
- else {
- fDTDHandler.attributeDecl(elName, name, type, enumeration,
- defaultType, fLiteral, fLiteral2, null);
- }
- }
- skipSeparator(false, !scanningInternalSubset());
- }
-
- // call handler
- if (fDTDHandler != null) {
- fDTDHandler.endAttlist(null);
- }
- fMarkUpDepth--;
- fReportEntity = true;
-
- } // scanAttlistDecl()
-
- /**
- * Scans an attribute type definition
- * <p>
- * <pre>
- * [54] AttType ::= StringType | TokenizedType | EnumeratedType
- * [55] StringType ::= 'CDATA'
- * [56] TokenizedType ::= 'ID'
- * | 'IDREF'
- * | 'IDREFS'
- * | 'ENTITY'
- * | 'ENTITIES'
- * | 'NMTOKEN'
- * | 'NMTOKENS'
- * [57] EnumeratedType ::= NotationType | Enumeration
- * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
- * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
- * </pre>
- * <p>
- * <strong>Note:</strong> Called after scanning past '<!ATTLIST'
- *
- * @param elName The element type name this declaration is about.
- * @param atName The attribute name this declaration is about.
- */
- private final String scanAttType(String elName, String atName)
- throws IOException, XNIException {
-
- String type = null;
- fEnumerationCount = 0;
- /*
- * Watchout: the order here is important: when a string happens to
- * be a substring of another string, the longer one needs to be
- * looked for first!!
- */
- if (fEntityScanner.skipString("CDATA")) {
- type = "CDATA";
- }
- else if (fEntityScanner.skipString("IDREFS")) {
- type = "IDREFS";
- }
- else if (fEntityScanner.skipString("IDREF")) {
- type = "IDREF";
- }
- else if (fEntityScanner.skipString("ID")) {
- type = "ID";
- }
- else if (fEntityScanner.skipString("ENTITY")) {
- type = "ENTITY";
- }
- else if (fEntityScanner.skipString("ENTITIES")) {
- type = "ENTITIES";
- }
- else if (fEntityScanner.skipString("NMTOKENS")) {
- type = "NMTOKENS";
- }
- else if (fEntityScanner.skipString("NMTOKEN")) {
- type = "NMTOKEN";
- }
- else if (fEntityScanner.skipString("NOTATION")) {
- type = "NOTATION";
- // spaces
- if (!skipSeparator(true, !scanningInternalSubset())) {
- reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE",
- new Object[]{elName, atName});
- }
- // open paren
- int c = fEntityScanner.scanChar();
- if (c != '(') {
- reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE",
- new Object[]{elName, atName});
- }
- fMarkUpDepth++;
- do {
- skipSeparator(false, !scanningInternalSubset());
- String aName = fEntityScanner.scanName();
- if (aName == null) {
- reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE",
- new Object[]{elName, atName});
- }
- ensureEnumerationSize(fEnumerationCount + 1);
- fEnumeration[fEnumerationCount++] = aName;
- skipSeparator(false, !scanningInternalSubset());
- c = fEntityScanner.scanChar();
- } while (c == '|');
- if (c != ')') {
- reportFatalError("NotationTypeUnterminated",
- new Object[]{elName, atName});
- }
- fMarkUpDepth--;
- }
- else { // Enumeration
- type = "ENUMERATION";
- // open paren
- int c = fEntityScanner.scanChar();
- if (c != '(') {
- // "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL",
- reportFatalError("AttTypeRequiredInAttDef",
- new Object[]{elName, atName});
- }
- fMarkUpDepth++;
- do {
- skipSeparator(false, !scanningInternalSubset());
- String token = fEntityScanner.scanNmtoken();
- if (token == null) {
- reportFatalError("MSG_NMTOKEN_REQUIRED_IN_ENUMERATION",
- new Object[]{elName, atName});
- }
- ensureEnumerationSize(fEnumerationCount + 1);
- fEnumeration[fEnumerationCount++] = token;
- skipSeparator(false, !scanningInternalSubset());
- c = fEntityScanner.scanChar();
- } while (c == '|');
- if (c != ')') {
- reportFatalError("EnumerationUnterminated",
- new Object[]{elName, atName});
- }
- fMarkUpDepth--;
- }
- return type;
-
- } // scanAttType():String
-
-
- /**
- * Scans an attribute default declaration
- * <p>
- * <pre>
- * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
- * </pre>
- *
- * @param name The name of the attribute being scanned.
- * @param defaultVal The string to fill in with the default value.
- */
- protected final String scanAttDefaultDecl(String elName, String atName,
- String type,
- XMLString defaultVal,
- XMLString nonNormalizedDefaultVal)
- throws IOException, XNIException {
-
- String defaultType = null;
- fString.clear();
- defaultVal.clear();
- if (fEntityScanner.skipString("#REQUIRED")) {
- defaultType = "#REQUIRED";
- }
- else if (fEntityScanner.skipString("#IMPLIED")) {
- defaultType = "#IMPLIED";
- }
- else {
- if (fEntityScanner.skipString("#FIXED")) {
- defaultType = "#FIXED";
- // spaces
- if (!skipSeparator(true, !scanningInternalSubset())) {
- reportFatalError("MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL",
- new Object[]{elName, atName});
- }
- }
- // AttValue
- boolean isVC = !fStandalone && (fSeenExternalDTD || fSeenExternalPE) ;
- scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName, isVC, elName);
- }
- return defaultType;
-
- } // ScanAttDefaultDecl
-
- /**
- * Scans an entity declaration
- * <p>
- * <pre>
- * [70] EntityDecl ::= GEDecl | PEDecl
- * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
- * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
- * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
- * [74] PEDef ::= EntityValue | ExternalID
- * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
- * | 'PUBLIC' S PubidLiteral S SystemLiteral
- * [76] NDataDecl ::= S 'NDATA' S Name
- * </pre>
- * <p>
- * <strong>Note:</strong> Called after scanning past '<!ENTITY'
- */
- private final void scanEntityDecl() throws IOException, XNIException {
-
- boolean isPEDecl = false;
- boolean sawPERef = false;
- fReportEntity = false;
- if (fEntityScanner.skipSpaces()) {
- if (!fEntityScanner.skipChar('%')) {
- isPEDecl = false; // <!ENTITY x "x">
- }
- else if (skipSeparator(true, !scanningInternalSubset())) {
- // <!ENTITY % x "x">
- isPEDecl = true;
- }
- else if (scanningInternalSubset()) {
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
- null);
- isPEDecl = true;
- }
- else if (fEntityScanner.peekChar() == '%') {
- // <!ENTITY %%x; "x"> is legal
- skipSeparator(false, !scanningInternalSubset());
- isPEDecl = true;
- }
- else {
- sawPERef = true;
- }
- }
- else if (scanningInternalSubset() || !fEntityScanner.skipChar('%')) {
- // <!ENTITY[^ ]...> or <!ENTITY[^ %]...>
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
- null);
- isPEDecl = false;
- }
- else if (fEntityScanner.skipSpaces()) {
- // <!ENTITY% ...>
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL",
- null);
- isPEDecl = false;
- }
- else {
- sawPERef = true;
- }
- if (sawPERef) {
- while (true) {
- String peName = fEntityScanner.scanName();
- if (peName == null) {
- reportFatalError("NameRequiredInPEReference", null);
- }
- else if (!fEntityScanner.skipChar(';')) {
- reportFatalError("SemicolonRequiredInPEReference",
- new Object[]{peName});
- }
- else {
- startPE(peName, false);
- }
- fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('%'))
- break;
- if (!isPEDecl) {
- if (skipSeparator(true, !scanningInternalSubset())) {
- isPEDecl = true;
- break;
- }
- isPEDecl = fEntityScanner.skipChar('%');
- }
- }
- }
-
- // name
- String name = null;
- if(fNamespaces) {
- name = fEntityScanner.scanNCName();
- } else {
- name = fEntityScanner.scanName();
- }
- if (name == null) {
- reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null);
- }
- // spaces
- if (!skipSeparator(true, !scanningInternalSubset())) {
- if(fNamespaces && fEntityScanner.peekChar() == ':') {
- fEntityScanner.scanChar();
- XMLStringBuffer colonName = new XMLStringBuffer(name);
- colonName.append(":");
- String str = fEntityScanner.scanName();
- if (str != null)
- colonName.append(str);
- reportFatalError("ColonNotLegalWithNS", new Object[] {colonName.toString()});
- if (!skipSeparator(true, !scanningInternalSubset())) {
- reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL",
- new Object[]{name});
- }
- } else {
- reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL",
- new Object[]{name});
- }
- }
-
- // external id
- scanExternalID(fStrings, false);
- String systemId = fStrings[0];
- String publicId = fStrings[1];
-
- if (isPEDecl && systemId != null) {
- fSeenExternalPE = true;
- }
-
- String notation = null;
- // NDATA
- boolean sawSpace = skipSeparator(true, !scanningInternalSubset());
- if (!isPEDecl && fEntityScanner.skipString("NDATA")) {
- // check whether there was space before NDATA
- if (!sawSpace) {
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL",
- new Object[]{name});
- }
-
- // spaces
- if (!skipSeparator(true, !scanningInternalSubset())) {
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL",
- new Object[]{name});
- }
- notation = fEntityScanner.scanName();
- if (notation == null) {
- reportFatalError("MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL",
- new Object[]{name});
- }
- }
-
- // internal entity
- if (systemId == null) {
- scanEntityValue(fLiteral, fLiteral2);
- // since we need it's value anyway, let's snag it so it doesn't get corrupted
- // if a new load takes place before we store the entity values
- fStringBuffer.clear();
- fStringBuffer2.clear();
- fStringBuffer.append(fLiteral.ch, fLiteral.offset, fLiteral.length);
- fStringBuffer2.append(fLiteral2.ch, fLiteral2.offset, fLiteral2.length);
- }
-
- // skip possible trailing space
- skipSeparator(false, !scanningInternalSubset());
-
- // end
- if (!fEntityScanner.skipChar('>')) {
- reportFatalError("EntityDeclUnterminated", new Object[]{name});
- }
- fMarkUpDepth--;
-
- // register entity and make callback
- if (isPEDecl) {
- name = "%" + name;
- }
- if (systemId != null) {
- String baseSystemId = fEntityScanner.getBaseSystemId();
- if (notation != null) {
- fEntityManager.addUnparsedEntity(name, publicId, systemId, baseSystemId, notation);
- }
- else {
- fEntityManager.addExternalEntity(name, publicId, systemId,
- baseSystemId);
- }
- if (fDTDHandler != null) {
- fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false));
- if (notation != null) {
- fDTDHandler.unparsedEntityDecl(name, fResourceIdentifier,
- notation, null);
- }
- else {
- fDTDHandler.externalEntityDecl(name, fResourceIdentifier, null);
- }
- }
- }
- else {
- fEntityManager.addInternalEntity(name, fStringBuffer.toString());
- if (fDTDHandler != null) {
- fDTDHandler.internalEntityDecl(name, fStringBuffer, fStringBuffer2, null);
- }
- }
- fReportEntity = true;
-
- } // scanEntityDecl()
-
- /**
- * Scans an entity value.
- *
- * @param value The string to fill in with the value.
- * @param nonNormalizedValue The string to fill in with the
- * non-normalized value.
- *
- * <strong>Note:</strong> This method uses fString, fStringBuffer (through
- * the use of scanCharReferenceValue), and fStringBuffer2, anything in them
- * at the time of calling is lost.
- */
- protected final void scanEntityValue(XMLString value,
- XMLString nonNormalizedValue)
- throws IOException, XNIException
- {
- int quote = fEntityScanner.scanChar();
- if (quote != '\'' && quote != '"') {
- reportFatalError("OpenQuoteMissingInDecl", null);
- }
- // store at which depth of entities we start
- int entityDepth = fEntityDepth;
-
- XMLString literal = fString;
- XMLString literal2 = fString;
- if (fEntityScanner.scanLiteral(quote, fString) != quote) {
- fStringBuffer.clear();
- fStringBuffer2.clear();
- do {
- fStringBuffer.append(fString);
- fStringBuffer2.append(fString);
- if (fEntityScanner.skipChar('&')) {
- if (fEntityScanner.skipChar('#')) {
- fStringBuffer2.append("");
- scanCharReferenceValue(fStringBuffer, fStringBuffer2);
- }
- else {
- fStringBuffer.append('&');
- fStringBuffer2.append('&');
- String eName = fEntityScanner.scanName();
- if (eName == null) {
- reportFatalError("NameRequiredInReference",
- null);
- }
- else {
- fStringBuffer.append(eName);
- fStringBuffer2.append(eName);
- }
- if (!fEntityScanner.skipChar(';')) {
- reportFatalError("SemicolonRequiredInReference",
- new Object[]{eName});
- }
- else {
- fStringBuffer.append(';');
- fStringBuffer2.append(';');
- }
- }
- }
- else if (fEntityScanner.skipChar('%')) {
- while (true) {
- fStringBuffer2.append('%');
- String peName = fEntityScanner.scanName();
- if (peName == null) {
- reportFatalError("NameRequiredInPEReference",
- null);
- }
- else if (!fEntityScanner.skipChar(';')) {
- reportFatalError("SemicolonRequiredInPEReference",
- new Object[]{peName});
- }
- else {
- if (scanningInternalSubset()) {
- reportFatalError("PEReferenceWithinMarkup",
- new Object[]{peName});
- }
- fStringBuffer2.append(peName);
- fStringBuffer2.append(';');
- }
- startPE(peName, true);
- // REVISIT: [Q] Why do we skip spaces here? -Ac
- // REVISIT: This will make returning the non-
- // normalized value harder. -Ac
- fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('%'))
- break;
- }
- }
- else {
- int c = fEntityScanner.peekChar();
- if (XMLChar.isHighSurrogate(c)) {
- scanSurrogates(fStringBuffer2);
- }
- else if (isInvalidLiteral(c)) {
- reportFatalError("InvalidCharInLiteral",
- new Object[]{Integer.toHexString(c)});
- fEntityScanner.scanChar();
- }
- // if it's not the delimiting quote or if it is but from a
- // different entity than the one this literal started from,
- // simply append the character to our buffer
- else if (c != quote || entityDepth != fEntityDepth) {
- fStringBuffer.append((char)c);
- fStringBuffer2.append((char)c);
- fEntityScanner.scanChar();
- }
- }
- } while (fEntityScanner.scanLiteral(quote, fString) != quote);
- fStringBuffer.append(fString);
- fStringBuffer2.append(fString);
- literal = fStringBuffer;
- literal2 = fStringBuffer2;
- }
- value.setValues(literal);
- nonNormalizedValue.setValues(literal2);
- if (!fEntityScanner.skipChar(quote)) {
- reportFatalError("CloseQuoteMissingInDecl", null);
- }
- } // scanEntityValue(XMLString,XMLString):void
-
- /**
- * Scans a notation declaration
- * <p>
- * <pre>
- * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID|PublicID) S? '>'
- * [83] PublicID ::= 'PUBLIC' S PubidLiteral
- * </pre>
- * <p>
- * <strong>Note:</strong> Called after scanning past '<!NOTATION'
- */
- private final void scanNotationDecl() throws IOException, XNIException {
-
- // spaces
- fReportEntity = false;
- if (!skipSeparator(true, !scanningInternalSubset())) {
- reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL",
- null);
- }
-
- // notation name
- String name = null;
- if(fNamespaces) {
- name = fEntityScanner.scanNCName();
- } else {
- name = fEntityScanner.scanName();
- }
- if (name == null) {
- reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL",
- null);
- }
-
- // spaces
- if (!skipSeparator(true, !scanningInternalSubset())) {
- // check for invalid ":"
- if(fNamespaces && fEntityScanner.peekChar() == ':') {
- fEntityScanner.scanChar();
- XMLStringBuffer colonName = new XMLStringBuffer(name);
- colonName.append(":");
- colonName.append(fEntityScanner.scanName());
- reportFatalError("ColonNotLegalWithNS", new Object[] {colonName.toString()});
- skipSeparator(true, !scanningInternalSubset());
- } else {
- reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL",
- new Object[]{name});
- }
- }
-
- // external id
- scanExternalID(fStrings, true);
- String systemId = fStrings[0];
- String publicId = fStrings[1];
- String baseSystemId = fEntityScanner.getBaseSystemId();
-
- if (systemId == null && publicId == null) {
- reportFatalError("ExternalIDorPublicIDRequired",
- new Object[]{name});
- }
-
- // skip possible trailing space
- skipSeparator(false, !scanningInternalSubset());
-
- // end
- if (!fEntityScanner.skipChar('>')) {
- reportFatalError("NotationDeclUnterminated", new Object[]{name});
- }
- fMarkUpDepth--;
-
- // call handler
- if (fDTDHandler != null) {
- fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false));
- fDTDHandler.notationDecl(name, fResourceIdentifier, null);
- }
- fReportEntity = true;
-
- } // scanNotationDecl()
-
- /**
- * Scans a conditional section. If it's a section to ignore the whole
- * section gets scanned through and this method only returns after the
- * closing bracket has been found. When it's an include section though, it
- * returns to let the main loop take care of scanning it. In that case the
- * end of the section if handled by the main loop (scanDecls).
- * <p>
- * <pre>
- * [61] conditionalSect ::= includeSect | ignoreSect
- * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
- * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
- * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
- * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
- * </pre>
- * <p>
- * <strong>Note:</strong> Called after scanning past '<![' */
- private final void scanConditionalSect(int currPEDepth)
- throws IOException, XNIException {
-
- fReportEntity = false;
- skipSeparator(false, !scanningInternalSubset());
-
- if (fEntityScanner.skipString("INCLUDE")) {
- skipSeparator(false, !scanningInternalSubset());
- if(currPEDepth != fPEDepth && fValidation) {
- fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
- "INVALID_PE_IN_CONDITIONAL",
- new Object[]{ fEntityManager.fCurrentEntity.name},
- XMLErrorReporter.SEVERITY_ERROR);
- }
- // call handler
- if (!fEntityScanner.skipChar('[')) {
- reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
- }
-
- if (fDTDHandler != null) {
- fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_INCLUDE,
- null);
- }
- fIncludeSectDepth++;
- // just stop there and go back to the main loop
- fReportEntity = true;
- }
- else if (fEntityScanner.skipString("IGNORE")) {
- skipSeparator(false, !scanningInternalSubset());
- if(currPEDepth != fPEDepth && fValidation) {
- fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
- "INVALID_PE_IN_CONDITIONAL",
- new Object[]{ fEntityManager.fCurrentEntity.name},
- XMLErrorReporter.SEVERITY_ERROR);
- }
- // call handler
- if (fDTDHandler != null) {
- fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE,
- null);
- }
- if (!fEntityScanner.skipChar('[')) {
- reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
- }
- fReportEntity = true;
- int initialDepth = ++fIncludeSectDepth;
- if (fDTDHandler != null) {
- fIgnoreConditionalBuffer.clear();
- }
- while (true) {
- if (fEntityScanner.skipChar('<')) {
- if (fDTDHandler != null) {
- fIgnoreConditionalBuffer.append('<');
- }
- //
- // These tests are split so that we handle cases like
- // '<<![' and '<!<![' which we might otherwise miss.
- //
- if (fEntityScanner.skipChar('!')) {
- if(fEntityScanner.skipChar('[')) {
- if (fDTDHandler != null) {
- fIgnoreConditionalBuffer.append("![");
- }
- fIncludeSectDepth++;
- } else {
- if (fDTDHandler != null) {
- fIgnoreConditionalBuffer.append("!");
- }
- }
- }
- }
- else if (fEntityScanner.skipChar(']')) {
- if (fDTDHandler != null) {
- fIgnoreConditionalBuffer.append(']');
- }
- //
- // The same thing goes for ']<![' and '<]]>', etc.
- //
- if (fEntityScanner.skipChar(']')) {
- if (fDTDHandler != null) {
- fIgnoreConditionalBuffer.append(']');
- }
- while (fEntityScanner.skipChar(']')) {
- /* empty loop body */
- if (fDTDHandler != null) {
- fIgnoreConditionalBuffer.append(']');
- }
- }
- if (fEntityScanner.skipChar('>')) {
- if (fIncludeSectDepth-- == initialDepth) {
- fMarkUpDepth--;
- // call handler
- if (fDTDHandler != null) {
- fLiteral.setValues(fIgnoreConditionalBuffer.ch, 0,
- fIgnoreConditionalBuffer.length - 2);
- fDTDHandler.ignoredCharacters(fLiteral, null);
- fDTDHandler.endConditional(null);
- }
- return;
- } else if(fDTDHandler != null) {
- fIgnoreConditionalBuffer.append('>');
- }
- }
- }
- }
- else {
- int c = fEntityScanner.scanChar();
- if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
- reportFatalError("IgnoreSectUnterminated", null);
- return;
- }
- if (fDTDHandler != null) {
- fIgnoreConditionalBuffer.append((char)c);
- }
- }
- }
- }
- else {
- reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
- }
-
- } // scanConditionalSect()
-
- /**
- * Dispatch an XML "event".
- *
- * @param complete True if this method is intended to scan
- * and dispatch as much as possible.
- *
- * @return True if there is more to scan.
- *
- * @throws IOException Thrown on i/o error.
- * @throws XNIException Thrown on parse error.
- *
- */
- protected final boolean scanDecls(boolean complete)
- throws IOException, XNIException {
-
- skipSeparator(false, true);
- boolean again = true;
- while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) {
- again = complete;
- if (fEntityScanner.skipChar('<')) {
- fMarkUpDepth++;
- if (fEntityScanner.skipChar('?')) {
- scanPI();
- }
- else if (fEntityScanner.skipChar('!')) {
- if (fEntityScanner.skipChar('-')) {
- if (!fEntityScanner.skipChar('-')) {
- reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
- null);
- } else {
- scanComment();
- }
- }
- else if (fEntityScanner.skipString("ELEMENT")) {
- scanElementDecl();
- }
- else if (fEntityScanner.skipString("ATTLIST")) {
- scanAttlistDecl();
- }
- else if (fEntityScanner.skipString("ENTITY")) {
- scanEntityDecl();
- }
- else if (fEntityScanner.skipString("NOTATION")) {
- scanNotationDecl();
- }
- else if (fEntityScanner.skipChar('[') &&
- !scanningInternalSubset()) {
- scanConditionalSect(fPEDepth);
- }
- else {
- fMarkUpDepth--;
- reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
- null);
- }
- }
- else {
- fMarkUpDepth--;
- reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
- }
- }
- else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']')) {
- // end of conditional section?
- if (!fEntityScanner.skipChar(']')
- || !fEntityScanner.skipChar('>')) {
- reportFatalError("IncludeSectUnterminated", null);
- }
- // call handler
- if (fDTDHandler != null) {
- fDTDHandler.endConditional(null);
- }
- // decreaseMarkupDepth();
- fIncludeSectDepth--;
- fMarkUpDepth--;
- }
- else if (scanningInternalSubset() &&
- fEntityScanner.peekChar() == ']') {
- // this is the end of the internal subset, let's stop here
- return false;
- }
- else if (fEntityScanner.skipSpaces()) {
- // simply skip
- }
- else {
- reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
- // Skip the part in error
- int ch;
- do {
- // Ignore the current character
- fEntityScanner.scanChar();
- // Skip any separators
- skipSeparator(false, true);
- // Keeping getting the next character,
- // until it's one of the expected ones
- ch = fEntityScanner.peekChar();
- } while (ch != '<' && ch != ']' && !XMLChar.isSpace(ch));
- }
- skipSeparator(false, true);
- }
- return fScannerState != SCANNER_STATE_END_OF_INPUT;
- }
-
- /**
- * Skip separator. This is typically just whitespace but it can also be one
- * or more parameter entity references.
- * <p>
- * If there are some it "expands them" by calling the corresponding entity
- * from the entity manager.
- * <p>
- * This is recursive and will process has many refs as possible.
- *
- * @param spaceRequired Specify whether some leading whitespace should be
- * found
- * @param lookForPERefs Specify whether parameter entity references should
- * be looked for
- * @return True if any leading whitespace was found or the end of a
- * parameter entity was crossed.
- */
- private boolean skipSeparator(boolean spaceRequired, boolean lookForPERefs)
- throws IOException, XNIException
- {
- int depth = fPEDepth;
- boolean sawSpace = fEntityScanner.skipSpaces();
- if (!lookForPERefs || !fEntityScanner.skipChar('%')) {
- return !spaceRequired || sawSpace || (depth != fPEDepth);
- }
- while (true) {
- String name = fEntityScanner.scanName();
- if (name == null) {
- reportFatalError("NameRequiredInPEReference", null);
- }
- else if (!fEntityScanner.skipChar(';')) {
- reportFatalError("SemicolonRequiredInPEReference",
- new Object[]{name});
- }
- startPE(name, false);
- fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('%'))
- return true;
- }
- }
-
-
- /*
- * Element Children Content Stack
- */
- private final void pushContentStack(int c) {
- if (fContentStack.length == fContentDepth) {
- int[] newStack = new int[fContentDepth * 2];
- System.arraycopy(fContentStack, 0, newStack, 0, fContentDepth);
- fContentStack = newStack;
- }
- fContentStack[fContentDepth++] = c;
- }
-
- private final int popContentStack() {
- return fContentStack[--fContentDepth];
- }
-
-
- /*
- * Parameter Entity Stack
- */
- private final void pushPEStack(int depth, boolean report) {
- if (fPEStack.length == fPEDepth) {
- int[] newIntStack = new int[fPEDepth * 2];
- System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth);
- fPEStack = newIntStack;
- // report end/start calls
- boolean[] newBooleanStack = new boolean[fPEDepth * 2];
- System.arraycopy(fPEReport, 0, newBooleanStack, 0, fPEDepth);
- fPEReport = newBooleanStack;
-
- }
- fPEReport[fPEDepth] = report;
- fPEStack[fPEDepth++] = depth;
- }
-
- /** pop the stack */
- private final int popPEStack() {
- return fPEStack[--fPEDepth];
- }
-
- /** look at the top of the stack */
- private final boolean peekReportEntity() {
- return fPEReport[fPEDepth-1];
- }
-
-
- /*
- * Utility method
- */
- private final void ensureEnumerationSize(int size) {
- if (fEnumeration.length == size) {
- String[] newEnum = new String[size * 2];
- System.arraycopy(fEnumeration, 0, newEnum, 0, size);
- fEnumeration = newEnum;
- }
- }
-
- // private methods
- private void init() {
- // reset state related data
- fStartDTDCalled = false;
- fExtEntityDepth = 0;
- fIncludeSectDepth = 0;
- fMarkUpDepth = 0;
- fPEDepth = 0;
-
- fStandalone = false;
- fSeenExternalDTD = false;
- fSeenExternalPE = false;
-
- // set starting state
- setScannerState(SCANNER_STATE_TEXT_DECL);
- }
-
- } // class XMLDTDScannerImpl