Save This Page
Home » Xerces-J-src.2.9.1 » org.apache.xerces » impl » dtd » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.xerces.impl.dtd;
   19   
   20   import org.apache.xerces.impl.Constants;
   21   import org.apache.xerces.impl.RevalidationHandler;
   22   import org.apache.xerces.impl.XMLEntityManager;
   23   import org.apache.xerces.impl.XMLErrorReporter;
   24   import org.apache.xerces.impl.dtd.models.ContentModelValidator;
   25   import org.apache.xerces.impl.dv.DTDDVFactory;
   26   import org.apache.xerces.impl.dv.DatatypeValidator;
   27   import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
   28   import org.apache.xerces.impl.msg.XMLMessageFormatter;
   29   import org.apache.xerces.impl.validation.ValidationManager;
   30   import org.apache.xerces.impl.validation.ValidationState;
   31   import org.apache.xerces.util.SymbolTable;
   32   import org.apache.xerces.util.XMLChar;
   33   import org.apache.xerces.util.XMLSymbols;
   34   import org.apache.xerces.xni.Augmentations;
   35   import org.apache.xerces.xni.NamespaceContext;
   36   import org.apache.xerces.xni.QName;
   37   import org.apache.xerces.xni.XMLAttributes;
   38   import org.apache.xerces.xni.XMLDocumentHandler;
   39   import org.apache.xerces.xni.XMLLocator;
   40   import org.apache.xerces.xni.XMLResourceIdentifier;
   41   import org.apache.xerces.xni.XMLString;
   42   import org.apache.xerces.xni.XNIException;
   43   import org.apache.xerces.xni.grammars.Grammar;
   44   import org.apache.xerces.xni.grammars.XMLGrammarDescription;
   45   import org.apache.xerces.xni.grammars.XMLGrammarPool;
   46   import org.apache.xerces.xni.parser.XMLComponent;
   47   import org.apache.xerces.xni.parser.XMLComponentManager;
   48   import org.apache.xerces.xni.parser.XMLConfigurationException;
   49   import org.apache.xerces.xni.parser.XMLDocumentFilter;
   50   import org.apache.xerces.xni.parser.XMLDocumentSource;
   51   
   52   /**
   53    * The DTD validator. The validator implements a document
   54    * filter: receiving document events from the scanner; validating
   55    * the content and structure; augmenting the InfoSet, if applicable;
   56    * and notifying the parser of the information resulting from the
   57    * validation process.
   58    * <p> Formerly, this component also handled DTD events and grammar construction.
   59    * To facilitate the development of a meaningful DTD grammar caching/preparsing
   60    * framework, this functionality has been moved into the XMLDTDLoader
   61    * class.  Therefore, this class no longer implements the DTDFilter
   62    * or DTDContentModelFilter interfaces.
   63    * <p>
   64    * This component requires the following features and properties from the
   65    * component manager that uses it:
   66    * <ul>
   67    *  <li>http://xml.org/sax/features/namespaces</li>
   68    *  <li>http://xml.org/sax/features/validation</li>
   69    *  <li>http://apache.org/xml/features/validation/dynamic</li>
   70    *  <li>http://apache.org/xml/properties/internal/symbol-table</li>
   71    *  <li>http://apache.org/xml/properties/internal/error-reporter</li>
   72    *  <li>http://apache.org/xml/properties/internal/grammar-pool</li>
   73    *  <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li>
   74    * </ul>
   75    * 
   76    * @xerces.internal
   77    *
   78    * @author Eric Ye, IBM
   79    * @author Andy Clark, IBM
   80    * @author Jeffrey Rodriguez IBM
   81    * @author Neil Graham, IBM
   82    *
   83    * @version $Id: XMLDTDValidator.java 572055 2007-09-02 17:55:43Z mrglavas $
   84    */
   85   public class XMLDTDValidator
   86           implements XMLComponent, XMLDocumentFilter, XMLDTDValidatorFilter, RevalidationHandler {
   87   
   88       //
   89       // Constants
   90       //
   91   
   92       /** Symbol: "&lt;&lt;datatypes>>". */
   93   
   94       /** Top level scope (-1). */
   95       private static final int TOP_LEVEL_SCOPE = -1;
   96   
   97       // feature identifiers
   98   
   99       /** Feature identifier: namespaces. */
  100       protected static final String NAMESPACES =
  101           Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
  102   
  103       /** Feature identifier: validation. */
  104       protected static final String VALIDATION =
  105           Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
  106   
  107       /** Feature identifier: dynamic validation. */
  108       protected static final String DYNAMIC_VALIDATION = 
  109           Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE;
  110       
  111       /** Feature identifier: balance syntax trees. */
  112       protected static final String BALANCE_SYNTAX_TREES =
  113           Constants.XERCES_FEATURE_PREFIX + Constants.BALANCE_SYNTAX_TREES;
  114   
  115       /** Feature identifier: warn on duplicate attdef */
  116       protected static final String WARN_ON_DUPLICATE_ATTDEF = 
  117           Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; 
  118       
  119   	protected static final String PARSER_SETTINGS = 
  120   		Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;	
  121   
  122   
  123   
  124       // property identifiers
  125   
  126       /** Property identifier: symbol table. */
  127       protected static final String SYMBOL_TABLE =
  128           Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
  129   
  130       /** Property identifier: error reporter. */
  131       protected static final String ERROR_REPORTER =
  132           Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
  133   
  134       /** Property identifier: grammar pool. */
  135       protected static final String GRAMMAR_POOL =
  136           Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
  137   
  138       /** Property identifier: datatype validator factory. */
  139       protected static final String DATATYPE_VALIDATOR_FACTORY =
  140           Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY;
  141   
  142       // property identifier:  ValidationManager
  143       protected static final String VALIDATION_MANAGER =
  144           Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
  145   
  146       // recognized features and properties
  147   
  148       /** Recognized features. */
  149       private static final String[] RECOGNIZED_FEATURES = {
  150           NAMESPACES,
  151           VALIDATION,
  152           DYNAMIC_VALIDATION,
  153           BALANCE_SYNTAX_TREES
  154       };
  155   
  156       /** Feature defaults. */
  157       private static final Boolean[] FEATURE_DEFAULTS = {
  158           null,
  159           null,
  160           Boolean.FALSE,
  161           Boolean.FALSE,
  162       };
  163   
  164       /** Recognized properties. */
  165       private static final String[] RECOGNIZED_PROPERTIES = {
  166           SYMBOL_TABLE,       
  167           ERROR_REPORTER,
  168           GRAMMAR_POOL,
  169           DATATYPE_VALIDATOR_FACTORY,
  170           VALIDATION_MANAGER
  171       };
  172   
  173       /** Property defaults. */
  174       private static final Object[] PROPERTY_DEFAULTS = {
  175           null,
  176           null,
  177           null,
  178           null,
  179           null,
  180       };
  181   
  182       // debugging
  183   
  184       /** Compile to true to debug attributes. */
  185       private static final boolean DEBUG_ATTRIBUTES = false;
  186   
  187       /** Compile to true to debug element children. */
  188       private static final boolean DEBUG_ELEMENT_CHILDREN = false;
  189   
  190       //        
  191       // Data
  192       //
  193   
  194       // updated during reset
  195       protected ValidationManager fValidationManager = null;
  196       
  197       // validation state
  198       protected final ValidationState fValidationState = new ValidationState();
  199   
  200       // features
  201   
  202       /** Namespaces. */
  203       protected boolean fNamespaces;
  204   
  205       /** Validation. */
  206       protected boolean fValidation;
  207   
  208       /** Validation against only DTD */
  209       protected boolean fDTDValidation;
  210   
  211       /** 
  212        * Dynamic validation. This state of this feature is only useful when
  213        * the validation feature is set to <code>true</code>.
  214        */
  215       protected boolean fDynamicValidation;
  216       
  217       /** Controls whether the DTD grammar produces balanced syntax trees. */
  218       protected boolean fBalanceSyntaxTrees;
  219   
  220       /** warn on duplicate attribute definition, this feature works only when validation is true */
  221       protected boolean fWarnDuplicateAttdef;
  222           
  223       // properties
  224   
  225       /** Symbol table. */
  226       protected SymbolTable fSymbolTable;
  227   
  228       /** Error reporter. */
  229       protected XMLErrorReporter fErrorReporter;
  230   
  231       // the grammar pool
  232       protected XMLGrammarPool fGrammarPool;
  233   
  234       /** Grammar bucket. */
  235       protected DTDGrammarBucket fGrammarBucket;
  236   
  237       /* location of the document as passed in from startDocument call */
  238       protected XMLLocator fDocLocation;
  239   
  240       /** Namespace support. */
  241       protected NamespaceContext fNamespaceContext = null;
  242   
  243       /** Datatype validator factory. */
  244       protected DTDDVFactory fDatatypeValidatorFactory;
  245   
  246       // handlers
  247   
  248       /** Document handler. */
  249       protected XMLDocumentHandler fDocumentHandler;
  250   
  251       protected XMLDocumentSource fDocumentSource;
  252       // grammars
  253   
  254       /** DTD Grammar. */
  255       protected DTDGrammar fDTDGrammar;
  256   
  257       // state
  258   
  259       /** True if seen DOCTYPE declaration. */
  260       protected boolean fSeenDoctypeDecl = false;
  261   
  262       /** Perform validation. */
  263       private boolean fPerformValidation;
  264       
  265       /** Schema type: None, DTD, Schema */
  266       private String fSchemaType;
  267   
  268       // information regarding the current element
  269   
  270       /** Current element name. */
  271       private final QName fCurrentElement = new QName();
  272   
  273       /** Current element index. */
  274       private int fCurrentElementIndex = -1;
  275   
  276       /** Current content spec type. */
  277       private int fCurrentContentSpecType = -1;
  278   
  279       /** The root element name. */
  280       private final QName fRootElement = new QName();
  281   
  282       private boolean fInCDATASection = false;
  283       // element stack
  284   
  285       /** Element index stack. */
  286       private int[] fElementIndexStack = new int[8];
  287   
  288       /** Content spec type stack. */
  289       private int[] fContentSpecTypeStack = new int[8];
  290   
  291       /** Element name stack. */
  292       private QName[] fElementQNamePartsStack = new QName[8];
  293   
  294       // children list and offset stack
  295   
  296       /** 
  297        * Element children. This data structure is a growing stack that
  298        * holds the children of elements from the root to the current
  299        * element depth. This structure never gets "deeper" than the
  300        * deepest element. Space is re-used once each element is closed.
  301        * <p>
  302        * <strong>Note:</strong> This is much more efficient use of memory
  303        * than creating new arrays for each element depth.
  304        * <p>
  305        * <strong>Note:</strong> The use of this data structure is for
  306        * validation "on the way out". If the validation model changes to
  307        * "on the way in", then this data structure is not needed.
  308        */
  309       private QName[] fElementChildren = new QName[32];
  310   
  311       /** Element children count. */
  312       private int fElementChildrenLength = 0;
  313   
  314       /** 
  315        * Element children offset stack. This stack refers to offsets
  316        * into the <code>fElementChildren</code> array.
  317        * @see #fElementChildren
  318        */
  319       private int[] fElementChildrenOffsetStack = new int[32];
  320   
  321       /** Element depth. */
  322       private int fElementDepth = -1;
  323   
  324       // validation states
  325   
  326       /** True if seen the root element. */
  327       private boolean fSeenRootElement = false;
  328   
  329       /** True if inside of element content. */
  330       private boolean fInElementContent = false;
  331   
  332       // temporary variables
  333   
  334       /** Temporary element declaration. */
  335       private XMLElementDecl fTempElementDecl = new XMLElementDecl();
  336   
  337       /** Temporary atribute declaration. */
  338       private XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl();
  339   
  340       /** Temporary entity declaration. */
  341       private XMLEntityDecl fEntityDecl = new XMLEntityDecl();
  342   
  343       /** Temporary qualified name. */
  344       private QName fTempQName = new QName();
  345   
  346       /** Temporary string buffers. */
  347       private StringBuffer fBuffer = new StringBuffer();
  348   
  349       // symbols: general
  350   
  351       // attribute validators
  352   
  353       /** Datatype validator: ID. */
  354       protected DatatypeValidator fValID;
  355   
  356       /** Datatype validator: IDREF. */
  357       protected DatatypeValidator fValIDRef;
  358   
  359       /** Datatype validator: IDREFS. */
  360       protected DatatypeValidator fValIDRefs;
  361   
  362       /** Datatype validator: ENTITY. */
  363       protected DatatypeValidator fValENTITY;
  364   
  365       /** Datatype validator: ENTITIES. */
  366       protected DatatypeValidator fValENTITIES;
  367   
  368       /** Datatype validator: NMTOKEN. */
  369       protected DatatypeValidator fValNMTOKEN;
  370   
  371       /** Datatype validator: NMTOKENS. */
  372       protected DatatypeValidator fValNMTOKENS;
  373   
  374       /** Datatype validator: NOTATION. */
  375       protected DatatypeValidator fValNOTATION;
  376   
  377       // to check for duplicate ID or ANNOTATION attribute declare in
  378       // ATTLIST, and misc VCs
  379   
  380       //
  381       // Constructors
  382       //
  383   
  384       /** Default constructor. */
  385       public XMLDTDValidator() {
  386   
  387           // initialize data
  388           for (int i = 0; i < fElementQNamePartsStack.length; i++) {
  389               fElementQNamePartsStack[i] = new QName();
  390           }
  391           fGrammarBucket = new DTDGrammarBucket();
  392   
  393       } // <init>()
  394   
  395       DTDGrammarBucket getGrammarBucket() {
  396           return fGrammarBucket;
  397       } // getGrammarBucket():  DTDGrammarBucket
  398   
  399       //
  400       // XMLComponent methods
  401       //
  402   
  403       /*
  404        * Resets the component. The component can query the component manager
  405        * about any features and properties that affect the operation of the
  406        * component.
  407        * 
  408        * @param componentManager The component manager.
  409        *
  410        * @throws SAXException Thrown by component on finitialization error.
  411        *                      For example, if a feature or property is
  412        *                      required for the operation of the component, the
  413        *                      component manager may throw a 
  414        *                      SAXNotRecognizedException or a
  415        *                      SAXNotSupportedException.
  416        */
  417       public void reset(XMLComponentManager componentManager)
  418       throws XMLConfigurationException {
  419   
  420           // clear grammars
  421           fDTDGrammar = null;
  422           fSeenDoctypeDecl = false;
  423           fInCDATASection = false;
  424           // initialize state
  425           fSeenRootElement = false;
  426           fInElementContent = false;
  427           fCurrentElementIndex = -1;
  428           fCurrentContentSpecType = -1;
  429   
  430           fRootElement.clear();
  431   
  432   		fValidationState.resetIDTables();
  433   		
  434   		fGrammarBucket.clear();
  435   		fElementDepth = -1;                      
  436   		fElementChildrenLength = 0;
  437           
  438           boolean parser_settings;
  439           try {
  440           	parser_settings = componentManager.getFeature(PARSER_SETTINGS);  	
  441           }
  442           catch (XMLConfigurationException e){
  443           	parser_settings = true;
  444           }
  445           
  446           if (!parser_settings){
  447           	// parser settings have not been changed
  448   			fValidationManager.addValidationState(fValidationState);
  449           	return;
  450           }
  451   
  452           // sax features
  453           try {
  454               fNamespaces = componentManager.getFeature(NAMESPACES);
  455           }
  456           catch (XMLConfigurationException e) {
  457               fNamespaces = true;
  458           }
  459           try {
  460               fValidation = componentManager.getFeature(VALIDATION);
  461           }
  462           catch (XMLConfigurationException e) {
  463               fValidation = false;
  464           }
  465           try {
  466               fDTDValidation = !(componentManager.getFeature(Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE));
  467           }
  468           catch (XMLConfigurationException e) {
  469               // must be in a schema-less configuration!
  470               fDTDValidation = true;
  471           }
  472   
  473           // Xerces features
  474           try {
  475               fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION);
  476           }
  477           catch (XMLConfigurationException e) {
  478               fDynamicValidation = false;
  479           }
  480           
  481           try {
  482               fBalanceSyntaxTrees = componentManager.getFeature(BALANCE_SYNTAX_TREES);
  483           }
  484           catch (XMLConfigurationException e) {
  485               fBalanceSyntaxTrees = false;
  486           }
  487           
  488           try {
  489               fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF);
  490           }
  491           catch (XMLConfigurationException e) {
  492               fWarnDuplicateAttdef = false;
  493           }
  494           
  495           try {
  496               fSchemaType = (String)componentManager.getProperty (Constants.JAXP_PROPERTY_PREFIX 
  497               + Constants.SCHEMA_LANGUAGE);           
  498           }
  499           catch (XMLConfigurationException e){
  500               fSchemaType = null;
  501           }
  502   
  503           fValidationManager= (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER);
  504           fValidationManager.addValidationState(fValidationState);      
  505           fValidationState.setUsingNamespaces(fNamespaces);
  506           
  507           // get needed components
  508           fErrorReporter = (XMLErrorReporter)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.ERROR_REPORTER_PROPERTY);
  509           fSymbolTable = (SymbolTable)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.SYMBOL_TABLE_PROPERTY);
  510           try {
  511               fGrammarPool= (XMLGrammarPool)componentManager.getProperty(GRAMMAR_POOL);
  512           } catch (XMLConfigurationException e) {
  513               fGrammarPool = null;
  514           }
  515   
  516           fDatatypeValidatorFactory = (DTDDVFactory)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY);
  517   		init();
  518   
  519       } // reset(XMLComponentManager)
  520   
  521       /**
  522        * Returns a list of feature identifiers that are recognized by
  523        * this component. This method may return null if no features
  524        * are recognized by this component.
  525        */
  526       public String[] getRecognizedFeatures() {
  527           return (String[])(RECOGNIZED_FEATURES.clone());
  528       } // getRecognizedFeatures():String[]
  529   
  530       /**
  531        * Sets the state of a feature. This method is called by the component
  532        * manager any time after reset when a feature changes state. 
  533        * <p>
  534        * <strong>Note:</strong> Components should silently ignore features
  535        * that do not affect the operation of the component.
  536        * 
  537        * @param featureId The feature identifier.
  538        * @param state     The state of the feature.
  539        *
  540        * @throws SAXNotRecognizedException The component should not throw
  541        *                                   this exception.
  542        * @throws SAXNotSupportedException The component should not throw
  543        *                                  this exception.
  544        */
  545       public void setFeature(String featureId, boolean state)
  546       throws XMLConfigurationException {
  547       } // setFeature(String,boolean)
  548   
  549       /**
  550        * Returns a list of property identifiers that are recognized by
  551        * this component. This method may return null if no properties
  552        * are recognized by this component.
  553        */
  554       public String[] getRecognizedProperties() {
  555           return (String[])(RECOGNIZED_PROPERTIES.clone());
  556       } // getRecognizedProperties():String[]
  557   
  558       /**
  559        * Sets the value of a property. This method is called by the component
  560        * manager any time after reset when a property changes value. 
  561        * <p>
  562        * <strong>Note:</strong> Components should silently ignore properties
  563        * that do not affect the operation of the component.
  564        * 
  565        * @param propertyId The property identifier.
  566        * @param value      The value of the property.
  567        *
  568        * @throws SAXNotRecognizedException The component should not throw
  569        *                                   this exception.
  570        * @throws SAXNotSupportedException The component should not throw
  571        *                                  this exception.
  572        */
  573       public void setProperty(String propertyId, Object value)
  574       throws XMLConfigurationException {
  575       } // setProperty(String,Object)
  576   
  577       /** 
  578        * Returns the default state for a feature, or null if this
  579        * component does not want to report a default value for this
  580        * feature.
  581        *
  582        * @param featureId The feature identifier.
  583        *
  584        * @since Xerces 2.2.0
  585        */
  586       public Boolean getFeatureDefault(String featureId) {
  587           for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
  588               if (RECOGNIZED_FEATURES[i].equals(featureId)) {
  589                   return FEATURE_DEFAULTS[i];
  590               }
  591           }
  592           return null;
  593       } // getFeatureDefault(String):Boolean
  594   
  595       /** 
  596        * Returns the default state for a property, or null if this
  597        * component does not want to report a default value for this
  598        * property. 
  599        *
  600        * @param propertyId The property identifier.
  601        *
  602        * @since Xerces 2.2.0
  603        */
  604       public Object getPropertyDefault(String propertyId) {
  605           for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
  606               if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
  607                   return PROPERTY_DEFAULTS[i];
  608               }
  609           }
  610           return null;
  611       } // getPropertyDefault(String):Object
  612   
  613       //
  614       // XMLDocumentSource methods
  615       //
  616   
  617       /** Sets the document handler to receive information about the document. */
  618       public void setDocumentHandler(XMLDocumentHandler documentHandler) {
  619           fDocumentHandler = documentHandler;
  620       } // setDocumentHandler(XMLDocumentHandler)
  621   
  622       /** Returns the document handler */
  623       public XMLDocumentHandler getDocumentHandler() {
  624           return fDocumentHandler;
  625       } // getDocumentHandler():  XMLDocumentHandler
  626   
  627   
  628       //
  629       // XMLDocumentHandler methods
  630       //
  631   
  632       /** Sets the document source */
  633       public void setDocumentSource(XMLDocumentSource source){
  634           fDocumentSource = source;
  635       } // setDocumentSource
  636   
  637       /** Returns the document source */
  638       public XMLDocumentSource getDocumentSource (){
  639           return fDocumentSource;
  640       } // getDocumentSource
  641   
  642       /**
  643        * The start of the document.
  644        *
  645        * @param locator The system identifier of the entity if the entity
  646        *                 is external, null otherwise.
  647        * @param encoding The auto-detected IANA encoding name of the entity
  648        *                 stream. This value will be null in those situations
  649        *                 where the entity encoding is not auto-detected (e.g.
  650        *                 internal entities or a document entity that is
  651        *                 parsed from a java.io.Reader).
  652        * @param namespaceContext
  653        *                 The namespace context in effect at the
  654        *                 start of this document.
  655        *                 This object represents the current context.
  656        *                 Implementors of this class are responsible
  657        *                 for copying the namespace bindings from the
  658        *                 the current context (and its parent contexts)
  659        *                 if that information is important.
  660        * @param augs   Additional information that may include infoset augmentations
  661        *
  662        * @throws XNIException Thrown by handler to signal an error.
  663        */
  664       public void startDocument(XMLLocator locator, String encoding, 
  665                                 NamespaceContext namespaceContext, Augmentations augs) 
  666       throws XNIException {
  667   
  668           // call handlers
  669           // get initial grammars
  670           if(fGrammarPool != null) {
  671               Grammar [] grammars = fGrammarPool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_DTD);
  672               for(int i = 0; i<grammars.length; i++) {
  673                   fGrammarBucket.putGrammar((DTDGrammar)grammars[i]);
  674               }
  675           }
  676           fDocLocation = locator;
  677           fNamespaceContext = namespaceContext;
  678      
  679           if (fDocumentHandler != null) {
  680               fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs);
  681           }
  682   
  683       } // startDocument(XMLLocator,String)
  684   
  685       /**
  686        * Notifies of the presence of an XMLDecl line in the document. If
  687        * present, this method will be called immediately following the
  688        * startDocument call.
  689        * 
  690        * @param version    The XML version.
  691        * @param encoding   The IANA encoding name of the document, or null if
  692        *                   not specified.
  693        * @param standalone The standalone value, or null if not specified.     
  694        * @param augs   Additional information that may include infoset augmentations
  695        *
  696        * @throws XNIException Thrown by handler to signal an error.
  697        */
  698       public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
  699       throws XNIException {
  700   
  701           // save standalone state
  702           fGrammarBucket.setStandalone(standalone != null && standalone.equals("yes"));
  703   
  704           // call handlers
  705           if (fDocumentHandler != null) {
  706               fDocumentHandler.xmlDecl(version, encoding, standalone, augs);
  707           }
  708   
  709       } // xmlDecl(String,String,String)
  710   
  711       /**
  712        * Notifies of the presence of the DOCTYPE line in the document.
  713        * 
  714        * @param rootElement The name of the root element.
  715        * @param publicId    The public identifier if an external DTD or null
  716        *                    if the external DTD is specified using SYSTEM.
  717        * @param systemId    The system identifier if an external DTD, null
  718        *                    otherwise.     
  719        * @param augs   Additional information that may include infoset augmentations
  720        *
  721        * @throws XNIException Thrown by handler to signal an error.
  722        */
  723       public void doctypeDecl(String rootElement, String publicId, String systemId, 
  724                               Augmentations augs)
  725       throws XNIException {
  726   
  727           // save root element state
  728           fSeenDoctypeDecl = true;
  729           fRootElement.setValues(null, rootElement, rootElement, null);
  730           // find or create grammar:
  731           String eid = null;
  732           try {
  733               eid = XMLEntityManager.expandSystemId(systemId, fDocLocation.getExpandedSystemId(), false);
  734           } catch (java.io.IOException e) {
  735           }
  736           XMLDTDDescription grammarDesc = new XMLDTDDescription(publicId, systemId, fDocLocation.getExpandedSystemId(), eid, rootElement);
  737           fDTDGrammar = fGrammarBucket.getGrammar(grammarDesc);
  738           if(fDTDGrammar == null) {
  739               // give grammar pool a chance...
  740               //
  741               // Do not bother checking the pool if no public or system identifier was provided. 
  742               // Since so many different DTDs have roots in common, using only a root name as the 
  743               // key may cause an unexpected grammar to be retrieved from the grammar pool. This scenario
  744               // would occur when an ExternalSubsetResolver has been queried and the
  745               // XMLInputSource returned contains an input stream but no external identifier.
  746               // This can never happen when the instance document specified a DOCTYPE. -- mrglavas
  747               if (fGrammarPool != null && (systemId != null || publicId != null)) {
  748                   fDTDGrammar = (DTDGrammar)fGrammarPool.retrieveGrammar(grammarDesc);
  749               }
  750           }
  751           if(fDTDGrammar == null) {
  752               // we'll have to create it...
  753               if (!fBalanceSyntaxTrees) {
  754                   fDTDGrammar = new DTDGrammar(fSymbolTable, grammarDesc);
  755               }
  756               else {
  757                   fDTDGrammar = new BalancedDTDGrammar(fSymbolTable, grammarDesc);
  758               }
  759           } else {
  760               // we've found a cached one;so let's make sure not to read
  761               // any external subset!
  762               fValidationManager.setCachedDTD(true);
  763           }
  764           fGrammarBucket.setActiveGrammar(fDTDGrammar);
  765   
  766           // call handlers
  767           if (fDocumentHandler != null) {
  768               fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs);
  769           }
  770   
  771       } // doctypeDecl(String,String,String, Augmentations)
  772   
  773   
  774       /**
  775        * The start of an element.
  776        * 
  777        * @param element    The name of the element.
  778        * @param attributes The element attributes.     
  779        * @param augs   Additional information that may include infoset augmentations
  780        *
  781        * @throws XNIException Thrown by handler to signal an error.
  782        */
  783       public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
  784       throws XNIException {
  785   
  786           handleStartElement(element, attributes, augs);
  787           // call handlers
  788           if (fDocumentHandler != null) {
  789               fDocumentHandler.startElement(element, attributes, augs);
  790   
  791           }
  792   
  793       } // startElement(QName,XMLAttributes)
  794   
  795       /**
  796        * An empty element.
  797        * 
  798        * @param element    The name of the element.
  799        * @param attributes The element attributes.     
  800        * @param augs   Additional information that may include infoset augmentations
  801        *
  802        * @throws XNIException Thrown by handler to signal an error.
  803        */
  804       public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
  805       throws XNIException {
  806   
  807           boolean removed = handleStartElement(element, attributes, augs);
  808   
  809           if (fDocumentHandler !=null) {
  810               fDocumentHandler.emptyElement(element, attributes, augs);
  811           }
  812           if (!removed) {
  813               handleEndElement(element, augs, true);
  814           }
  815           
  816   
  817       } // emptyElement(QName,XMLAttributes)
  818   
  819       /**
  820        * Character content.
  821        * 
  822        * @param text The content.
  823        *
  824        * @param augs   Additional information that may include infoset augmentations
  825        *
  826        * @throws XNIException Thrown by handler to signal an error.
  827        */
  828       public void characters(XMLString text, Augmentations augs) throws XNIException {
  829   
  830           boolean callNextCharacters = true;
  831   
  832           // REVISIT: [Q] Is there a more efficient way of doing this?
  833           //          Perhaps if the scanner told us so we don't have to
  834           //          look at the characters again. -Ac
  835           boolean allWhiteSpace = true;
  836           for (int i=text.offset; i< text.offset+text.length; i++) {
  837               if (!isSpace(text.ch[i])) {
  838                   allWhiteSpace = false;
  839                   break;
  840               }
  841           }
  842           // call the ignoreableWhiteSpace callback
  843           // never call ignorableWhitespace if we are in cdata section
  844           if (fInElementContent && allWhiteSpace && !fInCDATASection) {
  845               if (fDocumentHandler != null) {
  846                   fDocumentHandler.ignorableWhitespace(text, augs);
  847                   callNextCharacters = false;
  848               }
  849           }
  850   
  851           // validate
  852           if (fPerformValidation) {
  853               if (fInElementContent) {
  854                   if (fGrammarBucket.getStandalone() &&
  855                       fDTDGrammar.getElementDeclIsExternal(fCurrentElementIndex)) {
  856                       if (allWhiteSpace) {
  857                           fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
  858                                                       "MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE",
  859                                                       null, XMLErrorReporter.SEVERITY_ERROR);
  860                       }
  861                   }
  862                   if (!allWhiteSpace) {
  863                       charDataInContent();
  864                   }
  865                   
  866                   // For E15.2
  867                   if (augs != null && augs.getItem(Constants.CHAR_REF_PROBABLE_WS) == Boolean.TRUE) {
  868                       fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 
  869                                                  "MSG_CONTENT_INVALID_SPECIFIED",
  870                                                  new Object[]{ fCurrentElement.rawname, 
  871                                                      fDTDGrammar.getContentSpecAsString(fElementDepth),
  872                                                      "character reference"},
  873                                                  XMLErrorReporter.SEVERITY_ERROR);                
  874                   }
  875               }
  876   
  877               if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
  878                   charDataInContent();
  879               }
  880           }
  881   
  882           // call handlers
  883           if (callNextCharacters && fDocumentHandler != null) {
  884               fDocumentHandler.characters(text, augs);
  885           }
  886   
  887       } // characters(XMLString)
  888   
  889   
  890   
  891       /**
  892        * Ignorable whitespace. For this method to be called, the document
  893        * source must have some way of determining that the text containing
  894        * only whitespace characters should be considered ignorable. For
  895        * example, the validator can determine if a length of whitespace
  896        * characters in the document are ignorable based on the element
  897        * content model.
  898        * 
  899        * @param text The ignorable whitespace.
  900        * @param augs   Additional information that may include infoset augmentations
  901        *
  902        * @throws XNIException Thrown by handler to signal an error.
  903        */
  904       public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
  905   
  906           // call handlers
  907           if (fDocumentHandler != null) {
  908               fDocumentHandler.ignorableWhitespace(text, augs);
  909           }
  910   
  911       } // ignorableWhitespace(XMLString)
  912   
  913       /**
  914        * The end of an element.
  915        * 
  916        * @param element The name of the element.
  917        * @param augs   Additional information that may include infoset augmentations
  918        *
  919        * @throws XNIException Thrown by handler to signal an error.
  920        */
  921       public void endElement(QName element, Augmentations augs) throws XNIException {
  922   
  923           handleEndElement(element,  augs, false);
  924   
  925       } // endElement(QName)
  926   
  927       /** 
  928        * The start of a CDATA section. 
  929        * @param augs   Additional information that may include infoset augmentations
  930        *
  931        * @throws XNIException Thrown by handler to signal an error.
  932        */
  933       public void startCDATA(Augmentations augs) throws XNIException {
  934   
  935           if (fPerformValidation && fInElementContent) {
  936               charDataInContent();
  937           }
  938           fInCDATASection = true;
  939           // call handlers
  940           if (fDocumentHandler != null) {
  941               fDocumentHandler.startCDATA(augs);
  942           }
  943   
  944       } // startCDATA()
  945   
  946       /**
  947        * The end of a CDATA section. 
  948        * @param augs   Additional information that may include infoset augmentations
  949        *
  950        * @throws XNIException Thrown by handler to signal an error.
  951        */
  952       public void endCDATA(Augmentations augs) throws XNIException {
  953   
  954           fInCDATASection = false;
  955           // call handlers
  956           if (fDocumentHandler != null) {
  957               fDocumentHandler.endCDATA(augs);
  958           }
  959   
  960       } // endCDATA()
  961   
  962       /**
  963        * The end of the document.
  964        * @param augs   Additional information that may include infoset augmentations
  965        *
  966        * @throws XNIException Thrown by handler to signal an error.
  967        */
  968       public void endDocument(Augmentations augs) throws XNIException {
  969   
  970           // call handlers
  971           if (fDocumentHandler != null) {
  972               fDocumentHandler.endDocument(augs);
  973           }
  974   
  975       } // endDocument()
  976   
  977       /**
  978        * A comment.
  979        * 
  980        * @param text The text in the comment.
  981        * @param augs   Additional information that may include infoset augmentations
  982        *
  983        * @throws XNIException Thrown by application to signal an error.
  984        */
  985       public void comment(XMLString text, Augmentations augs) throws XNIException {
  986           // fixes E15.1
  987           if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) {
  988               fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl);
  989               if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
  990                       fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 
  991                                                  "MSG_CONTENT_INVALID_SPECIFIED",
  992                                                  new Object[]{ fCurrentElement.rawname,
  993                                                                "EMPTY",
  994                                                                "comment"},
  995                                                  XMLErrorReporter.SEVERITY_ERROR);                
  996               }
  997           }
  998           // call handlers
  999           if (fDocumentHandler != null) {
 1000               fDocumentHandler.comment(text, augs);
 1001           }
 1002   
 1003       } // comment(XMLString)
 1004   
 1005   
 1006       /**
 1007        * A processing instruction. Processing instructions consist of a
 1008        * target name and, optionally, text data. The data is only meaningful
 1009        * to the application.
 1010        * <p>
 1011        * Typically, a processing instruction's data will contain a series
 1012        * of pseudo-attributes. These pseudo-attributes follow the form of
 1013        * element attributes but are <strong>not</strong> parsed or presented
 1014        * to the application as anything other than text. The application is
 1015        * responsible for parsing the data.
 1016        * 
 1017        * @param target The target.
 1018        * @param data   The data or null if none specified.     
 1019        * @param augs   Additional information that may include infoset augmentations
 1020        *
 1021        * @throws XNIException Thrown by handler to signal an error.
 1022        */
 1023       public void processingInstruction(String target, XMLString data, Augmentations augs)
 1024       throws XNIException {
 1025   
 1026           // fixes E15.1
 1027           if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) {
 1028               fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl);
 1029               if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
 1030                       fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 
 1031                                                  "MSG_CONTENT_INVALID_SPECIFIED",
 1032                                                  new Object[]{ fCurrentElement.rawname,
 1033                                                                "EMPTY",
 1034                                                                "processing instruction"},
 1035                                                  XMLErrorReporter.SEVERITY_ERROR);                
 1036               }
 1037           }
 1038           // call handlers
 1039           if (fDocumentHandler != null) {
 1040               fDocumentHandler.processingInstruction(target, data, augs);
 1041           }
 1042       } // processingInstruction(String,XMLString)
 1043   
 1044       /**
 1045        * This method notifies the start of a general entity.
 1046        * <p>
 1047        * <strong>Note:</strong> This method is not called for entity references
 1048        * appearing as part of attribute values.
 1049        * 
 1050        * @param name     The name of the general entity.
 1051        * @param identifier The resource identifier.
 1052        * @param encoding The auto-detected IANA encoding name of the entity
 1053        *                 stream. This value will be null in those situations
 1054        *                 where the entity encoding is not auto-detected (e.g.
 1055        *                 internal entities or a document entity that is
 1056        *                 parsed from a java.io.Reader).
 1057        * @param augs     Additional information that may include infoset augmentations
 1058        *                 
 1059        * @exception XNIException Thrown by handler to signal an error.
 1060        */
 1061       public void startGeneralEntity(String name, 
 1062                                      XMLResourceIdentifier identifier,
 1063                                      String encoding, 
 1064                                      Augmentations augs) throws XNIException {
 1065           if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) {
 1066               fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl);
 1067               // fixes E15.1
 1068               if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
 1069                   fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 
 1070                                              "MSG_CONTENT_INVALID_SPECIFIED",
 1071                                              new Object[]{ fCurrentElement.rawname,
 1072                                                            "EMPTY", "ENTITY"},
 1073                                              XMLErrorReporter.SEVERITY_ERROR);                
 1074               }
 1075               if (fGrammarBucket.getStandalone()) {
 1076                   XMLDTDLoader.checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter);
 1077               }
 1078           }
 1079           if (fDocumentHandler != null) {
 1080               fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs);
 1081           }
 1082       }
 1083   
 1084       /**
 1085        * This method notifies the end of a general entity.
 1086        * <p>
 1087        * <strong>Note:</strong> This method is not called for entity references
 1088        * appearing as part of attribute values.
 1089        * 
 1090        * @param name   The name of the entity.
 1091        * @param augs   Additional information that may include infoset augmentations
 1092        *               
 1093        * @exception XNIException
 1094        *                   Thrown by handler to signal an error.
 1095        */
 1096       public void endGeneralEntity(String name, Augmentations augs) throws XNIException {
 1097           // call handlers
 1098           if (fDocumentHandler != null) {
 1099               fDocumentHandler.endGeneralEntity(name, augs);
 1100           }
 1101       } // endEntity(String)
 1102   
 1103       /**
 1104        * Notifies of the presence of a TextDecl line in an entity. If present,
 1105        * this method will be called immediately following the startParameterEntity call.
 1106        * <p>
 1107        * <strong>Note:</strong> This method is only called for external
 1108        * parameter entities referenced in the DTD.
 1109        * 
 1110        * @param version  The XML version, or null if not specified.
 1111        * @param encoding The IANA encoding name of the entity.
 1112        * @param augs Additional information that may include infoset
 1113        *                      augmentations.
 1114        *
 1115        * @throws XNIException Thrown by handler to signal an error.
 1116        */
 1117       public void textDecl(String version, String encoding, Augmentations augs) throws XNIException {
 1118   
 1119           // call handlers
 1120           if (fDocumentHandler != null) {
 1121               fDocumentHandler.textDecl(version, encoding, augs);
 1122           }
 1123       }
 1124   
 1125   
 1126       public final boolean hasGrammar(){
 1127           
 1128           return (fDTDGrammar != null);
 1129       }
 1130       
 1131       public final boolean validate(){
 1132           // Do validation if all of the following are true:
 1133           // 1. The JAXP Schema Language property is not XML Schema
 1134           //    REVISIT: since only DTD and Schema are supported at this time,
 1135           //             such checking is sufficient. but if more schema types
 1136           //             are introduced in the future, we'll need to change it
 1137           //             to something like
 1138           //             (fSchemaType == null || fSchemaType == NS_XML_DTD)
 1139           // 2. One of the following is true (validation features)
 1140           // 2.1 Dynamic validation is off, and validation is on
 1141           // 2.2 Dynamic validation is on, and DOCTYPE was seen
 1142           // 3 Xerces schema validation feature is off, or DOCTYPE was seen.
 1143           return (fSchemaType != Constants.NS_XMLSCHEMA) && 
 1144                  (!fDynamicValidation && fValidation ||
 1145                   fDynamicValidation && fSeenDoctypeDecl) &&
 1146                  (fDTDValidation || fSeenDoctypeDecl);
 1147       }
 1148       
 1149               //REVISIT:we can convert into functions.. adding default attribute values.. and one validating.
 1150   
 1151       /** Add default attributes and validate. */
 1152       protected void addDTDDefaultAttrsAndValidate(QName elementName, int elementIndex, 
 1153                                                  XMLAttributes attributes) 
 1154       throws XNIException {
 1155   
 1156           // is there anything to do?
 1157           if (elementIndex == -1 || fDTDGrammar == null) {
 1158               return;
 1159           }
 1160   
 1161           //
 1162           // Check after all specified attrs are scanned
 1163           // (1) report error for REQUIRED attrs that are missing (V_TAGc)
 1164           // (2) add default attrs (FIXED and NOT_FIXED)
 1165           //
 1166           int attlistIndex = fDTDGrammar.getFirstAttributeDeclIndex(elementIndex);
 1167   
 1168           while (attlistIndex != -1) {
 1169   
 1170               fDTDGrammar.getAttributeDecl(attlistIndex, fTempAttDecl);
 1171   
 1172               if (DEBUG_ATTRIBUTES) {
 1173                   if (fTempAttDecl != null) {
 1174                       XMLElementDecl elementDecl = new XMLElementDecl();
 1175                       fDTDGrammar.getElementDecl(elementIndex, elementDecl);
 1176                       System.out.println("element: "+(elementDecl.name.localpart));
 1177                       System.out.println("attlistIndex " + attlistIndex + "\n"+
 1178                                          "attName : '"+(fTempAttDecl.name.localpart) + "'\n"
 1179                                          + "attType : "+fTempAttDecl.simpleType.type + "\n"
 1180                                          + "attDefaultType : "+fTempAttDecl.simpleType.defaultType + "\n"
 1181                                          + "attDefaultValue : '"+fTempAttDecl.simpleType.defaultValue + "'\n"
 1182                                          + attributes.getLength() +"\n"
 1183                                         );
 1184                   }
 1185               }
 1186               String attPrefix = fTempAttDecl.name.prefix;
 1187               String attLocalpart = fTempAttDecl.name.localpart;
 1188               String attRawName = fTempAttDecl.name.rawname;
 1189               String attType = getAttributeTypeName(fTempAttDecl);
 1190               int attDefaultType =fTempAttDecl.simpleType.defaultType;
 1191               String attValue = null;
 1192                               
 1193               if (fTempAttDecl.simpleType.defaultValue != null) {
 1194                   attValue = fTempAttDecl.simpleType.defaultValue;
 1195               }
 1196               
 1197               boolean specified = false;
 1198               boolean required = attDefaultType == XMLSimpleType.DEFAULT_TYPE_REQUIRED;
 1199               boolean cdata = attType == XMLSymbols.fCDATASymbol;
 1200   
 1201               if (!cdata || required || attValue != null) {
 1202                   int attrCount = attributes.getLength();
 1203                   for (int i = 0; i < attrCount; i++) {
 1204                       if (attributes.getQName(i) == attRawName) {
 1205                           specified = true;
 1206                           break;
 1207                       }
 1208                   }
 1209               }
 1210   
 1211               if (!specified) {
 1212                   if (required) {
 1213                       if (fPerformValidation) {
 1214                           Object[] args = {elementName.localpart, attRawName};
 1215                           fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1216                                                      "MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED", args,
 1217                                                      XMLErrorReporter.SEVERITY_ERROR);
 1218                       }
 1219                   }
 1220                   else if (attValue != null) {
 1221                       if (fPerformValidation && fGrammarBucket.getStandalone()) {
 1222                           if (fDTDGrammar.getAttributeDeclIsExternal(attlistIndex)) {
 1223   
 1224                               Object[] args = { elementName.localpart, attRawName};
 1225                               fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1226                                                          "MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED", args,
 1227                                                          XMLErrorReporter.SEVERITY_ERROR);
 1228                           }
 1229                       }
 1230   
 1231                       // add namespace information
 1232                       if (fNamespaces) {
 1233                           int index = attRawName.indexOf(':');
 1234                           if (index != -1) {
 1235                               attPrefix = attRawName.substring(0, index);
 1236                               attPrefix = fSymbolTable.addSymbol(attPrefix);
 1237                               attLocalpart = attRawName.substring(index + 1);
 1238                               attLocalpart = fSymbolTable.addSymbol(attLocalpart);
 1239                           }
 1240                       }
 1241   
 1242                       // add attribute
 1243                       fTempQName.setValues(attPrefix, attLocalpart, attRawName, fTempAttDecl.name.uri);
 1244                       int newAttr = attributes.addAttribute(fTempQName, attType, attValue);
 1245                   }
 1246               }
 1247               // get next att decl in the Grammar for this element
 1248               attlistIndex = fDTDGrammar.getNextAttributeDeclIndex(attlistIndex);
 1249           }
 1250   
 1251           // now iterate through the expanded attributes for
 1252           // 1. if every attribute seen is declared in the DTD
 1253           // 2. check if the VC: default_fixed holds
 1254           // 3. validate every attribute.
 1255           int attrCount = attributes.getLength();
 1256           for (int i = 0; i < attrCount; i++) {
 1257               String attrRawName = attributes.getQName(i);
 1258               boolean declared = false;
 1259               if (fPerformValidation) {
 1260                   if (fGrammarBucket.getStandalone()) {
 1261                       // check VC: Standalone Document Declaration, entities
 1262                       // references appear in the document.
 1263                       // REVISIT: this can be combined to a single check in
 1264                       // startEntity if we add one more argument in
 1265                       // startEnity, inAttrValue
 1266                       String nonNormalizedValue = attributes.getNonNormalizedValue(i);
 1267                       if (nonNormalizedValue != null) {
 1268                           String entityName = getExternalEntityRefInAttrValue(nonNormalizedValue);
 1269                           if (entityName != null) {
 1270                               fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1271                                                          "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE",
 1272                                                          new Object[]{entityName},
 1273                                                          XMLErrorReporter.SEVERITY_ERROR);
 1274                           }
 1275                       }
 1276                   }
 1277               }
 1278               int attDefIndex = -1;
 1279               int position =
 1280               fDTDGrammar.getFirstAttributeDeclIndex(elementIndex);
 1281               while (position != -1) {
 1282                   fDTDGrammar.getAttributeDecl(position, fTempAttDecl);
 1283                   if (fTempAttDecl.name.rawname == attrRawName) {
 1284                       // found the match att decl, 
 1285                       attDefIndex = position;
 1286                       declared = true;
 1287                       break;
 1288                   }
 1289                   position = fDTDGrammar.getNextAttributeDeclIndex(position);
 1290               }
 1291               if (!declared) {
 1292                   if (fPerformValidation) {
 1293                       // REVISIT - cache the elem/attr tuple so that we only
 1294                       // give this error once for each unique occurrence
 1295                       Object[] args = { elementName.rawname, attrRawName};
 1296   
 1297                       fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1298                                                  "MSG_ATTRIBUTE_NOT_DECLARED",
 1299                                                  args,XMLErrorReporter.SEVERITY_ERROR);   
 1300                   }
 1301                   continue;
 1302               }
 1303               // attribute is declared
 1304   
 1305               // fTempAttDecl should have the right value set now, so
 1306               // the following is not needed
 1307               // fGrammar.getAttributeDecl(attDefIndex,fTempAttDecl);
 1308   
 1309               String type = getAttributeTypeName(fTempAttDecl);
 1310               attributes.setType(i, type);
 1311               attributes.getAugmentations(i).putItem(Constants.ATTRIBUTE_DECLARED, Boolean.TRUE);
 1312   
 1313               boolean changedByNormalization = false;
 1314               String oldValue = attributes.getValue(i);
 1315               String attrValue = oldValue;
 1316               if (attributes.isSpecified(i) && type != XMLSymbols.fCDATASymbol) {
 1317                   changedByNormalization = normalizeAttrValue(attributes, i);
 1318                   attrValue = attributes.getValue(i);
 1319                   if (fPerformValidation && fGrammarBucket.getStandalone()
 1320                       && changedByNormalization 
 1321                       && fDTDGrammar.getAttributeDeclIsExternal(position)
 1322                      ) {
 1323                       // check VC: Standalone Document Declaration
 1324                       fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1325                                                  "MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE",
 1326                                                  new Object[]{attrRawName, oldValue, attrValue},
 1327                                                  XMLErrorReporter.SEVERITY_ERROR);
 1328                   }
 1329               }
 1330               if (!fPerformValidation) {
 1331                   continue;
 1332               }
 1333               if (fTempAttDecl.simpleType.defaultType ==
 1334                   XMLSimpleType.DEFAULT_TYPE_FIXED) {
 1335                   String defaultValue = fTempAttDecl.simpleType.defaultValue;
 1336   
 1337                   if (!attrValue.equals(defaultValue)) {
 1338                       Object[] args = {elementName.localpart,
 1339                           attrRawName,
 1340                           attrValue,
 1341                           defaultValue};
 1342                       fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1343                                                  "MSG_FIXED_ATTVALUE_INVALID",
 1344                                                  args, XMLErrorReporter.SEVERITY_ERROR);
 1345                   }
 1346               }
 1347   
 1348               if (fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENTITY ||
 1349                   fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENUMERATION ||
 1350                   fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ID ||
 1351                   fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_IDREF ||
 1352                   fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NMTOKEN ||
 1353                   fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NOTATION
 1354                  ) {
 1355                   validateDTDattribute(elementName, attrValue, fTempAttDecl);
 1356               }
 1357           } // for all attributes
 1358   
 1359       } // addDTDDefaultAttrsAndValidate(int,XMLAttrList)
 1360   
 1361       /** Checks entities in attribute values for standalone VC. */
 1362       protected String getExternalEntityRefInAttrValue(String nonNormalizedValue) {
 1363           int valLength = nonNormalizedValue.length();
 1364           int ampIndex = nonNormalizedValue.indexOf('&');
 1365           while (ampIndex != -1) {
 1366               if (ampIndex + 1 < valLength &&
 1367                   nonNormalizedValue.charAt(ampIndex+1) != '#') {
 1368                   int semicolonIndex = nonNormalizedValue.indexOf(';', ampIndex+1);
 1369                   String entityName = nonNormalizedValue.substring(ampIndex+1, semicolonIndex);
 1370                   entityName = fSymbolTable.addSymbol(entityName);
 1371                   int entIndex = fDTDGrammar.getEntityDeclIndex(entityName);
 1372                   if (entIndex > -1) {
 1373                       fDTDGrammar.getEntityDecl(entIndex, fEntityDecl);
 1374                       if (fEntityDecl.inExternal || 
 1375                           (entityName = getExternalEntityRefInAttrValue(fEntityDecl.value)) != null) {
 1376                           return entityName;
 1377                       }
 1378                   }
 1379               }
 1380               ampIndex = nonNormalizedValue.indexOf('&', ampIndex+1);
 1381           }
 1382           return null;
 1383       } // isExternalEntityRefInAttrValue(String):String
 1384   
 1385       /**
 1386        * Validate attributes in DTD fashion.
 1387        */
 1388       protected void validateDTDattribute(QName element, String attValue,
 1389                                         XMLAttributeDecl attributeDecl) 
 1390       throws XNIException {
 1391   
 1392           switch (attributeDecl.simpleType.type) {
 1393           case XMLSimpleType.TYPE_ENTITY: {                            
 1394                   // NOTE: Save this information because invalidStandaloneAttDef
 1395                   boolean isAlistAttribute = attributeDecl.simpleType.list;
 1396   
 1397                   try {
 1398                       if (isAlistAttribute) {
 1399                           fValENTITIES.validate(attValue, fValidationState);
 1400                       }
 1401                       else {
 1402                           fValENTITY.validate(attValue, fValidationState);
 1403                       }
 1404                   }
 1405                   catch (InvalidDatatypeValueException ex) {
 1406                       fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1407                                                  ex.getKey(),
 1408                                                  ex.getArgs(),
 1409                                                  XMLErrorReporter.SEVERITY_ERROR );
 1410   
 1411                   }
 1412                   break;
 1413               }
 1414   
 1415           case XMLSimpleType.TYPE_NOTATION:
 1416           case XMLSimpleType.TYPE_ENUMERATION: {
 1417                   boolean found = false;
 1418                   String [] enumVals = attributeDecl.simpleType.enumeration;
 1419                   if (enumVals == null) {
 1420                       found = false;
 1421                   }
 1422                   else
 1423                       for (int i = 0; i < enumVals.length; i++) {
 1424                           if (attValue == enumVals[i] || attValue.equals(enumVals[i])) {
 1425                               found = true;
 1426                               break;
 1427                           }
 1428                       }
 1429   
 1430                   if (!found) {
 1431                       StringBuffer enumValueString = new StringBuffer();
 1432                       if (enumVals != null)
 1433                           for (int i = 0; i < enumVals.length; i++) {
 1434                               enumValueString.append(enumVals[i]+" ");
 1435                           }
 1436                       fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 
 1437                                                  "MSG_ATTRIBUTE_VALUE_NOT_IN_LIST",
 1438                                                  new Object[]{attributeDecl.name.rawname, attValue, enumValueString},
 1439                                                  XMLErrorReporter.SEVERITY_ERROR);
 1440                   }
 1441                   break;
 1442               }
 1443   
 1444           case XMLSimpleType.TYPE_ID: {
 1445                   try {
 1446                       fValID.validate(attValue, fValidationState);
 1447                   }
 1448                   catch (InvalidDatatypeValueException ex) {
 1449                       fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1450                                                  ex.getKey(),
 1451                                                  ex.getArgs(),
 1452                                                  XMLErrorReporter.SEVERITY_ERROR );
 1453                   }
 1454                   break;
 1455               }
 1456   
 1457           case XMLSimpleType.TYPE_IDREF: {
 1458                   boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef
 1459   
 1460                   try {
 1461                       if (isAlistAttribute) {
 1462                           fValIDRefs.validate(attValue, fValidationState);
 1463                       }
 1464                       else {
 1465                           fValIDRef.validate(attValue, fValidationState);
 1466                       }
 1467                   }
 1468                   catch (InvalidDatatypeValueException ex) {
 1469                       if (isAlistAttribute) {
 1470                           fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1471                                                      "IDREFSInvalid",
 1472                                                      new Object[]{attValue},
 1473                                                      XMLErrorReporter.SEVERITY_ERROR );
 1474                       }
 1475                       else {
 1476                           fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1477                                                      ex.getKey(),
 1478                                                      ex.getArgs(),
 1479                                                      XMLErrorReporter.SEVERITY_ERROR );
 1480                       }
 1481   
 1482                   }
 1483                   break;
 1484               }
 1485   
 1486           case XMLSimpleType.TYPE_NMTOKEN: {
 1487                   boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef
 1488                   //changes fTempAttDef
 1489                   try {
 1490                       if (isAlistAttribute) {
 1491                           fValNMTOKENS.validate(attValue, fValidationState);
 1492                       }
 1493                       else {
 1494                           fValNMTOKEN.validate(attValue, fValidationState);
 1495                       }
 1496                   }
 1497                   catch (InvalidDatatypeValueException ex) {
 1498                       if (isAlistAttribute) {
 1499                           fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1500                                                      "NMTOKENSInvalid",
 1501                                                      new Object[] { attValue},
 1502                                                      XMLErrorReporter.SEVERITY_ERROR);
 1503                       }
 1504                       else {
 1505                           fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1506                                                      "NMTOKENInvalid",
 1507                                                      new Object[] { attValue},
 1508                                                      XMLErrorReporter.SEVERITY_ERROR);
 1509                       }
 1510                   }
 1511                   break;
 1512               }
 1513   
 1514           } // switch
 1515   
 1516       } // validateDTDattribute(QName,String,XMLAttributeDecl)
 1517   
 1518   
 1519       /** Returns true if invalid standalone attribute definition. */
 1520       protected boolean invalidStandaloneAttDef(QName element, QName attribute) {
 1521           // REVISIT: This obviously needs to be fixed! -Ac
 1522           boolean state = true;
 1523           /*
 1524          if (fStandaloneReader == -1) {
 1525             return false;
 1526          }
 1527          // we are normalizing a default att value...  this ok?
 1528          if (element.rawname == -1) {
 1529             return false;
 1530          }
 1531          return getAttDefIsExternal(element, attribute);
 1532          */
 1533           return state;
 1534       }
 1535   
 1536   
 1537       //
 1538       // Private methods
 1539       //
 1540   
 1541   
 1542       /**
 1543        * Normalize the attribute value of a non CDATA attributes collapsing
 1544        * sequences of space characters (x20)
 1545        *
 1546        * @param attributes The list of attributes
 1547        * @param index The index of the attribute to normalize
 1548        */
 1549       private boolean normalizeAttrValue(XMLAttributes attributes, int index) {
 1550           // vars
 1551           boolean leadingSpace = true;
 1552           boolean spaceStart = false;
 1553           boolean readingNonSpace = false;
 1554           int count = 0;
 1555           int eaten = 0;
 1556           String attrValue = attributes.getValue(index);
 1557           char[] attValue = new char[attrValue.length()];
 1558   
 1559           fBuffer.setLength(0);
 1560           attrValue.getChars(0, attrValue.length(), attValue, 0);
 1561           for (int i = 0; i < attValue.length; i++) {
 1562   
 1563               if (attValue[i] == ' ') {
 1564   
 1565                   // now the tricky part
 1566                   if (readingNonSpace) {
 1567                       spaceStart = true;
 1568                       readingNonSpace = false;
 1569                   }
 1570   
 1571                   if (spaceStart && !leadingSpace) {
 1572                       spaceStart = false;
 1573                       fBuffer.append(attValue[i]);
 1574                       count++;
 1575                   }
 1576                   else {
 1577                       if (leadingSpace || !spaceStart) {
 1578                           eaten ++;
 1579                           /*** BUG #3512 ***
 1580                           int entityCount = attributes.getEntityCount(index);
 1581                           for (int j = 0;  j < entityCount; j++) {
 1582                               int offset = attributes.getEntityOffset(index, j);
 1583                               int length = attributes.getEntityLength(index, j);
 1584                               if (offset <= i-eaten+1) {
 1585                                   if (offset+length >= i-eaten+1) {
 1586                                       if (length > 0)
 1587                                           length--;
 1588                                   }
 1589                               } 
 1590                               else {
 1591                                   if (offset > 0)
 1592                                       offset--;
 1593                               }
 1594                               attributes.setEntityOffset(index, j, offset);
 1595                               attributes.setEntityLength(index, j, length);
 1596                           }
 1597                           /***/
 1598                       }
 1599                   }
 1600   
 1601               }
 1602               else {
 1603                   readingNonSpace = true;
 1604                   spaceStart = false;
 1605                   leadingSpace = false;
 1606                   fBuffer.append(attValue[i]);
 1607                   count++;
 1608               }
 1609           }
 1610   
 1611           // check if the last appended character is a space.
 1612           if (count > 0 && fBuffer.charAt(count-1) == ' ') {
 1613               fBuffer.setLength(count-1);
 1614               /*** BUG #3512 ***
 1615               int entityCount = attributes.getEntityCount(index);
 1616               for (int j=0;  j < entityCount; j++) {
 1617                   int offset = attributes.getEntityOffset(index, j);
 1618                   int length = attributes.getEntityLength(index, j);
 1619                   if (offset < count-1) {
 1620                       if (offset+length == count) {
 1621                           length--;
 1622                       }
 1623                   } 
 1624                   else {
 1625                       offset--;
 1626                   }
 1627                   attributes.setEntityOffset(index, j, offset);
 1628                   attributes.setEntityLength(index, j, length);
 1629               }
 1630               /***/
 1631           }
 1632           String newValue = fBuffer.toString();
 1633           attributes.setValue(index, newValue);
 1634           return ! attrValue.equals(newValue);
 1635       }
 1636   
 1637       /** Root element specified. */
 1638       private final void rootElementSpecified(QName rootElement) throws XNIException {
 1639           if (fPerformValidation) {
 1640               String root1 = fRootElement.rawname;
 1641               String root2 = rootElement.rawname;
 1642               if (root1 == null || !root1.equals(root2)) {
 1643                   fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, 
 1644                                               "RootElementTypeMustMatchDoctypedecl", 
 1645                                               new Object[]{root1, root2}, 
 1646                                               XMLErrorReporter.SEVERITY_ERROR);
 1647               }
 1648           }
 1649       } // rootElementSpecified(QName)
 1650   
 1651       /**
 1652        * Check that the content of an element is valid.
 1653        * <p>
 1654        * This is the method of primary concern to the validator. This method is called
 1655        * upon the scanner reaching the end tag of an element. At that time, the
 1656        * element's children must be structurally validated, so it calls this method.
 1657        * The index of the element being checked (in the decl pool), is provided as
 1658        * well as an array of element name indexes of the children. The validator must
 1659        * confirm that this element can have these children in this order.
 1660        * <p>
 1661        * This can also be called to do 'what if' testing of content models just to see
 1662        * if they would be valid.
 1663        * <p>
 1664        * Note that the element index is an index into the element decl pool, whereas
 1665        * the children indexes are name indexes, i.e. into the string pool.
 1666        * <p>
 1667        * A value of -1 in the children array indicates a PCDATA node. All other
 1668        * indexes will be positive and represent child elements. The count can be
 1669        * zero, since some elements have the EMPTY content model and that must be
 1670        * confirmed.
 1671        *
 1672        * @param elementIndex The index within the <code>ElementDeclPool</code> of this
 1673        *                     element.
 1674        * @param childCount The number of entries in the <code>children</code> array.
 1675        * @param children The children of this element.  
 1676        *
 1677        * @return The value -1 if fully valid, else the 0 based index of the child
 1678        *         that first failed. If the value returned is equal to the number
 1679        *         of children, then additional content is required to reach a valid
 1680        *         ending state.
 1681        *
 1682        * @exception Exception Thrown on error.
 1683        */
 1684       private int checkContent(int elementIndex, 
 1685                                QName[] children,
 1686                                int childOffset, 
 1687                                int childCount) throws XNIException {
 1688   
 1689           fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl);
 1690   
 1691           // Get the element name index from the element
 1692           final String elementType = fCurrentElement.rawname;
 1693   
 1694           // Get out the content spec for this element
 1695           final int contentType = fCurrentContentSpecType;
 1696   
 1697   
 1698           //
 1699           //  Deal with the possible types of content. We try to optimized here
 1700           //  by dealing specially with content models that don't require the
 1701           //  full DFA treatment.
 1702           //
 1703           if (contentType == XMLElementDecl.TYPE_EMPTY) {
 1704               //
 1705               //  If the child count is greater than zero, then this is
 1706               //  an error right off the bat at index 0.
 1707               //
 1708               if (childCount != 0) {
 1709                   return 0;
 1710               }
 1711           }
 1712           else if (contentType == XMLElementDecl.TYPE_ANY) {
 1713               //
 1714               //  This one is open game so we don't pass any judgement on it
 1715               //  at all. Its assumed to fine since it can hold anything.
 1716               //
 1717           }
 1718           else if (contentType == XMLElementDecl.TYPE_MIXED ||  
 1719                    contentType == XMLElementDecl.TYPE_CHILDREN) {
 1720               // Get the content model for this element, faulting it in if needed
 1721               ContentModelValidator cmElem = null;
 1722               cmElem = fTempElementDecl.contentModelValidator;
 1723               int result = cmElem.validate(children, childOffset, childCount);
 1724               return result;
 1725           }
 1726           else if (contentType == -1) {
 1727               //REVISIT
 1728               /****
 1729               reportRecoverableXMLError(XMLMessages.MSG_ELEMENT_NOT_DECLARED,
 1730                                         XMLMessages.VC_ELEMENT_VALID,
 1731                                         elementType);
 1732               /****/
 1733           }
 1734           else if (contentType == XMLElementDecl.TYPE_SIMPLE) {
 1735   
 1736               //REVISIT
 1737               // this should never be reached in the case of DTD validation.
 1738   
 1739           }
 1740           else {
 1741               //REVISIT
 1742               /****
 1743               fErrorReporter.reportError(fErrorReporter.getLocator(),
 1744                                          ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
 1745                                          ImplementationMessages.VAL_CST,
 1746                                          0,
 1747                                          null,
 1748                                          XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
 1749               /****/
 1750           }
 1751   
 1752           // We succeeded
 1753           return -1;
 1754   
 1755       } // checkContent(int,int,QName[]):int
 1756   
 1757       /** Returns the content spec type for an element index. */
 1758       private int getContentSpecType(int elementIndex) {
 1759   
 1760           int contentSpecType = -1;
 1761           if (elementIndex > -1) {
 1762               if (fDTDGrammar.getElementDecl(elementIndex,fTempElementDecl)) {
 1763                   contentSpecType = fTempElementDecl.type;
 1764               }
 1765           }
 1766           return contentSpecType;
 1767       }
 1768   
 1769       /** Character data in content. */
 1770       private void charDataInContent() {
 1771   
 1772           if (DEBUG_ELEMENT_CHILDREN) {
 1773               System.out.println("charDataInContent()");
 1774           }
 1775           if (fElementChildren.length <= fElementChildrenLength) {
 1776               QName[] newarray = new QName[fElementChildren.length * 2];
 1777               System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length);
 1778               fElementChildren = newarray;
 1779           }
 1780           QName qname = fElementChildren[fElementChildrenLength];
 1781           if (qname == null) {
 1782               for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
 1783                   fElementChildren[i] = new QName();
 1784               }
 1785               qname = fElementChildren[fElementChildrenLength];
 1786           }
 1787           qname.clear();
 1788           fElementChildrenLength++;
 1789   
 1790       } // charDataInCount()
 1791   
 1792       /** convert attribute type from ints to strings */
 1793       private String getAttributeTypeName(XMLAttributeDecl attrDecl) {
 1794   
 1795           switch (attrDecl.simpleType.type) {
 1796           case XMLSimpleType.TYPE_ENTITY: {
 1797                   return attrDecl.simpleType.list ? XMLSymbols.fENTITIESSymbol : XMLSymbols.fENTITYSymbol;
 1798               }
 1799           case XMLSimpleType.TYPE_ENUMERATION: {
 1800                   StringBuffer buffer = new StringBuffer();
 1801                   buffer.append('(');
 1802                   for (int i=0; i<attrDecl.simpleType.enumeration.length ; i++) {
 1803                       if (i > 0) {
 1804                           buffer.append("|");
 1805                       }
 1806                       buffer.append(attrDecl.simpleType.enumeration[i]);
 1807                   }
 1808                   buffer.append(')');
 1809                   return fSymbolTable.addSymbol(buffer.toString());
 1810               }
 1811           case XMLSimpleType.TYPE_ID: {
 1812                   return XMLSymbols.fIDSymbol;
 1813               }
 1814           case XMLSimpleType.TYPE_IDREF: {
 1815                   return attrDecl.simpleType.list ? XMLSymbols.fIDREFSSymbol : XMLSymbols.fIDREFSymbol;
 1816               }
 1817           case XMLSimpleType.TYPE_NMTOKEN: {
 1818                   return attrDecl.simpleType.list ? XMLSymbols.fNMTOKENSSymbol : XMLSymbols.fNMTOKENSymbol;
 1819               }
 1820           case XMLSimpleType.TYPE_NOTATION: {
 1821                   return XMLSymbols.fNOTATIONSymbol;
 1822               }
 1823           }
 1824           return XMLSymbols.fCDATASymbol;
 1825   
 1826       } // getAttributeTypeName(XMLAttributeDecl):String
 1827   
 1828       /** initialization */
 1829       protected void init() {
 1830   
 1831           // datatype validators
 1832           if (fValidation || fDynamicValidation) {
 1833               try {
 1834                   //REVISIT: datatypeRegistry + initialization of datatype 
 1835                   //         why do we cast to ListDatatypeValidator?
 1836                   fValID       = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDSymbol);
 1837                   fValIDRef    = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSymbol);
 1838                   fValIDRefs   = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSSymbol);
 1839                   fValENTITY   = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITYSymbol);
 1840                   fValENTITIES = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITIESSymbol);
 1841                   fValNMTOKEN  = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSymbol);
 1842                   fValNMTOKENS = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSSymbol);
 1843                   fValNOTATION = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNOTATIONSymbol);
 1844   
 1845               }
 1846               catch (Exception e) {
 1847                   // should never happen
 1848                   e.printStackTrace(System.err);
 1849               }
 1850   
 1851           }
 1852   
 1853       } // init()
 1854   
 1855       /** ensure element stack capacity */
 1856       private void ensureStackCapacity (int newElementDepth) {
 1857           if (newElementDepth == fElementQNamePartsStack.length) {
 1858   
 1859               QName[] newStackOfQueue = new QName[newElementDepth * 2];
 1860               System.arraycopy(this.fElementQNamePartsStack, 0, newStackOfQueue, 0, newElementDepth );
 1861               fElementQNamePartsStack = newStackOfQueue;
 1862   
 1863               QName qname = fElementQNamePartsStack[newElementDepth];
 1864               if (qname == null) {
 1865                   for (int i = newElementDepth; i < fElementQNamePartsStack.length; i++) {
 1866                       fElementQNamePartsStack[i] = new QName();
 1867                   }
 1868               }
 1869   
 1870               int[] newStack = new int[newElementDepth * 2];
 1871               System.arraycopy(fElementIndexStack, 0, newStack, 0, newElementDepth);
 1872               fElementIndexStack = newStack;
 1873   
 1874               newStack = new int[newElementDepth * 2];
 1875               System.arraycopy(fContentSpecTypeStack, 0, newStack, 0, newElementDepth);
 1876               fContentSpecTypeStack = newStack;
 1877   
 1878           }
 1879       } // ensureStackCapacity
 1880       
 1881       
 1882       //
 1883       // Protected methods
 1884       //
 1885   
 1886       /** Handle element
 1887        * @return true if validator is removed from the pipeline
 1888        */
 1889       protected boolean handleStartElement(QName element, XMLAttributes attributes, Augmentations augs) 
 1890                           throws XNIException {
 1891   
 1892   
 1893           // VC: Root Element Type
 1894           // see if the root element's name matches the one in DoctypeDecl 
 1895           if (!fSeenRootElement) {
 1896               // REVISIT: Here are current assumptions about validation features
 1897               //          given that XMLSchema validator is in the pipeline
 1898               //
 1899               // http://xml.org/sax/features/validation = true
 1900               // http://apache.org/xml/features/validation/schema = true
 1901               //
 1902               // [1] XML instance document only has reference to a DTD 
 1903               //  Outcome: report validation errors only against dtd.
 1904               //
 1905               // [2] XML instance document has only XML Schema grammars:
 1906               //  Outcome: report validation errors only against schemas (no errors produced from DTD validator)
 1907               //
 1908               // [3] XML instance document has DTD and XML schemas:
 1909               // [a] if schema language is not set outcome - validation errors reported against both grammars: DTD and schemas.
 1910               // [b] if schema language is set to XML Schema - do not report validation errors
 1911               //         
 1912               // if dynamic validation is on
 1913               //            validate only against grammar we've found (depending on settings
 1914               //            for schema feature)
 1915               // 
 1916               // 
 1917               fPerformValidation = validate();
 1918               fSeenRootElement = true;
 1919               fValidationManager.setEntityState(fDTDGrammar);
 1920               fValidationManager.setGrammarFound(fSeenDoctypeDecl);
 1921               rootElementSpecified(element);
 1922           }
 1923           if (fDTDGrammar == null) {
 1924   
 1925               if (!fPerformValidation) {
 1926                   fCurrentElementIndex = -1;
 1927                   fCurrentContentSpecType = -1;
 1928                   fInElementContent = false;
 1929               }
 1930               if (fPerformValidation) {
 1931                   fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 
 1932                                              "MSG_GRAMMAR_NOT_FOUND",
 1933                                              new Object[]{ element.rawname},
 1934                                              XMLErrorReporter.SEVERITY_ERROR);
 1935               }
 1936               // modify pipeline
 1937               if (fDocumentSource !=null ) {
 1938                   fDocumentSource.setDocumentHandler(fDocumentHandler);
 1939                   if (fDocumentHandler != null)
 1940                       fDocumentHandler.setDocumentSource(fDocumentSource);
 1941                   return true;
 1942               }
 1943           }
 1944           else {
 1945               //  resolve the element
 1946               fCurrentElementIndex = fDTDGrammar.getElementDeclIndex(element);
 1947               //changed here.. new function for getContentSpecType
 1948               fCurrentContentSpecType = fDTDGrammar.getContentSpecType(fCurrentElementIndex);
 1949               if (fCurrentContentSpecType == -1 && fPerformValidation) {
 1950                   fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 
 1951                                              "MSG_ELEMENT_NOT_DECLARED",
 1952                                              new Object[]{ element.rawname},
 1953                                              XMLErrorReporter.SEVERITY_ERROR);
 1954               }
 1955               
 1956               //  0. insert default attributes
 1957               //  1. normalize the attributes
 1958               //  2. validate the attrivute list.
 1959               // TO DO: 
 1960               //changed here.. also pass element name,
 1961               addDTDDefaultAttrsAndValidate(element, fCurrentElementIndex, attributes);
 1962           }
 1963   
 1964           // set element content state
 1965           fInElementContent = fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN;
 1966   
 1967           // increment the element depth, add this element's 
 1968           // QName to its enclosing element 's children list
 1969           fElementDepth++;
 1970           if (fPerformValidation) {
 1971               // push current length onto stack
 1972               if (fElementChildrenOffsetStack.length <= fElementDepth) {
 1973                   int newarray[] = new int[fElementChildrenOffsetStack.length * 2];
 1974                   System.arraycopy(fElementChildrenOffsetStack, 0, newarray, 0, fElementChildrenOffsetStack.length);
 1975                   fElementChildrenOffsetStack = newarray;
 1976               }
 1977               fElementChildrenOffsetStack[fElementDepth] = fElementChildrenLength;
 1978   
 1979               // add this element to children
 1980               if (fElementChildren.length <= fElementChildrenLength) {
 1981                   QName[] newarray = new QName[fElementChildrenLength * 2];
 1982                   System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length);
 1983                   fElementChildren = newarray;
 1984               }
 1985               QName qname = fElementChildren[fElementChildrenLength];
 1986               if (qname == null) {
 1987                   for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
 1988                       fElementChildren[i] = new QName();
 1989                   }
 1990                   qname = fElementChildren[fElementChildrenLength];
 1991               }
 1992               qname.setValues(element);
 1993               fElementChildrenLength++;
 1994           }
 1995   
 1996           // save current element information
 1997           fCurrentElement.setValues(element);
 1998           ensureStackCapacity(fElementDepth);
 1999           fElementQNamePartsStack[fElementDepth].setValues(fCurrentElement); 
 2000           fElementIndexStack[fElementDepth] = fCurrentElementIndex;
 2001           fContentSpecTypeStack[fElementDepth] = fCurrentContentSpecType;
 2002           startNamespaceScope(element, attributes, augs);
 2003           return false;
 2004   
 2005       } // handleStartElement(QName,XMLAttributes)
 2006   
 2007       protected void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs){
 2008       }
 2009   
 2010       /** Handle end element. */
 2011       protected void handleEndElement(QName element,  Augmentations augs, boolean isEmpty)
 2012       throws XNIException {
 2013   
 2014           // decrease element depth
 2015           fElementDepth--;
 2016   
 2017           // validate
 2018           if (fPerformValidation) {
 2019               int elementIndex = fCurrentElementIndex;
 2020               if (elementIndex != -1 && fCurrentContentSpecType != -1) {
 2021                   QName children[] = fElementChildren;
 2022                   int childrenOffset = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
 2023                   int childrenLength = fElementChildrenLength - childrenOffset;
 2024                   int result = checkContent(elementIndex, 
 2025                                             children, childrenOffset, childrenLength);
 2026   
 2027                   if (result != -1) {
 2028                       fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl);
 2029                       if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
 2030                           fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 
 2031                                                      "MSG_CONTENT_INVALID",
 2032                                                      new Object[]{ element.rawname, "EMPTY"},
 2033                                                      XMLErrorReporter.SEVERITY_ERROR);
 2034                       }
 2035                       else {
 2036                           String messageKey = result != childrenLength ? 
 2037                                               "MSG_CONTENT_INVALID" : "MSG_CONTENT_INCOMPLETE";
 2038                           fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 
 2039                                                      messageKey,
 2040                                                      new Object[]{ element.rawname, 
 2041                                                          fDTDGrammar.getContentSpecAsString(elementIndex)},
 2042                                                      XMLErrorReporter.SEVERITY_ERROR);
 2043                       }
 2044                   }
 2045               }
 2046               fElementChildrenLength = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
 2047           }
 2048           
 2049           endNamespaceScope(fCurrentElement, augs, isEmpty);
 2050           
 2051           // now pop this element off the top of the element stack
 2052           if (fElementDepth < -1) {
 2053               throw new RuntimeException("FWK008 Element stack underflow");
 2054           }
 2055           if (fElementDepth < 0) {
 2056               fCurrentElement.clear();
 2057               fCurrentElementIndex = -1;
 2058               fCurrentContentSpecType = -1;
 2059               fInElementContent = false;
 2060   
 2061               // TO DO : fix this
 2062               //
 2063               // Check after document is fully parsed
 2064               // (1) check that there was an element with a matching id for every
 2065               //   IDREF and IDREFS attr (V_IDREF0)
 2066               //
 2067               if (fPerformValidation) {
 2068                   String value = fValidationState.checkIDRefID();
 2069                   if (value != null) {
 2070                       fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
 2071                                                   "MSG_ELEMENT_WITH_ID_REQUIRED",
 2072                                                   new Object[]{value},
 2073                                                   XMLErrorReporter.SEVERITY_ERROR );
 2074                   }
 2075               }
 2076               return;
 2077           }
 2078   
 2079           // If Namespace enable then localName != rawName
 2080           fCurrentElement.setValues(fElementQNamePartsStack[fElementDepth]);
 2081   
 2082           fCurrentElementIndex = fElementIndexStack[fElementDepth];
 2083           fCurrentContentSpecType = fContentSpecTypeStack[fElementDepth];
 2084           fInElementContent = (fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN);
 2085   
 2086       } // handleEndElement(QName,boolean)
 2087   
 2088       protected void endNamespaceScope(QName element,  Augmentations augs, boolean isEmpty){
 2089   
 2090           // call handlers
 2091           if (fDocumentHandler != null && !isEmpty) {
 2092               // NOTE: The binding of the element doesn't actually happen
 2093               //       yet because the namespace binder does that. However,
 2094               //       if it does it before this point, then the endPrefix-
 2095               //       Mapping calls get made too soon! As long as the
 2096               //       rawnames match, we know it'll have a good binding,
 2097               //       so we can just use the current element. -Ac
 2098               fDocumentHandler.endElement(fCurrentElement, augs);
 2099           }
 2100       }
 2101   
 2102       // returns whether a character is space according to the
 2103       // version of XML this validator supports.
 2104       protected boolean isSpace(int c) {
 2105           return XMLChar.isSpace(c);
 2106       } // isSpace(int):  boolean
 2107   
 2108       public boolean characterData(String data, Augmentations augs) {       
 2109           characters(new XMLString(data.toCharArray(), 0, data.length()), augs);
 2110           return true;
 2111       }
 2112   
 2113   } // class XMLDTDValidator

Save This Page
Home » Xerces-J-src.2.9.1 » org.apache.xerces » impl » dtd » [javadoc | source]