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