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