All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xerces.impl.XMLDTDScannerImpl Maven / Gradle / Ivy

Go to download

Xerces2 is the next generation of high performance, fully compliant XML parsers in the Apache Xerces family. This new version of Xerces introduces the Xerces Native Interface (XNI), a complete framework for building parser components and configurations that is extremely modular and easy to program. The Apache Xerces2 parser is the reference implementation of XNI but other parser components, configurations, and parsers can be written using the Xerces Native Interface. For complete design and implementation documents, refer to the XNI Manual. Xerces2 is a fully conforming XML Schema 1.0 processor. A partial experimental implementation of the XML Schema 1.1 Structures and Datatypes Working Drafts (December 2009) and an experimental implementation of the XML Schema Definition Language (XSD): Component Designators (SCD) Candidate Recommendation (January 2010) are provided for evaluation. For more information, refer to the XML Schema page. Xerces2 also provides a complete implementation of the Document Object Model Level 3 Core and Load/Save W3C Recommendations and provides a complete implementation of the XML Inclusions (XInclude) W3C Recommendation. It also provides support for OASIS XML Catalogs v1.1. Xerces2 is able to parse documents written according to the XML 1.1 Recommendation, except that it does not yet provide an option to enable normalization checking as described in section 2.13 of this specification. It also handles namespaces according to the XML Namespaces 1.1 Recommendation, and will correctly serialize XML 1.1 documents if the DOM level 3 load/save APIs are in use.

There is a newer version: 2.12.2
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.xerces.impl;

import java.io.IOException;

import org.apache.xerces.impl.msg.XMLMessageFormatter;
import org.apache.xerces.util.SymbolTable;
import org.apache.xerces.util.XMLChar;
import org.apache.xerces.util.XMLStringBuffer;
import org.apache.xerces.util.XMLSymbols;
import org.apache.xerces.xni.Augmentations;
import org.apache.xerces.xni.XMLDTDContentModelHandler;
import org.apache.xerces.xni.XMLDTDHandler;
import org.apache.xerces.xni.XMLResourceIdentifier;
import org.apache.xerces.xni.XMLString;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.parser.XMLComponent;
import org.apache.xerces.xni.parser.XMLComponentManager;
import org.apache.xerces.xni.parser.XMLConfigurationException;
import org.apache.xerces.xni.parser.XMLDTDScanner;
import org.apache.xerces.xni.parser.XMLInputSource;

/**
 * This class is responsible for scanning the declarations found
 * in the internal and external subsets of a DTD in an XML document.
 * The scanner acts as the sources for the DTD information which is 
 * communicated to the DTD handlers.
 * 

* 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 1514806 2013-08-16 17:29:02Z mrglavas $ */ public class XMLDTDScannerImpl extends XMLScanner implements XMLDTDScanner, XMLComponent, XMLEntityHandler { // // Constants // // scanner states /** Scanner state: end of input. */ protected static final int SCANNER_STATE_END_OF_INPUT = 0; /** Scanner state: text declaration. */ protected static final int SCANNER_STATE_TEXT_DECL = 1; /** Scanner state: markup declaration. */ protected static final int SCANNER_STATE_MARKUP_DECL = 2; // recognized features and properties /** Recognized features. */ private static final String[] RECOGNIZED_FEATURES = { VALIDATION, NOTIFY_CHAR_REFS, }; /** Feature defaults. */ private static final Boolean[] FEATURE_DEFAULTS = { null, Boolean.FALSE, }; /** Recognized properties. */ private static final String[] RECOGNIZED_PROPERTIES = { SYMBOL_TABLE, ERROR_REPORTER, ENTITY_MANAGER, }; /** Property defaults. */ private static final Object[] PROPERTY_DEFAULTS = { null, null, null, }; // debugging /** Debug scanner state. */ private static final boolean DEBUG_SCANNER_STATE = false; // // Data // // handlers /** DTD handler. */ protected XMLDTDHandler fDTDHandler; /** DTD content model handler. */ protected XMLDTDContentModelHandler fDTDContentModelHandler; // state /** Scanner state. */ protected int fScannerState; /** Standalone. */ protected boolean fStandalone; /** Seen external DTD. */ protected boolean fSeenExternalDTD; /** Seen a parameter entity reference. */ protected boolean fSeenPEReferences; // private data /** Start DTD called. */ private boolean fStartDTDCalled; /** * 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 final String[] fStrings = new String[3]; /** String. */ private final XMLString fString = new XMLString(); /** String buffer. */ private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); /** String buffer. */ private final XMLStringBuffer fStringBuffer2 = new XMLStringBuffer(); /** Literal text. */ private final XMLString fLiteral = new XMLString(); /** Literal text. */ private final XMLString fLiteral2 = new XMLString(); /** Enumeration values. */ private String[] fEnumeration = new String[5]; /** Enumeration values count. */ private int fEnumerationCount; /** Ignore conditional section buffer. */ private final XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(128); // // Constructors // /** Default constructor. */ public XMLDTDScannerImpl() {} // () /** Constructor for he use of non-XMLComponentManagers. */ public XMLDTDScannerImpl(SymbolTable symbolTable, XMLErrorReporter errorReporter, XMLEntityManager entityManager) { fSymbolTable = symbolTable; fErrorReporter = errorReporter; fEntityManager = entityManager; entityManager.setProperty(SYMBOL_TABLE, fSymbolTable); } // // XMLDTDScanner methods // /** * Sets the input source. * * @param inputSource The input source or null. * * @throws IOException Thrown on i/o error. */ public void setInputSource(XMLInputSource inputSource) throws IOException { if (inputSource == null) { // no system id was available if (fDTDHandler != null) { fDTDHandler.startDTD(null, null); fDTDHandler.endDTD(null); } return; } fEntityManager.setEntityHandler(this); fEntityManager.startDTDEntity(inputSource); } // setInputSource(XMLInputSource) /** * Scans the external subset of the document. * * @param complete True if the scanner should scan the document * completely, pushing all events to the registered * document handler. A value of false indicates that * that the scanner should only scan the next portion * of the document and return. A scanner instance is * permitted to completely scan a document if it does * not support this "pull" scanning model. * * @return True if there is more to scan, false otherwise. */ public boolean scanDTDExternalSubset(boolean complete) throws IOException, XNIException { fEntityManager.setEntityHandler(this); if (fScannerState == SCANNER_STATE_TEXT_DECL) { fSeenExternalDTD = true; boolean textDecl = scanTextDecl(); if (fScannerState == SCANNER_STATE_END_OF_INPUT) { return false; } else { // next state is markup decls regardless of whether there // is a TextDecl or not setScannerState(SCANNER_STATE_MARKUP_DECL); if (textDecl && !complete) { return true; } } } // keep dispatching "events" do { if (!scanDecls(complete)) { return false; } } while (complete); // return that there is more to scan return true; } // scanDTDExternalSubset(boolean):boolean /** * Scans the internal subset of the document. * * @param complete True if the scanner should scan the document * completely, pushing all events to the registered * document handler. A value of false indicates that * that the scanner should only scan the next portion * of the document and return. A scanner instance is * permitted to completely scan a document if it does * not support this "pull" scanning model. * @param standalone True if the document was specified as standalone. * This value is important for verifying certain * well-formedness constraints. * @param 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. */ public boolean scanDTDInternalSubset(boolean complete, boolean standalone, boolean hasExternalSubset) throws IOException, XNIException { // reset entity scanner fEntityScanner = fEntityManager.getEntityScanner(); fEntityManager.setEntityHandler(this); fStandalone = standalone; if (fScannerState == SCANNER_STATE_TEXT_DECL) { // call handler if (fDTDHandler != null) { fDTDHandler.startDTD(fEntityScanner, null); fStartDTDCalled = true; } // set starting state for internal subset setScannerState(SCANNER_STATE_MARKUP_DECL); } // keep dispatching "events" do { if (!scanDecls(complete)) { // call handler if (fDTDHandler != null && hasExternalSubset == false) { fDTDHandler.endDTD(null); } // we're done, set starting state for external subset setScannerState(SCANNER_STATE_TEXT_DECL); return false; } } while (complete); // return that there is more to scan return true; } // scanDTDInternalSubset(boolean,boolean,boolean):boolean // // XMLComponent methods // /** * reset * * @param componentManager */ public void reset(XMLComponentManager componentManager) throws XMLConfigurationException { super.reset(componentManager); init(); } // reset(XMLComponentManager) // this is made for something like XMLDTDLoader--XMLComponentManager-free operation... public void reset() { super.reset(); init(); } /** * Returns a list of feature identifiers that are recognized by * this component. This method may return null if no features * are recognized by this component. */ public String[] getRecognizedFeatures() { return (String[])(RECOGNIZED_FEATURES.clone()); } // getRecognizedFeatures():String[] /** * Returns a list of property identifiers that are recognized by * this component. This method may return null if no properties * are recognized by this component. */ public String[] getRecognizedProperties() { return (String[])(RECOGNIZED_PROPERTIES.clone()); } // getRecognizedProperties():String[] /** * Returns the default state for a feature, or null if this * component does not want to report a default value for this * feature. * * @param featureId The feature identifier. * * @since Xerces 2.2.0 */ public Boolean getFeatureDefault(String featureId) { for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { if (RECOGNIZED_FEATURES[i].equals(featureId)) { return FEATURE_DEFAULTS[i]; } } return null; } // getFeatureDefault(String):Boolean /** * Returns the default state for a property, or null if this * component does not want to report a default value for this * property. * * @param propertyId The property identifier. * * @since Xerces 2.2.0 */ public Object getPropertyDefault(String propertyId) { for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { return PROPERTY_DEFAULTS[i]; } } return null; } // getPropertyDefault(String):Object // // XMLDTDSource methods // /** * setDTDHandler * * @param dtdHandler */ public void setDTDHandler(XMLDTDHandler dtdHandler) { fDTDHandler = dtdHandler; } // setDTDHandler(XMLDTDHandler) /** * getDTDHandler * * @return the XMLDTDHandler */ public XMLDTDHandler getDTDHandler() { return fDTDHandler; } // getDTDHandler(): XMLDTDHandler // // XMLDTDContentModelSource methods // /** * setDTDContentModelHandler * * @param dtdContentModelHandler */ public void setDTDContentModelHandler(XMLDTDContentModelHandler dtdContentModelHandler) { fDTDContentModelHandler = dtdContentModelHandler; } // setDTDContentModelHandler /** * getDTDContentModelHandler * * @return XMLDTDContentModelHandler */ public XMLDTDContentModelHandler getDTDContentModelHandler() { return fDTDContentModelHandler ; } // setDTDContentModelHandler // // XMLEntityHandler methods // /** * This method notifies of the start of an entity. The DTD has the * pseudo-name of "[dtd]" parameter entity names start with '%'; and * general entities are just specified by their name. * * @param name The name of the entity. * @param identifier The resource identifier. * @param encoding The auto-detected IANA encoding name of the entity * stream. This value will be null in those situations * where the entity encoding is not auto-detected (e.g. * internal entities or a document entity that is * parsed from a java.io.Reader). * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void startEntity(String name, XMLResourceIdentifier identifier, String encoding, Augmentations augs) throws XNIException { super.startEntity(name, identifier, encoding, augs); boolean dtdEntity = name.equals("[dtd]"); if (dtdEntity) { // call handler if (fDTDHandler != null && !fStartDTDCalled ) { fDTDHandler.startDTD(fEntityScanner, null); } if (fDTDHandler != null) { fDTDHandler.startExternalSubset(identifier,null); } fEntityManager.startExternalSubset(); fExtEntityDepth++; } else if (name.charAt(0) == '%') { pushPEStack(fMarkUpDepth, fReportEntity); if (fEntityScanner.isExternal()) { fExtEntityDepth++; } } // call handler if (fDTDHandler != null && !dtdEntity && fReportEntity) { fDTDHandler.startParameterEntity(name, identifier, encoding, augs); } } // startEntity(String,XMLResourceIdentifier,String) /** * This method notifies the end of an entity. The DTD has the pseudo-name * of "[dtd]" parameter entity names start with '%'; and general entities * are just specified by their name. * * @param name The name of the entity. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void endEntity(String name, Augmentations augs) throws XNIException { super.endEntity(name, augs); // if there is no data after the doctype // if (fScannerState == SCANNER_STATE_END_OF_INPUT) return; // Handle end of PE boolean reportEntity = fReportEntity; if (name.startsWith("%")) { reportEntity = peekReportEntity(); // check well-formedness of the enity int startMarkUpDepth = popPEStack(); // throw fatalError if this entity was incomplete and // was a freestanding decl if(startMarkUpDepth == 0 && startMarkUpDepth < fMarkUpDepth) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL", new Object[]{ fEntityManager.fCurrentEntity.name}, XMLErrorReporter.SEVERITY_FATAL_ERROR); } if (startMarkUpDepth != fMarkUpDepth) { reportEntity = false; if (fValidation) { // Proper nesting of parameter entities is a Validity Constraint // and must not be enforced when validation is off fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "ImproperDeclarationNesting", new Object[]{ name }, XMLErrorReporter.SEVERITY_ERROR); } } if (fEntityScanner.isExternal()) { fExtEntityDepth--; } // call handler 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--; } } // 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 * * @return The name of the parameter entity (with the '%') */ protected String startPE(String name, boolean literal) throws IOException, XNIException { 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(); } return pName; } /** * Dispatch an XML "event". * * @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("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 { super.scanPIData(target, data); fMarkUpDepth--; // call handler if (fDTDHandler != null) { fDTDHandler.processingInstruction(target, data, null); } } // scanPIData(String) /** * Scans a comment. *

*

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

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

*

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

* 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); } } // scanElementDecl() /** * 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'. */ 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. *
     * [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. */ 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 *

*

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

* 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 // call handler if (fDTDHandler != null) { String[] enumeration = null; if (fEnumerationCount != 0) { enumeration = new String[fEnumerationCount]; System.arraycopy(fEnumeration, 0, enumeration, 0, fEnumerationCount); } // Determine whether the default value to be passed should be null. // REVISIT: should probably check whether fLiteral.ch is null instead. LM. if (defaultType!=null && (defaultType.equals("#REQUIRED") || defaultType.equals("#IMPLIED"))) { fDTDHandler.attributeDecl(elName, name, type, enumeration, defaultType, null, null, null); } else { fDTDHandler.attributeDecl(elName, name, type, enumeration, defaultType, fLiteral, fLiteral2, null); } } skipSeparator(false, !scanningInternalSubset()); } // call handler if (fDTDHandler != null) { fDTDHandler.endAttlist(null); } fMarkUpDepth--; fReportEntity = true; } // scanAttlistDecl() /** * Scans an attribute type definition *

*

     * [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. */ 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}); 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; } // scanAttType():String /** * 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 */ 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 || fSeenPEReferences); scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName, isVC, elName); } return defaultType; } // ScanAttDefaultDecl /** * 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' */ private final void scanEntityDecl() throws IOException, XNIException { boolean isPEDecl = false; boolean sawPERef = false; fReportEntity = false; if (fEntityScanner.skipSpaces()) { if (!fEntityScanner.skipChar('%')) { isPEDecl = false; // } else if (skipSeparator(true, !scanningInternalSubset())) { // isPEDecl = true; } else if (scanningInternalSubset()) { reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_PEDECL", null); isPEDecl = true; } else if (fEntityScanner.peekChar() == '%') { // is legal skipSeparator(false, !scanningInternalSubset()); isPEDecl = true; } else { sawPERef = true; } } else if (scanningInternalSubset() || !fEntityScanner.skipChar('%')) { // or reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL", null); isPEDecl = false; } else if (fEntityScanner.skipSpaces()) { // 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}); } } // count of direct and indirect references to parameter entities in the value of the entity. int paramEntityRefs = 0; // internal entity if (systemId == null) { paramEntityRefs = 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(), paramEntityRefs); if (fDTDHandler != null) { fDTDHandler.internalEntityDecl(name, fStringBuffer, fStringBuffer2, null); } } fReportEntity = true; } // scanEntityDecl() /** *

Scans an entity value.

* *

Note: This method uses fString, fStringBuffer (through * the use of scanCharReferenceValue), and fStringBuffer2, anything in them * at the time of calling is lost.

* * @param value The string to fill in with the value. * @param nonNormalizedValue The string to fill in with the * non-normalized value. * * @return Count of direct and indirect references to parameter entities in the value of the entity. */ protected final int scanEntityValue(XMLString value, XMLString nonNormalizedValue) throws IOException, XNIException { int quote = fEntityScanner.scanChar(); if (quote != '\'' && quote != '"') { reportFatalError("OpenQuoteMissingInDecl", null); } // store at which depth of entities we start int entityDepth = fEntityDepth; // count of direct and indirect references to parameter entities in the value of the entity. int paramEntityRefs = 0; 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(';'); } final String pNameWithPct = startPE(peName, true); paramEntityRefs += (fEntityManager.getParamEntityRefCount(pNameWithPct) + 1); // 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); } return paramEntityRefs; } // scanEntityValue(XMLString,XMLString):int /** * Scans a notation declaration *

*

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

* 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 = null; if(fNamespaces) { name = fEntityScanner.scanNCName(); } else { name = fEntityScanner.scanName(); } if (name == null) { reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL", null); } // spaces if (!skipSeparator(true, !scanningInternalSubset())) { // check for invalid ":" if(fNamespaces && fEntityScanner.peekChar() == ':') { fEntityScanner.scanChar(); XMLStringBuffer colonName = new XMLStringBuffer(name); colonName.append(':'); colonName.append(fEntityScanner.scanName()); reportFatalError("ColonNotLegalWithNS", new Object[] {colonName.toString()}); skipSeparator(true, !scanningInternalSubset()); } else { reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL", new Object[]{name}); } } // external id scanExternalID(fStrings, true); String systemId = fStrings[0]; String publicId = fStrings[1]; String baseSystemId = fEntityScanner.getBaseSystemId(); if (systemId == null && publicId == null) { reportFatalError("ExternalIDorPublicIDRequired", new Object[]{name}); } // skip possible trailing space skipSeparator(false, !scanningInternalSubset()); // end if (!fEntityScanner.skipChar('>')) { reportFatalError("NotationDeclUnterminated", new Object[]{name}); } fMarkUpDepth--; // call handler if (fDTDHandler != null) { fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false)); fDTDHandler.notationDecl(name, fResourceIdentifier, null); } fReportEntity = true; } // scanNotationDecl() /** * Scans a conditional section. If it's a section to ignore the whole * section gets scanned through and this method only returns after the * closing bracket has been found. When it's an include section though, it * returns to let the main loop take care of scanning it. In that case the * end of the section if handled by the main loop (scanDecls). *

*

     * [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 '<![' */ 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 // '<', etc. // if (fEntityScanner.skipChar(']')) { if (fDTDHandler != null) { fIgnoreConditionalBuffer.append(']'); } while (fEntityScanner.skipChar(']')) { /* empty loop body */ if (fDTDHandler != null) { fIgnoreConditionalBuffer.append(']'); } } if (fEntityScanner.skipChar('>')) { if (fIncludeSectDepth-- == initialDepth) { fMarkUpDepth--; // call handler if (fDTDHandler != null) { fLiteral.setValues(fIgnoreConditionalBuffer.ch, 0, fIgnoreConditionalBuffer.length - 2); fDTDHandler.ignoredCharacters(fLiteral, null); fDTDHandler.endConditional(null); } return; } else if(fDTDHandler != null) { fIgnoreConditionalBuffer.append('>'); } } } } else { int c = fEntityScanner.scanChar(); if (fScannerState == SCANNER_STATE_END_OF_INPUT) { reportFatalError("IgnoreSectUnterminated", null); return; } if (fDTDHandler != null) { fIgnoreConditionalBuffer.append((char)c); } } } } else { reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); } } // scanConditionalSect() /** * Dispatch an XML "event". * * @param complete True if this method is intended to scan * and dispatch as much as possible. * * @return True if there is more to scan. * * @throws IOException Thrown on i/o error. * @throws XNIException Thrown on parse error. * */ protected final boolean scanDecls(boolean complete) throws IOException, XNIException { skipSeparator(false, true); boolean again = true; while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) { again = complete; if (fEntityScanner.skipChar('<')) { fMarkUpDepth++; if (fEntityScanner.skipChar('?')) { scanPI(); } else if (fEntityScanner.skipChar('!')) { if (fEntityScanner.skipChar('-')) { if (!fEntityScanner.skipChar('-')) { reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); } else { scanComment(); } } else if (fEntityScanner.skipString("ELEMENT")) { scanElementDecl(); } else if (fEntityScanner.skipString("ATTLIST")) { scanAttlistDecl(); } else if (fEntityScanner.skipString("ENTITY")) { scanEntityDecl(); } else if (fEntityScanner.skipString("NOTATION")) { scanNotationDecl(); } else if (fEntityScanner.skipChar('[') && !scanningInternalSubset()) { scanConditionalSect(fPEDepth); } else { fMarkUpDepth--; reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); } } else { fMarkUpDepth--; reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); } } else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']')) { // end of conditional section? if (!fEntityScanner.skipChar(']') || !fEntityScanner.skipChar('>')) { reportFatalError("IncludeSectUnterminated", null); } // call handler if (fDTDHandler != null) { fDTDHandler.endConditional(null); } // decreaseMarkupDepth(); fIncludeSectDepth--; fMarkUpDepth--; } else if (scanningInternalSubset() && fEntityScanner.peekChar() == ']') { // this is the end of the internal subset, let's stop here return false; } else if (fEntityScanner.skipSpaces()) { // simply skip } else { reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); // Skip the part in error int ch; do { // Ignore the current character fEntityScanner.scanChar(); // Skip any separators skipSeparator(false, true); // Keeping getting the next character, // until it's one of the expected ones ch = fEntityScanner.peekChar(); } while (ch != '<' && ch != ']' && !XMLChar.isSpace(ch)); } skipSeparator(false, true); } return fScannerState != SCANNER_STATE_END_OF_INPUT; } /** * Skip separator. This is typically just whitespace but it can also be one * or more parameter entity references. *

* 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. */ private boolean skipSeparator(boolean spaceRequired, boolean lookForPERefs) throws IOException, XNIException { int depth = fPEDepth; boolean sawSpace = fEntityScanner.skipSpaces(); if (!lookForPERefs || !fEntityScanner.skipChar('%')) { return !spaceRequired || sawSpace || (depth != fPEDepth); } while (true) { String name = fEntityScanner.scanName(); if (name == null) { reportFatalError("NameRequiredInPEReference", null); } else if (!fEntityScanner.skipChar(';')) { reportFatalError("SemicolonRequiredInPEReference", new Object[]{name}); } startPE(name, false); fEntityScanner.skipSpaces(); if (!fEntityScanner.skipChar('%')) return true; } } /* * Element Children Content Stack */ private final void pushContentStack(int c) { if (fContentStack.length == fContentDepth) { int[] newStack = new int[fContentDepth * 2]; System.arraycopy(fContentStack, 0, newStack, 0, fContentDepth); fContentStack = newStack; } fContentStack[fContentDepth++] = c; } private final int popContentStack() { return fContentStack[--fContentDepth]; } /* * Parameter Entity Stack */ private final void pushPEStack(int depth, boolean report) { if (fPEStack.length == fPEDepth) { int[] newIntStack = new int[fPEDepth * 2]; System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth); fPEStack = newIntStack; // report end/start calls boolean[] newBooleanStack = new boolean[fPEDepth * 2]; System.arraycopy(fPEReport, 0, newBooleanStack, 0, fPEDepth); fPEReport = newBooleanStack; } fPEReport[fPEDepth] = report; fPEStack[fPEDepth++] = depth; } /** pop the stack */ private final int popPEStack() { return fPEStack[--fPEDepth]; } /** look at the top of the stack */ private final boolean peekReportEntity() { return fPEReport[fPEDepth-1]; } /* * Utility method */ private final void ensureEnumerationSize(int size) { if (fEnumeration.length == size) { String[] newEnum = new String[size * 2]; System.arraycopy(fEnumeration, 0, newEnum, 0, size); fEnumeration = newEnum; } } // private methods private void init() { // reset state related data fStartDTDCalled = false; fExtEntityDepth = 0; fIncludeSectDepth = 0; fMarkUpDepth = 0; fPEDepth = 0; fStandalone = false; fSeenExternalDTD = false; fSeenPEReferences = false; // set starting state setScannerState(SCANNER_STATE_TEXT_DECL); } private int skipInvalidEnumerationValue() throws IOException { int c; do { c = fEntityScanner.scanChar(); } while (c != '|' && c != ')'); ensureEnumerationSize(fEnumerationCount + 1); fEnumeration[fEnumerationCount++] = XMLSymbols.EMPTY_STRING; return c; } } // class XMLDTDScannerImpl





© 2015 - 2024 Weber Informatics LLC | Privacy Policy