FileDocCategorySizeDatePackage
XMLDTDScannerImpl.javaAPI DocApache Xerces 3.0.181424Fri Sep 14 20:33:54 BST 2007org.apache.xerces.impl

XMLDTDScannerImpl

public class XMLDTDScannerImpl extends XMLScanner implements org.apache.xerces.xni.parser.XMLDTDScanner, XMLEntityHandler, org.apache.xerces.xni.parser.XMLComponent
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.

This component requires the following features and properties from the component manager that uses it:

  • http://xml.org/sax/features/validation
  • http://apache.org/xml/features/scanner/notify-char-refs
  • http://apache.org/xml/properties/internal/symbol-table
  • http://apache.org/xml/properties/internal/error-reporter
  • http://apache.org/xml/properties/internal/entity-manager
xerces.internal
author
Arnaud Le Hors, IBM
author
Andy Clark, IBM
author
Glenn Marcy, IBM
author
Eric Ye, IBM
version
$Id: XMLDTDScannerImpl.java 572055 2007-09-02 17:55:43Z mrglavas $

Fields Summary
protected static final int
SCANNER_STATE_END_OF_INPUT
Scanner state: end of input.
protected static final int
SCANNER_STATE_TEXT_DECL
Scanner state: text declaration.
protected static final int
SCANNER_STATE_MARKUP_DECL
Scanner state: markup declaration.
private static final String[]
RECOGNIZED_FEATURES
Recognized features.
private static final Boolean[]
FEATURE_DEFAULTS
Feature defaults.
private static final String[]
RECOGNIZED_PROPERTIES
Recognized properties.
private static final Object[]
PROPERTY_DEFAULTS
Property defaults.
private static final boolean
DEBUG_SCANNER_STATE
Debug scanner state.
protected org.apache.xerces.xni.XMLDTDHandler
fDTDHandler
DTD handler.
protected org.apache.xerces.xni.XMLDTDContentModelHandler
fDTDContentModelHandler
DTD content model handler.
protected int
fScannerState
Scanner state.
protected boolean
fStandalone
Standalone.
protected boolean
fSeenExternalDTD
Seen external DTD.
protected boolean
fSeenPEReferences
Seen a parameter entity reference.
private boolean
fStartDTDCalled
Start DTD called.
private int[]
fContentStack
Stack of content operators (either '|' or ',') in children content.
private int
fContentDepth
Size of content stack.
private int[]
fPEStack
Parameter entity stack to check well-formedness.
private boolean[]
fPEReport
Parameter entity stack to report start/end entity calls.
private int
fPEDepth
Number of opened parameter entities.
private int
fMarkUpDepth
Markup depth.
private int
fExtEntityDepth
Number of opened external entities.
private int
fIncludeSectDepth
Number of opened include sections.
private final String[]
fStrings
Array of 3 strings.
private final org.apache.xerces.xni.XMLString
fString
String.
private final org.apache.xerces.util.XMLStringBuffer
fStringBuffer
String buffer.
private final org.apache.xerces.util.XMLStringBuffer
fStringBuffer2
String buffer.
private final org.apache.xerces.xni.XMLString
fLiteral
Literal text.
private final org.apache.xerces.xni.XMLString
fLiteral2
Literal text.
private String[]
fEnumeration
Enumeration values.
private int
fEnumerationCount
Enumeration values count.
private final org.apache.xerces.util.XMLStringBuffer
fIgnoreConditionalBuffer
Ignore conditional section buffer.
Constructors Summary
public XMLDTDScannerImpl()
Default constructor.


    //
    // Constructors
    //

       
      
public XMLDTDScannerImpl(org.apache.xerces.util.SymbolTable symbolTable, XMLErrorReporter errorReporter, XMLEntityManager entityManager)
Constructor for he use of non-XMLComponentManagers.

        fSymbolTable = symbolTable;
        fErrorReporter = errorReporter;
        fEntityManager = entityManager;
        entityManager.setProperty(SYMBOL_TABLE, fSymbolTable);
    
Methods Summary
public voidendEntity(java.lang.String name, org.apache.xerces.xni.Augmentations augs)
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.


        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
            if (fDTDHandler != null && reportEntity) {
                fDTDHandler.endParameterEntity(name, augs);
            }
        }
        // end DTD
        else if (name.equals("[dtd]")) {
            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--;
        }

    
private final voidensureEnumerationSize(int size)

        if (fEnumeration.length == size) {
            String[] newEnum = new String[size * 2];
            System.arraycopy(fEnumeration, 0, newEnum, 0, size);
            fEnumeration = newEnum;
        }
    
public org.apache.xerces.xni.XMLDTDContentModelHandlergetDTDContentModelHandler()
getDTDContentModelHandler

return
XMLDTDContentModelHandler

        return fDTDContentModelHandler ;
    
public org.apache.xerces.xni.XMLDTDHandlergetDTDHandler()
getDTDHandler

return
the XMLDTDHandler

        return fDTDHandler;
    
public java.lang.BooleangetFeatureDefault(java.lang.String featureId)
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

        for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
            if (RECOGNIZED_FEATURES[i].equals(featureId)) {
                return FEATURE_DEFAULTS[i];
            }
        }
        return null;
    
public java.lang.ObjectgetPropertyDefault(java.lang.String propertyId)
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

        for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
            if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
                return PROPERTY_DEFAULTS[i];
            }
        }
        return null;
    
public java.lang.String[]getRecognizedFeatures()
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.

        return (String[])(RECOGNIZED_FEATURES.clone());
    
public java.lang.String[]getRecognizedProperties()
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.

        return (String[])(RECOGNIZED_PROPERTIES.clone());
    
private static java.lang.StringgetScannerStateName(int state)
Returns the scanner state name.


        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+')";

    
private voidinit()

        // reset state related data
        fStartDTDCalled = false;
        fExtEntityDepth = 0;
        fIncludeSectDepth = 0;
        fMarkUpDepth = 0;
        fPEDepth = 0;

        fStandalone = false;
        fSeenExternalDTD = false;
        fSeenPEReferences = false;

        // set starting state
        setScannerState(SCANNER_STATE_TEXT_DECL);
    
private final booleanpeekReportEntity()
look at the top of the stack

        return fPEReport[fPEDepth-1];
    
private final intpopContentStack()

        return fContentStack[--fContentDepth];
    
private final intpopPEStack()
pop the stack

        return fPEStack[--fPEDepth];
    
private final voidpushContentStack(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 voidpushPEStack(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;
    
public voidreset(org.apache.xerces.xni.parser.XMLComponentManager componentManager)
reset

param
componentManager

        
        super.reset(componentManager);
        init();

    
public voidreset()

        super.reset();
        init();
    
protected final java.lang.StringscanAttDefaultDecl(java.lang.String elName, java.lang.String atName, java.lang.String type, org.apache.xerces.xni.XMLString defaultVal, org.apache.xerces.xni.XMLString nonNormalizedDefaultVal)
Scans an attribute default declaration

[60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)

param
elName
param
atName The name of the attribute being scanned.
param
type
param
defaultVal The string to fill in with the default value.
param
nonNormalizedDefaultVal


        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 || fSeenPEReferences);
            scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName, isVC, elName);
        }
        return defaultType;

    
private final java.lang.StringscanAttType(java.lang.String elName, java.lang.String atName)
Scans an attribute type definition

[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? ')'

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.


        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});
                    c = skipInvalidEnumerationValue();
                    if (c == '|") {
                        continue;
                    }
                    break;
                }
                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});
                    c = skipInvalidEnumerationValue();
                    if (c == '|") {
                        continue;
                    }
                    break;
                }
                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;

    
protected final voidscanAttlistDecl()
Scans an attlist declaration

[52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
[53] AttDef ::= S Name S AttType S DefaultDecl

Note: Called after scanning past '<!ATTLIST'


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

    
private final voidscanChildren(java.lang.String elName)
scan children content model This assumes it can simply append to fStringBuffer.
[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? ')'

param
elName The element type name this declaration is about. Note: Called after scanning past the first open paranthesis.


        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());
        }
    
protected final voidscanComment()
Scans a comment.

[15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'

Note: Called after scanning past '<!--'


        fReportEntity = false;
        scanComment(fStringBuffer);
        fMarkUpDepth--;

        // call handler
        if (fDTDHandler != null) {
            fDTDHandler.comment(fStringBuffer, null);
        }
        fReportEntity = true;

    
private final voidscanConditionalSect(int currPEDepth)
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).

[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*)

Note: Called after scanning past '<!['


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

    
public booleanscanDTDExternalSubset(boolean complete)
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.


        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;

    
public booleanscanDTDInternalSubset(boolean complete, boolean standalone, boolean hasExternalSubset)
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
hasExternalSubset 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.

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

    
protected final booleanscanDecls(boolean complete)
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.

        
        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;
    
protected final voidscanElementDecl()
Scans an element declaration

[45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
[46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children

Note: Called after scanning past '<!ELEMENT'


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

    
private final voidscanEntityDecl()
Scans an entity declaration

[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

Note: Called after scanning past '<!ENTITY'


        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];

        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;

    
protected final voidscanEntityValue(org.apache.xerces.xni.XMLString value, org.apache.xerces.xni.XMLString nonNormalizedValue)
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. Note: This method uses fString, fStringBuffer (through the use of scanCharReferenceValue), and fStringBuffer2, anything in them at the time of calling is lost.

        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);
        }
    
private final voidscanMixed(java.lang.String elName)
scan Mixed content model This assumes the content model has been parsed up to #PCDATA and can simply append to fStringBuffer.
[51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
| '(' S? '#PCDATA' S? ')'

param
elName The element type name this declaration is about. Note: Called after scanning past '(#PCDATA'.


        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
    
private final voidscanNotationDecl()
Scans a notation declaration

[82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID|PublicID) S? '>'
[83] PublicID ::= 'PUBLIC' S PubidLiteral

Note: Called after scanning past '<!NOTATION'


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

    
protected final voidscanPIData(java.lang.String target, org.apache.xerces.xni.XMLString data)
Scans a processing data. This is needed to handle the situation where a document starts with a processing instruction whose target name starts with "xml". (e.g. xmlfoo)

param
target The PI target
param
data The string to fill in with the data


        super.scanPIData(target, data);
        fMarkUpDepth--;

        // call handler
        if (fDTDHandler != null) {
            fDTDHandler.processingInstruction(target, data, null);
        }

    
protected final booleanscanTextDecl()
Dispatch an XML "event".

return
true if a TextDecl was scanned.
throws
IOException Thrown on i/o error.
throws
XNIException Thrown on parse error.


        // 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.setXMLVersion(version);
                if (!fEntityScanner.fCurrentEntity.isEncodingExternallySpecified()) {
                    fEntityScanner.setEncoding(encoding);
                }

                // call handler
                if (fDTDHandler != null) {
                    fDTDHandler.textDecl(version, encoding, null);
                }
            }
        }
        fEntityManager.fCurrentEntity.mayReadChunks = true;

        return textDecl;
    
    
protected final booleanscanningInternalSubset()

        return fExtEntityDepth == 0;
    
public voidsetDTDContentModelHandler(org.apache.xerces.xni.XMLDTDContentModelHandler dtdContentModelHandler)
setDTDContentModelHandler

param
dtdContentModelHandler

        fDTDContentModelHandler = dtdContentModelHandler;
    
public voidsetDTDHandler(org.apache.xerces.xni.XMLDTDHandler dtdHandler)
setDTDHandler

param
dtdHandler

        fDTDHandler = dtdHandler;
    
public voidsetInputSource(org.apache.xerces.xni.parser.XMLInputSource inputSource)
Sets the input source.

param
inputSource The input source or null.
throws
IOException Thrown on i/o error.

        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);
    
protected final voidsetScannerState(int state)
Sets the scanner state.

param
state The new scanner state.


        fScannerState = state;
        if (DEBUG_SCANNER_STATE) {
            System.out.print("### setScannerState: ");
            System.out.print(getScannerStateName(state));
            System.out.println();
        }

    
private intskipInvalidEnumerationValue()

        int c;
        do {
            c = fEntityScanner.scanChar();
        } 
        while (c != '|" && c != ')");
        ensureEnumerationSize(fEnumerationCount + 1);
        fEnumeration[fEnumerationCount++] = XMLSymbols.EMPTY_STRING;
        return c;
    
private booleanskipSeparator(boolean spaceRequired, boolean lookForPERefs)
Skip separator. This is typically just whitespace but it can also be one or more parameter entity references.

If there are some it "expands them" by calling the corresponding entity from the entity manager.

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.

        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;
        }
    
public voidstartEntity(java.lang.String name, org.apache.xerces.xni.XMLResourceIdentifier identifier, java.lang.String encoding, org.apache.xerces.xni.Augmentations augs)
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.


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

    
protected voidstartPE(java.lang.String name, boolean literal)
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

        int depth = fPEDepth;
        String pName = "%"+name;
        if (!fSeenPEReferences) {
            fSeenPEReferences = true;
            fEntityManager.notifyHasPEReferences();
        }
        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();
        }