alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (XMLDTDScannerImpl.java)

This example Java source code file (XMLDTDScannerImpl.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

entity, ioexception, msg_markup_not_recognized_in_dtd, object, scanner_state_end_of_input, scanner_state_markup_decl, scanner_state_text_decl, string, xmldtdhandler, xmldtdscannerimpl, xmllimitanalyzer, xmlstring, xmlstringbuffer, xniexception

The XMLDTDScannerImpl.java Java example source code

/*
 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
 */

/*
 * Copyright 2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sun.org.apache.xerces.internal.impl;
import com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar;
import java.io.EOFException;
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.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;
import com.sun.org.apache.xerces.internal.xni.Augmentations;
import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler;
import com.sun.org.apache.xerces.internal.impl.Constants;
import com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer;
import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
import com.sun.xml.internal.stream.Entity;

/**
 * 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>http://apache.org/xml/features/scanner/notify-char-refs
 *  <li>http://apache.org/xml/properties/internal/symbol-table
 *  <li>http://apache.org/xml/properties/internal/error-reporter
 *  <li>http://apache.org/xml/properties/internal/entity-manager
 * </ul>
 *
 * @author Arnaud  Le Hors, IBM
 * @author Andy Clark, IBM
 * @author Glenn Marcy, IBM
 * @author Eric Ye, IBM
 *
 * @version $Id: XMLDTDScannerImpl.java,v 1.8 2010-11-01 04:39:41 joehw 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. */
    public XMLDTDHandler fDTDHandler = null;

    /** 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);

    /** Object contains grammar information for a non-validaing parser. */
    DTDGrammar nvGrammarInfo = null;

    boolean nonValidatingMode = false;
    //
    // 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);
            }
            if (nonValidatingMode){
                nvGrammarInfo.startDTD(null,null);
                nvGrammarInfo.endDTD(null);
            }
            return;
        }
        fEntityManager.setEntityHandler(this);
        fEntityManager.startDTDEntity(inputSource);
    } // setInputSource(XMLInputSource)


    public void setLimitAnalyzer(XMLLimitAnalyzer limitAnalyzer) {
        fLimitAnalyzer = limitAnalyzer;
    }

    /**
     * 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
        //xxx:stax getText() is supposed to return only DTD internal subset
        //shouldn't we record position here before we go ahead ??

        fEntityScanner = (XMLEntityScanner)fEntityManager.getEntityScanner();
        fEntityManager.setEntityHandler(this);
        fStandalone = standalone;
        //System.out.println("state"+fScannerState);
        if (fScannerState == SCANNER_STATE_TEXT_DECL) {
            // call handler
            if (fDTDHandler != null) {
                fDTDHandler.startDTD(fEntityScanner, null);
                fStartDTDCalled = true;
            }

            if (nonValidatingMode){
                fStartDTDCalled = true;
                nvGrammarInfo.startDTD(fEntityScanner,null);
            }
            // 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);
                }
                if (nonValidatingMode && hasExternalSubset == false ){
                    nvGrammarInfo.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();

    }

    public void reset(PropertyManager props) {
        setPropertyManager(props);
        super.reset(props);
        init() ;
        nonValidatingMode = true;
        //Revisit : Create new grammar until we implement GrammarPool.
        nvGrammarInfo = new DTDGrammar(fSymbolTable);
    }
    /**
     * 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();
            fEntityStore.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, null);
        }

    } // 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.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endEntity(String name, Augmentations augs)
    throws XNIException, IOException {

        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, null);
        }

        // end DTD
        if (dtdEntity) {
            if (fIncludeSectDepth != 0) {
                reportFatalError("IncludeSectUnterminated", null);
            }
            fScannerState = SCANNER_STATE_END_OF_INPUT;
            // call handler
            fEntityManager.endExternalSubset();
            fEntityStore.endExternalSubset();

            if (fDTDHandler != null) {
                fDTDHandler.endExternalSubset(null);
                fDTDHandler.endDTD(null);
            }
            fExtEntityDepth--;
        }

        //XML (Document Entity) is the last opened entity, however
        //if for some reason DTD Scanner receives this callback
        //there is something wrong (probably invalid XML), throw exception.
        //or
        //For standalone DTD loader, it might be the last opened entity
        //and if this is the last opened entity and fMarkUpDepth != 0 or
        //fIncludeSectDepth != 0 or fExtEntityDepth != 0 throw Exception
        if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.LAST_ENTITY))
            && ( fMarkUpDepth != 0 || fExtEntityDepth !=0 || fIncludeSectDepth != 0)){
            throw new EOFException();
        }

    } // 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 && !fEntityStore.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");
                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 "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 {
        //Venu REVISIT
        //      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: 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: 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);
        }
        if (nonValidatingMode) nvGrammarInfo.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: 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: 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: 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
            String[] enumr = null;
            if( fDTDHandler != null || nonValidatingMode){
                if (fEnumerationCount != 0) {
                    enumr = new String[fEnumerationCount];
                    System.arraycopy(fEnumeration, 0, enumr,
                    0, fEnumerationCount);
                }
            }
            // call handler
            // 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"))) {
                if (fDTDHandler != null){
                    fDTDHandler.attributeDecl(elName, name, type, enumr,
                    defaultType, null, null, null);
                }
                if(nonValidatingMode){
                    nvGrammarInfo.attributeDecl(elName, name, type, enumr,
                    defaultType, null, null, null);

                }
            }
            else {
                if (fDTDHandler != null){
                    fDTDHandler.attributeDecl(elName, name, type, enumr,
                    defaultType, fLiteral, fLiteral2, null);
                }
                if(nonValidatingMode){
                    nvGrammarInfo.attributeDecl(elName, name, type, enumr,
                    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: 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,
            fAttributes, 0, isVC);
        }
        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: 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 
            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 = fEntityScanner.scanName();
        if (name == null) {
            reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null);
        }

        // spaces
        if (!skipSeparator(true, !scanningInternalSubset())) {
            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(name, isPEDecl, 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) {
                fEntityStore.addUnparsedEntity(name, publicId, systemId, baseSystemId, notation);
            }
            else {
                fEntityStore.addExternalEntity(name, publicId, systemId,
                baseSystemId);
            }
            if (fDTDHandler != null) {
                //Venu Revisit : why false has been removed in expandSYstem
                fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId ));

                if (notation != null) {
                    fDTDHandler.unparsedEntityDecl(name, fResourceIdentifier,
                    notation, null);
                }
                else {
                    fDTDHandler.externalEntityDecl(name, fResourceIdentifier, null);
                }
            }
        }
        else {
            fEntityStore.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: 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(String entityName, boolean isPEDecl, 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;
        int countChar = 0;
        if (fLimitAnalyzer == null ) {
            fLimitAnalyzer = new XMLLimitAnalyzer();
         }
        fLimitAnalyzer.startEntity(entityName);

        if (fEntityScanner.scanLiteral(quote, fString) != quote) {
            fStringBuffer.clear();
            fStringBuffer2.clear();
            do {
                if (isPEDecl && fLimitAnalyzer != null) {
                    checkLimit("%" + entityName, fString.length + countChar);
                }
                countChar = 0;
                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 {
                    countChar++;
                    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;
        } else {
            if (isPEDecl) {
                checkLimit("%" + entityName, literal);
        }
        }
        value.setValues(literal);
        nonNormalizedValue.setValues(literal2);
        if (fLimitAnalyzer != null) {
            fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName);
        }

        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: 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 = fEntityScanner.scanName();
        if (name == null) {
            reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL",
            null);
        }

        // spaces
        if (!skipSeparator(true, !scanningInternalSubset())) {
            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--;

        fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId ));
        if (nonValidatingMode) nvGrammarInfo.notationDecl(name, fResourceIdentifier, null);
        // call handler
        if (fDTDHandler != null) {
            //Venu Revisit wby false has been removed.
            //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: 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
                    // '<

Other Java examples (source code examples)

Here is a short list of links related to this Java XMLDTDScannerImpl.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.