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