1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * The Apache Software License, Version 1.1
   7  *
   8  *
   9  * Copyright (c) 1999-2002 The Apache Software Foundation.
  10  * All rights reserved.
  11  *
  12  * Redistribution and use in source and binary forms, with or without
  13  * modification, are permitted provided that the following conditions
  14  * are met:
  15  *
  16  * 1. Redistributions of source code must retain the above copyright
  17  *    notice, this list of conditions and the following disclaimer.
  18  *
  19  * 2. Redistributions in binary form must reproduce the above copyright
  20  *    notice, this list of conditions and the following disclaimer in
  21  *    the documentation and/or other materials provided with the
  22  *    distribution.
  23  *
  24  * 3. The end-user documentation included with the redistribution,
  25  *    if any, must include the following acknowledgment:
  26  *       "This product includes software developed by the
  27  *        Apache Software Foundation (http://www.apache.org/)."
  28  *    Alternately, this acknowledgment may appear in the software itself,
  29  *    if and wherever such third-party acknowledgments normally appear.
  30  *
  31  * 4. The names "Xerces" and "Apache Software Foundation" must
  32  *    not be used to endorse or promote products derived from this
  33  *    software without prior written permission. For written
  34  *    permission, please contact apache@apache.org.
  35  *
  36  * 5. Products derived from this software may not be called "Apache",
  37  *    nor may "Apache" appear in their name, without prior written
  38  *    permission of the Apache Software Foundation.
  39  *
  40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  43  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  44  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  45  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  46  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  51  * SUCH DAMAGE.
  52  * ====================================================================
  53  *
  54  * This software consists of voluntary contributions made by many
  55  * individuals on behalf of the Apache Software Foundation and was
  56  * originally based on software copyright (c) 1999, International
  57  * Business Machines, Inc., http://www.apache.org.  For more
  58  * information on the Apache Software Foundation, please see
  59  * <http://www.apache.org/>.
  60  */
  61 
  62 package com.sun.org.apache.xerces.internal.impl.dtd;
  63 
  64 import java.util.ArrayList;
  65 import java.util.HashMap;
  66 import java.util.Iterator;
  67 import java.util.Locale;
  68 import java.util.Map;
  69 import java.util.StringTokenizer;
  70 
  71 import com.sun.org.apache.xerces.internal.impl.Constants;
  72 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  73 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  74 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  75 import com.sun.org.apache.xerces.internal.util.XMLChar;
  76 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  77 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  78 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
  79 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
  80 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  81 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  82 import com.sun.org.apache.xerces.internal.xni.XMLString;
  83 import com.sun.org.apache.xerces.internal.xni.XNIException;
  84 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar;
  85 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  86 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  87 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  88 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  89 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  90 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDContentModelFilter;
  91 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDContentModelSource;
  92 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDFilter;
  93 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource;
  94 
  95 /**
  96  * The DTD processor. The processor implements a DTD
  97  * filter: receiving DTD events from the DTD scanner; validating
  98  * the content and structure; building a grammar, if applicable;
  99  * and notifying the DTDHandler of the information resulting from the
 100  * process.
 101  * <p>
 102  * This component requires the following features and properties from the
 103  * component manager that uses it:
 104  * <ul>
 105  *  <li>http://xml.org/sax/features/namespaces</li>
 106  *  <li>http://apache.org/xml/properties/internal/symbol-table</li>
 107  *  <li>http://apache.org/xml/properties/internal/error-reporter</li>
 108  *  <li>http://apache.org/xml/properties/internal/grammar-pool</li>
 109  *  <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li>
 110  * </ul>
 111  *
 112  * @xerces.internal
 113  *
 114  * @author Neil Graham, IBM
 115  *
 116  * @version $Id: XMLDTDProcessor.java,v 1.5 2010-11-01 04:39:42 joehw Exp $
 117  */
 118 public class XMLDTDProcessor
 119         implements XMLComponent, XMLDTDFilter, XMLDTDContentModelFilter {
 120 
 121     //
 122     // Constants
 123     //
 124 
 125     /** Top level scope (-1). */
 126     private static final int TOP_LEVEL_SCOPE = -1;
 127 
 128     // feature identifiers
 129 
 130     /** Feature identifier: validation. */
 131     protected static final String VALIDATION =
 132         Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
 133 
 134     /** Feature identifier: notify character references. */
 135     protected static final String NOTIFY_CHAR_REFS =
 136         Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE;
 137 
 138     /** Feature identifier: warn on duplicate attdef */
 139     protected static final String WARN_ON_DUPLICATE_ATTDEF =
 140         Constants.XERCES_FEATURE_PREFIX +Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE;
 141 
 142     /** Feature identifier: warn on undeclared element referenced in content model. */
 143     protected static final String WARN_ON_UNDECLARED_ELEMDEF =
 144         Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_UNDECLARED_ELEMDEF_FEATURE;
 145 
 146         protected static final String PARSER_SETTINGS =
 147         Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
 148 
 149     // property identifiers
 150 
 151     /** Property identifier: symbol table. */
 152     protected static final String SYMBOL_TABLE =
 153         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
 154 
 155     /** Property identifier: error reporter. */
 156     protected static final String ERROR_REPORTER =
 157         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
 158 
 159     /** Property identifier: grammar pool. */
 160     protected static final String GRAMMAR_POOL =
 161         Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
 162 
 163     /** Property identifier: validator . */
 164     protected static final String DTD_VALIDATOR =
 165         Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY;
 166 
 167     // recognized features and properties
 168 
 169     /** Recognized features. */
 170     private static final String[] RECOGNIZED_FEATURES = {
 171         VALIDATION,
 172         WARN_ON_DUPLICATE_ATTDEF,
 173         WARN_ON_UNDECLARED_ELEMDEF,
 174         NOTIFY_CHAR_REFS,
 175     };
 176 
 177     /** Feature defaults. */
 178     private static final Boolean[] FEATURE_DEFAULTS = {
 179         null,
 180         Boolean.FALSE,
 181         Boolean.FALSE,
 182         null,
 183     };
 184 
 185     /** Recognized properties. */
 186     private static final String[] RECOGNIZED_PROPERTIES = {
 187         SYMBOL_TABLE,
 188         ERROR_REPORTER,
 189         GRAMMAR_POOL,
 190         DTD_VALIDATOR,
 191     };
 192 
 193     /** Property defaults. */
 194     private static final Object[] PROPERTY_DEFAULTS = {
 195         null,
 196         null,
 197         null,
 198         null,
 199     };
 200 
 201     // debugging
 202 
 203     //
 204     // Data
 205     //
 206 
 207     // features
 208 
 209     /** Validation. */
 210     protected boolean fValidation;
 211 
 212     /** Validation against only DTD */
 213     protected boolean fDTDValidation;
 214 
 215     /** warn on duplicate attribute definition, this feature works only when validation is true */
 216     protected boolean fWarnDuplicateAttdef;
 217 
 218     /** warn on undeclared element referenced in content model, this feature only works when valiation is true */
 219     protected boolean fWarnOnUndeclaredElemdef;
 220 
 221     // properties
 222 
 223     /** Symbol table. */
 224     protected SymbolTable fSymbolTable;
 225 
 226     /** Error reporter. */
 227     protected XMLErrorReporter fErrorReporter;
 228 
 229     /** Grammar bucket. */
 230     protected DTDGrammarBucket fGrammarBucket;
 231 
 232     // the validator to which we look for our grammar bucket (the
 233     // validator needs to hold the bucket so that it can initialize
 234     // the grammar with details like whether it's for a standalone document...
 235     protected XMLDTDValidator fValidator;
 236 
 237     // the grammar pool we'll try to add the grammar to:
 238     protected XMLGrammarPool fGrammarPool;
 239 
 240     // what's our Locale?
 241     protected Locale fLocale;
 242 
 243     // handlers
 244 
 245     /** DTD handler. */
 246     protected XMLDTDHandler fDTDHandler;
 247 
 248     /** DTD source. */
 249     protected XMLDTDSource fDTDSource;
 250 
 251     /** DTD content model handler. */
 252     protected XMLDTDContentModelHandler fDTDContentModelHandler;
 253 
 254     /** DTD content model source. */
 255     protected XMLDTDContentModelSource fDTDContentModelSource;
 256 
 257     // grammars
 258 
 259     /** DTD Grammar. */
 260     protected DTDGrammar fDTDGrammar;
 261 
 262     // state
 263 
 264     /** Perform validation. */
 265     private boolean fPerformValidation;
 266 
 267     /** True if in an ignore conditional section of the DTD. */
 268     protected boolean fInDTDIgnore;
 269 
 270     // information regarding the current element
 271 
 272     // validation states
 273 
 274     /** Mixed. */
 275     private boolean fMixed;
 276 
 277     // temporary variables
 278 
 279     /** Temporary entity declaration. */
 280     private final XMLEntityDecl fEntityDecl = new XMLEntityDecl();
 281 
 282     /** Notation declaration hash. */
 283     private final HashMap fNDataDeclNotations = new HashMap();
 284 
 285     /** DTD element declaration name. */
 286     private String fDTDElementDeclName = null;
 287 
 288     /** Mixed element type "hash". */
 289     private final ArrayList fMixedElementTypes = new ArrayList();
 290 
 291     /** Element declarations in DTD. */
 292     private final ArrayList fDTDElementDecls = new ArrayList();
 293 
 294     // to check for duplicate ID or ANNOTATION attribute declare in
 295     // ATTLIST, and misc VCs
 296 
 297     /** ID attribute names. */
 298     private HashMap fTableOfIDAttributeNames;
 299 
 300     /** NOTATION attribute names. */
 301     private HashMap fTableOfNOTATIONAttributeNames;
 302 
 303     /** NOTATION enumeration values. */
 304     private HashMap fNotationEnumVals;
 305 
 306     //
 307     // Constructors
 308     //
 309 
 310     /** Default constructor. */
 311     public XMLDTDProcessor() {
 312 
 313         // initialize data
 314 
 315     } // <init>()
 316 
 317     //
 318     // XMLComponent methods
 319     //
 320 
 321     /*
 322      * Resets the component. The component can query the component manager
 323      * about any features and properties that affect the operation of the
 324      * component.
 325      *
 326      * @param componentManager The component manager.
 327      *
 328      * @throws SAXException Thrown by component on finitialization error.
 329      *                      For example, if a feature or property is
 330      *                      required for the operation of the component, the
 331      *                      component manager may throw a
 332      *                      SAXNotRecognizedException or a
 333      *                      SAXNotSupportedException.
 334      */
 335     public void reset(XMLComponentManager componentManager) throws XMLConfigurationException {
 336 
 337         boolean parser_settings = componentManager.getFeature(PARSER_SETTINGS, true);
 338 
 339         if (!parser_settings) {
 340             // parser settings have not been changed
 341             reset();
 342             return;
 343         }
 344 
 345         // sax features
 346         fValidation = componentManager.getFeature(VALIDATION, false);
 347 
 348         fDTDValidation =
 349                 !(componentManager
 350                     .getFeature(
 351                         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE, false));
 352 
 353         // Xerces features
 354 
 355         fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF, false);
 356         fWarnOnUndeclaredElemdef = componentManager.getFeature(WARN_ON_UNDECLARED_ELEMDEF, false);
 357 
 358         // get needed components
 359         fErrorReporter =
 360             (XMLErrorReporter) componentManager.getProperty(
 361                 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY);
 362         fSymbolTable =
 363             (SymbolTable) componentManager.getProperty(
 364                 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY);
 365 
 366         fGrammarPool = (XMLGrammarPool) componentManager.getProperty(GRAMMAR_POOL, null);
 367 
 368         try {
 369             fValidator = (XMLDTDValidator) componentManager.getProperty(DTD_VALIDATOR, null);
 370         } catch (ClassCastException e) {
 371             fValidator = null;
 372         }
 373         // we get our grammarBucket from the validator...
 374         if (fValidator != null) {
 375             fGrammarBucket = fValidator.getGrammarBucket();
 376         } else {
 377             fGrammarBucket = null;
 378         }
 379         reset();
 380 
 381     } // reset(XMLComponentManager)
 382 
 383     protected void reset() {
 384         // clear grammars
 385         fDTDGrammar = null;
 386         // initialize state
 387         fInDTDIgnore = false;
 388 
 389         fNDataDeclNotations.clear();
 390 
 391         // datatype validators
 392         if (fValidation) {
 393 
 394             if (fNotationEnumVals == null) {
 395                 fNotationEnumVals = new HashMap();
 396             }
 397             fNotationEnumVals.clear();
 398 
 399             fTableOfIDAttributeNames = new HashMap();
 400             fTableOfNOTATIONAttributeNames = new HashMap();
 401         }
 402 
 403     }
 404     /**
 405      * Returns a list of feature identifiers that are recognized by
 406      * this component. This method may return null if no features
 407      * are recognized by this component.
 408      */
 409     public String[] getRecognizedFeatures() {
 410         return (String[])(RECOGNIZED_FEATURES.clone());
 411     } // getRecognizedFeatures():String[]
 412 
 413     /**
 414      * Sets the state of a feature. This method is called by the component
 415      * manager any time after reset when a feature changes state.
 416      * <p>
 417      * <strong>Note:</strong> Components should silently ignore features
 418      * that do not affect the operation of the component.
 419      *
 420      * @param featureId The feature identifier.
 421      * @param state     The state of the feature.
 422      *
 423      * @throws SAXNotRecognizedException The component should not throw
 424      *                                   this exception.
 425      * @throws SAXNotSupportedException The component should not throw
 426      *                                  this exception.
 427      */
 428     public void setFeature(String featureId, boolean state)
 429             throws XMLConfigurationException {
 430     } // setFeature(String,boolean)
 431 
 432     /**
 433      * Returns a list of property identifiers that are recognized by
 434      * this component. This method may return null if no properties
 435      * are recognized by this component.
 436      */
 437     public String[] getRecognizedProperties() {
 438         return (String[])(RECOGNIZED_PROPERTIES.clone());
 439     } // getRecognizedProperties():String[]
 440 
 441     /**
 442      * Sets the value of a property. This method is called by the component
 443      * manager any time after reset when a property changes value.
 444      * <p>
 445      * <strong>Note:</strong> Components should silently ignore properties
 446      * that do not affect the operation of the component.
 447      *
 448      * @param propertyId The property identifier.
 449      * @param value      The value of the property.
 450      *
 451      * @throws SAXNotRecognizedException The component should not throw
 452      *                                   this exception.
 453      * @throws SAXNotSupportedException The component should not throw
 454      *                                  this exception.
 455      */
 456     public void setProperty(String propertyId, Object value)
 457             throws XMLConfigurationException {
 458     } // setProperty(String,Object)
 459 
 460     /**
 461      * Returns the default state for a feature, or null if this
 462      * component does not want to report a default value for this
 463      * feature.
 464      *
 465      * @param featureId The feature identifier.
 466      *
 467      * @since Xerces 2.2.0
 468      */
 469     public Boolean getFeatureDefault(String featureId) {
 470         for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
 471             if (RECOGNIZED_FEATURES[i].equals(featureId)) {
 472                 return FEATURE_DEFAULTS[i];
 473             }
 474         }
 475         return null;
 476     } // getFeatureDefault(String):Boolean
 477 
 478     /**
 479      * Returns the default state for a property, or null if this
 480      * component does not want to report a default value for this
 481      * property.
 482      *
 483      * @param propertyId The property identifier.
 484      *
 485      * @since Xerces 2.2.0
 486      */
 487     public Object getPropertyDefault(String propertyId) {
 488         for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
 489             if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
 490                 return PROPERTY_DEFAULTS[i];
 491             }
 492         }
 493         return null;
 494     } // getPropertyDefault(String):Object
 495 
 496     //
 497     // XMLDTDSource methods
 498     //
 499 
 500     /**
 501      * Sets the DTD handler.
 502      *
 503      * @param dtdHandler The DTD handler.
 504      */
 505     public void setDTDHandler(XMLDTDHandler dtdHandler) {
 506         fDTDHandler = dtdHandler;
 507     } // setDTDHandler(XMLDTDHandler)
 508 
 509     /**
 510      * Returns the DTD handler.
 511      *
 512      * @return The DTD handler.
 513      */
 514     public XMLDTDHandler getDTDHandler() {
 515         return fDTDHandler;
 516     } // getDTDHandler():  XMLDTDHandler
 517 
 518     //
 519     // XMLDTDContentModelSource methods
 520     //
 521 
 522     /**
 523      * Sets the DTD content model handler.
 524      *
 525      * @param dtdContentModelHandler The DTD content model handler.
 526      */
 527     public void setDTDContentModelHandler(XMLDTDContentModelHandler dtdContentModelHandler) {
 528         fDTDContentModelHandler = dtdContentModelHandler;
 529     } // setDTDContentModelHandler(XMLDTDContentModelHandler)
 530 
 531     /**
 532      * Gets the DTD content model handler.
 533      *
 534      * @return dtdContentModelHandler The DTD content model handler.
 535      */
 536     public XMLDTDContentModelHandler getDTDContentModelHandler() {
 537         return fDTDContentModelHandler;
 538     } // getDTDContentModelHandler():  XMLDTDContentModelHandler
 539 
 540     //
 541     // XMLDTDContentModelHandler and XMLDTDHandler methods
 542     //
 543 
 544     /**
 545      * The start of the DTD external subset.
 546      *
 547      * @param augs Additional information that may include infoset
 548      *                      augmentations.
 549      *
 550      * @throws XNIException Thrown by handler to signal an error.
 551      */
 552     public void startExternalSubset(XMLResourceIdentifier identifier,
 553                                     Augmentations augs) throws XNIException {
 554         if(fDTDGrammar != null)
 555             fDTDGrammar.startExternalSubset(identifier, augs);
 556         if(fDTDHandler != null){
 557             fDTDHandler.startExternalSubset(identifier, augs);
 558         }
 559     }
 560 
 561     /**
 562      * The end of the DTD external subset.
 563      *
 564      * @param augs Additional information that may include infoset
 565      *                      augmentations.
 566      *
 567      * @throws XNIException Thrown by handler to signal an error.
 568      */
 569     public void endExternalSubset(Augmentations augs) throws XNIException {
 570         if(fDTDGrammar != null)
 571             fDTDGrammar.endExternalSubset(augs);
 572         if(fDTDHandler != null){
 573             fDTDHandler.endExternalSubset(augs);
 574         }
 575     }
 576 
 577     /**
 578      * Check standalone entity reference.
 579      * Made static to make common between the validator and loader.
 580      *
 581      * @param name
 582      *@param grammar    grammar to which entity belongs
 583      * @param tempEntityDecl    empty entity declaration to put results in
 584      * @param errorReporter     error reporter to send errors to
 585      *
 586      * @throws XNIException Thrown by application to signal an error.
 587      */
 588     protected static void checkStandaloneEntityRef(String name, DTDGrammar grammar,
 589                     XMLEntityDecl tempEntityDecl, XMLErrorReporter errorReporter) throws XNIException {
 590         // check VC: Standalone Document Declartion, entities references appear in the document.
 591         int entIndex = grammar.getEntityDeclIndex(name);
 592         if (entIndex > -1) {
 593             grammar.getEntityDecl(entIndex, tempEntityDecl);
 594             if (tempEntityDecl.inExternal) {
 595                 errorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
 596                                             "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE",
 597                                             new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR);
 598             }
 599         }
 600     }
 601 
 602     /**
 603      * A comment.
 604      *
 605      * @param text The text in the comment.
 606      * @param augs   Additional information that may include infoset augmentations
 607      *
 608      * @throws XNIException Thrown by application to signal an error.
 609      */
 610     public void comment(XMLString text, Augmentations augs) throws XNIException {
 611 
 612         // call handlers
 613         if(fDTDGrammar != null)
 614             fDTDGrammar.comment(text, augs);
 615         if (fDTDHandler != null) {
 616             fDTDHandler.comment(text, augs);
 617         }
 618 
 619     } // comment(XMLString)
 620 
 621 
 622     /**
 623      * A processing instruction. Processing instructions consist of a
 624      * target name and, optionally, text data. The data is only meaningful
 625      * to the application.
 626      * <p>
 627      * Typically, a processing instruction's data will contain a series
 628      * of pseudo-attributes. These pseudo-attributes follow the form of
 629      * element attributes but are <strong>not</strong> parsed or presented
 630      * to the application as anything other than text. The application is
 631      * responsible for parsing the data.
 632      *
 633      * @param target The target.
 634      * @param data   The data or null if none specified.
 635      * @param augs   Additional information that may include infoset augmentations
 636      *
 637      * @throws XNIException Thrown by handler to signal an error.
 638      */
 639     public void processingInstruction(String target, XMLString data, Augmentations augs)
 640     throws XNIException {
 641 
 642         // call handlers
 643         if(fDTDGrammar != null)
 644             fDTDGrammar.processingInstruction(target, data, augs);
 645         if (fDTDHandler != null) {
 646             fDTDHandler.processingInstruction(target, data, augs);
 647         }
 648     } // processingInstruction(String,XMLString)
 649 
 650     //
 651     // XMLDTDHandler methods
 652     //
 653 
 654     /**
 655      * The start of the DTD.
 656      *
 657      * @param locator  The document locator, or null if the document
 658      *                 location cannot be reported during the parsing of
 659      *                 the document DTD. However, it is <em>strongly</em>
 660      *                 recommended that a locator be supplied that can
 661      *                 at least report the base system identifier of the
 662      *                 DTD.
 663      * @param augs Additional information that may include infoset
 664      *                      augmentations.
 665      *
 666      * @throws XNIException Thrown by handler to signal an error.
 667      */
 668     public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException {
 669 
 670 
 671         // initialize state
 672         fNDataDeclNotations.clear();
 673         fDTDElementDecls.clear();
 674 
 675         // the grammar bucket's DTDGrammar will now be the
 676         // one we want, whether we're constructing it or not.
 677         // if we're not constructing it, then we should not have a reference
 678         // to it!
 679        if( !fGrammarBucket.getActiveGrammar().isImmutable()) {
 680             fDTDGrammar = fGrammarBucket.getActiveGrammar();
 681         }
 682 
 683         // call handlers
 684         if(fDTDGrammar != null )
 685             fDTDGrammar.startDTD(locator, augs);
 686         if (fDTDHandler != null) {
 687             fDTDHandler.startDTD(locator, augs);
 688         }
 689 
 690     } // startDTD(XMLLocator)
 691 
 692     /**
 693      * Characters within an IGNORE conditional section.
 694      *
 695      * @param text The ignored text.
 696      * @param augs Additional information that may include infoset
 697      *                      augmentations.
 698      *
 699      * @throws XNIException Thrown by handler to signal an error.
 700      */
 701     public void ignoredCharacters(XMLString text, Augmentations augs) throws XNIException {
 702 
 703         // ignored characters in DTD
 704         if(fDTDGrammar != null )
 705             fDTDGrammar.ignoredCharacters(text, augs);
 706         if (fDTDHandler != null) {
 707             fDTDHandler.ignoredCharacters(text, augs);
 708         }
 709     }
 710 
 711     /**
 712      * Notifies of the presence of a TextDecl line in an entity. If present,
 713      * this method will be called immediately following the startParameterEntity call.
 714      * <p>
 715      * <strong>Note:</strong> This method is only called for external
 716      * parameter entities referenced in the DTD.
 717      *
 718      * @param version  The XML version, or null if not specified.
 719      * @param encoding The IANA encoding name of the entity.
 720      * @param augs Additional information that may include infoset
 721      *                      augmentations.
 722      *
 723      * @throws XNIException Thrown by handler to signal an error.
 724      */
 725     public void textDecl(String version, String encoding, Augmentations augs) throws XNIException {
 726 
 727         // call handlers
 728         if(fDTDGrammar != null )
 729             fDTDGrammar.textDecl(version, encoding, augs);
 730         if (fDTDHandler != null) {
 731             fDTDHandler.textDecl(version, encoding, augs);
 732         }
 733     }
 734 
 735     /**
 736      * This method notifies of the start of a parameter entity. The parameter
 737      * entity name start with a '%' character.
 738      *
 739      * @param name     The name of the parameter entity.
 740      * @param identifier The resource identifier.
 741      * @param encoding The auto-detected IANA encoding name of the entity
 742      *                 stream. This value will be null in those situations
 743      *                 where the entity encoding is not auto-detected (e.g.
 744      *                 internal parameter entities).
 745      * @param augs Additional information that may include infoset
 746      *                      augmentations.
 747      *
 748      * @throws XNIException Thrown by handler to signal an error.
 749      */
 750     public void startParameterEntity(String name,
 751                                      XMLResourceIdentifier identifier,
 752                                      String encoding,
 753                                      Augmentations augs) throws XNIException {
 754 
 755         if (fPerformValidation && fDTDGrammar != null &&
 756                 fGrammarBucket.getStandalone()) {
 757             checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter);
 758         }
 759         // call handlers
 760         if(fDTDGrammar != null )
 761             fDTDGrammar.startParameterEntity(name, identifier, encoding, augs);
 762         if (fDTDHandler != null) {
 763             fDTDHandler.startParameterEntity(name, identifier, encoding, augs);
 764         }
 765     }
 766 
 767     /**
 768      * This method notifies the end of a parameter entity. Parameter entity
 769      * names begin with a '%' character.
 770      *
 771      * @param name The name of the parameter entity.
 772      * @param augs Additional information that may include infoset
 773      *                      augmentations.
 774      *
 775      * @throws XNIException Thrown by handler to signal an error.
 776      */
 777     public void endParameterEntity(String name, Augmentations augs) throws XNIException {
 778 
 779         // call handlers
 780         if(fDTDGrammar != null )
 781             fDTDGrammar.endParameterEntity(name, augs);
 782         if (fDTDHandler != null) {
 783             fDTDHandler.endParameterEntity(name, augs);
 784         }
 785     }
 786 
 787     /**
 788      * An element declaration.
 789      *
 790      * @param name         The name of the element.
 791      * @param contentModel The element content model.
 792      * @param augs Additional information that may include infoset
 793      *                      augmentations.
 794      *
 795      * @throws XNIException Thrown by handler to signal an error.
 796      */
 797     public void elementDecl(String name, String contentModel, Augmentations augs)
 798     throws XNIException {
 799 
 800         //check VC: Unique Element Declaration
 801         if (fValidation) {
 802             if (fDTDElementDecls.contains(name)) {
 803                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 804                                            "MSG_ELEMENT_ALREADY_DECLARED",
 805                                            new Object[]{ name},
 806                                            XMLErrorReporter.SEVERITY_ERROR);
 807             }
 808             else {
 809                 fDTDElementDecls.add(name);
 810             }
 811         }
 812 
 813         // call handlers
 814         if(fDTDGrammar != null )
 815             fDTDGrammar.elementDecl(name, contentModel, augs);
 816         if (fDTDHandler != null) {
 817             fDTDHandler.elementDecl(name, contentModel, augs);
 818         }
 819 
 820     } // elementDecl(String,String)
 821 
 822     /**
 823      * The start of an attribute list.
 824      *
 825      * @param elementName The name of the element that this attribute
 826      *                    list is associated with.
 827      * @param augs Additional information that may include infoset
 828      *                      augmentations.
 829      *
 830      * @throws XNIException Thrown by handler to signal an error.
 831      */
 832     public void startAttlist(String elementName, Augmentations augs)
 833         throws XNIException {
 834 
 835         // call handlers
 836         if(fDTDGrammar != null )
 837             fDTDGrammar.startAttlist(elementName, augs);
 838         if (fDTDHandler != null) {
 839             fDTDHandler.startAttlist(elementName, augs);
 840         }
 841 
 842     } // startAttlist(String)
 843 
 844     /**
 845      * An attribute declaration.
 846      *
 847      * @param elementName   The name of the element that this attribute
 848      *                      is associated with.
 849      * @param attributeName The name of the attribute.
 850      * @param type          The attribute type. This value will be one of
 851      *                      the following: "CDATA", "ENTITY", "ENTITIES",
 852      *                      "ENUMERATION", "ID", "IDREF", "IDREFS",
 853      *                      "NMTOKEN", "NMTOKENS", or "NOTATION".
 854      * @param enumeration   If the type has the value "ENUMERATION" or
 855      *                      "NOTATION", this array holds the allowed attribute
 856      *                      values; otherwise, this array is null.
 857      * @param defaultType   The attribute default type. This value will be
 858      *                      one of the following: "#FIXED", "#IMPLIED",
 859      *                      "#REQUIRED", or null.
 860      * @param defaultValue  The attribute default value, or null if no
 861      *                      default value is specified.
 862      * @param nonNormalizedDefaultValue  The attribute default value with no normalization
 863      *                      performed, or null if no default value is specified.
 864      * @param augs Additional information that may include infoset
 865      *                      augmentations.
 866      *
 867      * @throws XNIException Thrown by handler to signal an error.
 868      */
 869     public void attributeDecl(String elementName, String attributeName,
 870                               String type, String[] enumeration,
 871                               String defaultType, XMLString defaultValue,
 872                               XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException {
 873 
 874         if (type != XMLSymbols.fCDATASymbol && defaultValue != null) {
 875             normalizeDefaultAttrValue(defaultValue);
 876         }
 877 
 878         if (fValidation) {
 879 
 880                 boolean duplicateAttributeDef = false ;
 881 
 882                 //Get Grammar index to grammar array
 883                 DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar:fGrammarBucket.getActiveGrammar());
 884                 int elementIndex       = grammar.getElementDeclIndex( elementName);
 885                 if (grammar.getAttributeDeclIndex(elementIndex, attributeName) != -1) {
 886                     //more than one attribute definition is provided for the same attribute of a given element type.
 887                     duplicateAttributeDef = true ;
 888 
 889                     //this feature works only when validation is true.
 890                     if(fWarnDuplicateAttdef){
 891                         fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 892                                                  "MSG_DUPLICATE_ATTRIBUTE_DEFINITION",
 893                                                  new Object[]{ elementName, attributeName },
 894                                                  XMLErrorReporter.SEVERITY_WARNING );
 895                     }
 896                 }
 897 
 898 
 899             //
 900             // a) VC: One ID per Element Type, If duplicate ID attribute
 901             // b) VC: ID attribute Default. if there is a declareared attribute
 902             //        default for ID it should be of type #IMPLIED or #REQUIRED
 903             if (type == XMLSymbols.fIDSymbol) {
 904                 if (defaultValue != null && defaultValue.length != 0) {
 905                     if (defaultType == null ||
 906                         !(defaultType == XMLSymbols.fIMPLIEDSymbol ||
 907                           defaultType == XMLSymbols.fREQUIREDSymbol)) {
 908                         fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 909                                                    "IDDefaultTypeInvalid",
 910                                                    new Object[]{ attributeName},
 911                                                    XMLErrorReporter.SEVERITY_ERROR);
 912                     }
 913                 }
 914 
 915                 if (!fTableOfIDAttributeNames.containsKey(elementName)) {
 916                     fTableOfIDAttributeNames.put(elementName, attributeName);
 917                 }
 918                 else {
 919                         //we should not report an error, when there is duplicate attribute definition for given element type
 920                         //according to XML 1.0 spec, When more than one definition is provided for the same attribute of a given
 921                         //element type, the first declaration is binding and later declaration are *ignored*. So processor should
 922                         //ignore the second declarations, however an application would be warned of the duplicate attribute defintion
 923                         // if http://apache.org/xml/features/validation/warn-on-duplicate-attdef feature is set to true,
 924                         // one typical case where this could be a  problem, when any XML file
 925                         // provide the ID type information through internal subset so that it is available to the parser which read
 926                         //only internal subset. Now that attribute declaration(ID Type) can again be part of external parsed entity
 927                         //referenced. At that time if parser doesn't make this distinction it will throw an error for VC One ID per
 928                         //Element Type, which (second defintion) actually should be ignored. Application behavior may differ on the
 929                         //basis of error or warning thrown. - nb.
 930 
 931                         if(!duplicateAttributeDef){
 932                                 String previousIDAttributeName = (String)fTableOfIDAttributeNames.get( elementName );//rule a)
 933                                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 934                                                "MSG_MORE_THAN_ONE_ID_ATTRIBUTE",
 935                                                new Object[]{ elementName, previousIDAttributeName, attributeName},
 936                                                XMLErrorReporter.SEVERITY_ERROR);
 937                         }
 938                 }
 939             }
 940 
 941             //
 942             //  VC: One Notation Per Element Type, should check if there is a
 943             //      duplicate NOTATION attribute
 944 
 945             if (type == XMLSymbols.fNOTATIONSymbol) {
 946                 // VC: Notation Attributes: all notation names in the
 947                 //     (attribute) declaration must be declared.
 948                 for (int i=0; i<enumeration.length; i++) {
 949                     fNotationEnumVals.put(enumeration[i], attributeName);
 950                 }
 951 
 952                 if (fTableOfNOTATIONAttributeNames.containsKey( elementName ) == false) {
 953                     fTableOfNOTATIONAttributeNames.put( elementName, attributeName);
 954                 }
 955                 else {
 956                         //we should not report an error, when there is duplicate attribute definition for given element type
 957                         //according to XML 1.0 spec, When more than one definition is provided for the same attribute of a given
 958                         //element type, the first declaration is binding and later declaration are *ignored*. So processor should
 959                         //ignore the second declarations, however an application would be warned of the duplicate attribute definition
 960                         // if http://apache.org/xml/features/validation/warn-on-duplicate-attdef feature is set to true, Application behavior may differ on the basis of error or
 961                         //warning thrown. - nb.
 962 
 963                         if(!duplicateAttributeDef){
 964 
 965                                 String previousNOTATIONAttributeName = (String) fTableOfNOTATIONAttributeNames.get( elementName );
 966                                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 967                                                "MSG_MORE_THAN_ONE_NOTATION_ATTRIBUTE",
 968                                                new Object[]{ elementName, previousNOTATIONAttributeName, attributeName},
 969                                                XMLErrorReporter.SEVERITY_ERROR);
 970                          }
 971                 }
 972             }
 973 
 974             // VC: No Duplicate Tokens
 975             // XML 1.0 SE Errata - E2
 976             if (type == XMLSymbols.fENUMERATIONSymbol || type == XMLSymbols.fNOTATIONSymbol) {
 977                 outer:
 978                     for (int i = 0; i < enumeration.length; ++i) {
 979                         for (int j = i + 1; j < enumeration.length; ++j) {
 980                             if (enumeration[i].equals(enumeration[j])) {
 981                                 // Only report the first uniqueness violation. There could be others,
 982                                 // but additional overhead would be incurred tracking unique tokens
 983                                 // that have already been encountered. -- mrglavas
 984                                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 985                                                type == XMLSymbols.fENUMERATIONSymbol
 986                                                    ? "MSG_DISTINCT_TOKENS_IN_ENUMERATION"
 987                                                    : "MSG_DISTINCT_NOTATION_IN_ENUMERATION",
 988                                                new Object[]{ elementName, enumeration[i], attributeName },
 989                                                XMLErrorReporter.SEVERITY_ERROR);
 990                                 break outer;
 991                             }
 992                         }
 993                     }
 994             }
 995 
 996             // VC: Attribute Default Legal
 997             boolean ok = true;
 998             if (defaultValue != null &&
 999                 (defaultType == null ||
1000                  (defaultType != null && defaultType == XMLSymbols.fFIXEDSymbol))) {
1001 
1002                 String value = defaultValue.toString();
1003                 if (type == XMLSymbols.fNMTOKENSSymbol ||
1004                     type == XMLSymbols.fENTITIESSymbol ||
1005                     type == XMLSymbols.fIDREFSSymbol) {
1006 
1007                     StringTokenizer tokenizer = new StringTokenizer(value," ");
1008                     if (tokenizer.hasMoreTokens()) {
1009                         while (true) {
1010                             String nmtoken = tokenizer.nextToken();
1011                             if (type == XMLSymbols.fNMTOKENSSymbol) {
1012                                 if (!isValidNmtoken(nmtoken)) {
1013                                     ok = false;
1014                                     break;
1015                                 }
1016                             }
1017                             else if (type == XMLSymbols.fENTITIESSymbol ||
1018                                      type == XMLSymbols.fIDREFSSymbol) {
1019                                 if (!isValidName(nmtoken)) {
1020                                     ok = false;
1021                                     break;
1022                                 }
1023                             }
1024                             if (!tokenizer.hasMoreTokens()) {
1025                                 break;
1026                             }
1027                         }
1028                     }
1029 
1030                 }
1031                 else {
1032                     if (type == XMLSymbols.fENTITYSymbol ||
1033                         type == XMLSymbols.fIDSymbol ||
1034                         type == XMLSymbols.fIDREFSymbol ||
1035                         type == XMLSymbols.fNOTATIONSymbol) {
1036 
1037                         if (!isValidName(value)) {
1038                             ok = false;
1039                         }
1040 
1041                     }
1042                     else if (type == XMLSymbols.fNMTOKENSymbol ||
1043                              type == XMLSymbols.fENUMERATIONSymbol) {
1044 
1045                         if (!isValidNmtoken(value)) {
1046                             ok = false;
1047                         }
1048                     }
1049 
1050                     if (type == XMLSymbols.fNOTATIONSymbol ||
1051                         type == XMLSymbols.fENUMERATIONSymbol) {
1052                         ok = false;
1053                         for (int i=0; i<enumeration.length; i++) {
1054                             if (defaultValue.equals(enumeration[i])) {
1055                                 ok = true;
1056                             }
1057                         }
1058                     }
1059 
1060                 }
1061                 if (!ok) {
1062                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1063                                                "MSG_ATT_DEFAULT_INVALID",
1064                                                new Object[]{attributeName, value},
1065                                                XMLErrorReporter.SEVERITY_ERROR);
1066                 }
1067             }
1068         }
1069 
1070         // call handlers
1071         if(fDTDGrammar != null)
1072             fDTDGrammar.attributeDecl(elementName, attributeName,
1073                                   type, enumeration,
1074                                   defaultType, defaultValue, nonNormalizedDefaultValue, augs);
1075         if (fDTDHandler != null) {
1076             fDTDHandler.attributeDecl(elementName, attributeName,
1077                                       type, enumeration,
1078                                       defaultType, defaultValue, nonNormalizedDefaultValue, augs);
1079         }
1080 
1081     } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations)
1082 
1083     /**
1084      * The end of an attribute list.
1085      *
1086      * @param augs Additional information that may include infoset
1087      *                      augmentations.
1088      *
1089      * @throws XNIException Thrown by handler to signal an error.
1090      */
1091     public void endAttlist(Augmentations augs) throws XNIException {
1092 
1093         // call handlers
1094         if(fDTDGrammar != null)
1095             fDTDGrammar.endAttlist(augs);
1096         if (fDTDHandler != null) {
1097             fDTDHandler.endAttlist(augs);
1098         }
1099 
1100     } // endAttlist()
1101 
1102     /**
1103      * An internal entity declaration.
1104      *
1105      * @param name The name of the entity. Parameter entity names start with
1106      *             '%', whereas the name of a general entity is just the
1107      *             entity name.
1108      * @param text The value of the entity.
1109      * @param nonNormalizedText The non-normalized value of the entity. This
1110      *             value contains the same sequence of characters that was in
1111      *             the internal entity declaration, without any entity
1112      *             references expanded.
1113      * @param augs Additional information that may include infoset
1114      *                      augmentations.
1115      *
1116      * @throws XNIException Thrown by handler to signal an error.
1117      */
1118     public void internalEntityDecl(String name, XMLString text,
1119                                    XMLString nonNormalizedText,
1120                                    Augmentations augs) throws XNIException {
1121 
1122         DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar: fGrammarBucket.getActiveGrammar());
1123         int index = grammar.getEntityDeclIndex(name) ;
1124 
1125         //If the same entity is declared more than once, the first declaration
1126         //encountered is binding, SAX requires only effective(first) declaration
1127         //to be reported to the application
1128 
1129         //REVISIT: Does it make sense to pass duplicate Entity information across
1130         //the pipeline -- nb?
1131 
1132         //its a new entity and hasn't been declared.
1133         if(index == -1){
1134             //store internal entity declaration in grammar
1135             if(fDTDGrammar != null)
1136                 fDTDGrammar.internalEntityDecl(name, text, nonNormalizedText, augs);
1137             // call handlers
1138             if (fDTDHandler != null) {
1139                 fDTDHandler.internalEntityDecl(name, text, nonNormalizedText, augs);
1140             }
1141         }
1142 
1143     } // internalEntityDecl(String,XMLString,XMLString)
1144 
1145 
1146     /**
1147      * An external entity declaration.
1148      *
1149      * @param name     The name of the entity. Parameter entity names start
1150      *                 with '%', whereas the name of a general entity is just
1151      *                 the entity name.
1152      * @param identifier    An object containing all location information
1153      *                      pertinent to this external entity.
1154      * @param augs Additional information that may include infoset
1155      *                      augmentations.
1156      *
1157      * @throws XNIException Thrown by handler to signal an error.
1158      */
1159     public void externalEntityDecl(String name, XMLResourceIdentifier identifier,
1160                                    Augmentations augs) throws XNIException {
1161 
1162         DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar:  fGrammarBucket.getActiveGrammar());
1163         int index = grammar.getEntityDeclIndex(name) ;
1164 
1165         //If the same entity is declared more than once, the first declaration
1166         //encountered is binding, SAX requires only effective(first) declaration
1167         //to be reported to the application
1168 
1169         //REVISIT: Does it make sense to pass duplicate entity information across
1170         //the pipeline -- nb?
1171 
1172         //its a new entity and hasn't been declared.
1173         if(index == -1){
1174             //store external entity declaration in grammar
1175             if(fDTDGrammar != null)
1176                 fDTDGrammar.externalEntityDecl(name, identifier, augs);
1177             // call handlers
1178             if (fDTDHandler != null) {
1179                 fDTDHandler.externalEntityDecl(name, identifier, augs);
1180             }
1181         }
1182 
1183     } // externalEntityDecl(String,XMLResourceIdentifier, Augmentations)
1184 
1185     /**
1186      * An unparsed entity declaration.
1187      *
1188      * @param name     The name of the entity.
1189      * @param identifier    An object containing all location information
1190      *                      pertinent to this entity.
1191      * @param notation The name of the notation.
1192      * @param augs Additional information that may include infoset
1193      *                      augmentations.
1194      *
1195      * @throws XNIException Thrown by handler to signal an error.
1196      */
1197     public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier,
1198                                    String notation,
1199                                    Augmentations augs) throws XNIException {
1200 
1201         // VC: Notation declared,  in the production of NDataDecl
1202         if (fValidation) {
1203             fNDataDeclNotations.put(name, notation);
1204         }
1205 
1206         // call handlers
1207         if(fDTDGrammar != null)
1208             fDTDGrammar.unparsedEntityDecl(name, identifier, notation, augs);
1209         if (fDTDHandler != null) {
1210             fDTDHandler.unparsedEntityDecl(name, identifier, notation, augs);
1211         }
1212 
1213     } // unparsedEntityDecl(String,XMLResourceIdentifier,String,Augmentations)
1214 
1215     /**
1216      * A notation declaration
1217      *
1218      * @param name     The name of the notation.
1219      * @param identifier    An object containing all location information
1220      *                      pertinent to this notation.
1221      * @param augs Additional information that may include infoset
1222      *                      augmentations.
1223      *
1224      * @throws XNIException Thrown by handler to signal an error.
1225      */
1226     public void notationDecl(String name, XMLResourceIdentifier identifier,
1227                              Augmentations augs) throws XNIException {
1228 
1229         // VC: Unique Notation Name
1230         if (fValidation) {
1231             DTDGrammar grammar = (fDTDGrammar != null ? fDTDGrammar : fGrammarBucket.getActiveGrammar());
1232             if (grammar.getNotationDeclIndex(name) != -1) {
1233                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1234                                            "UniqueNotationName",
1235                                            new Object[]{name},
1236                                            XMLErrorReporter.SEVERITY_ERROR);
1237             }
1238         }
1239 
1240         // call handlers
1241         if(fDTDGrammar != null)
1242             fDTDGrammar.notationDecl(name, identifier, augs);
1243         if (fDTDHandler != null) {
1244             fDTDHandler.notationDecl(name, identifier, augs);
1245         }
1246 
1247     } // notationDecl(String,XMLResourceIdentifier, Augmentations)
1248 
1249     /**
1250      * The start of a conditional section.
1251      *
1252      * @param type The type of the conditional section. This value will
1253      *             either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE.
1254      * @param augs Additional information that may include infoset
1255      *                      augmentations.
1256      *
1257      * @throws XNIException Thrown by handler to signal an error.
1258      *
1259      * @see #CONDITIONAL_INCLUDE
1260      * @see #CONDITIONAL_IGNORE
1261      */
1262     public void startConditional(short type, Augmentations augs) throws XNIException {
1263 
1264         // set state
1265         fInDTDIgnore = type == XMLDTDHandler.CONDITIONAL_IGNORE;
1266 
1267         // call handlers
1268         if(fDTDGrammar != null)
1269             fDTDGrammar.startConditional(type, augs);
1270         if (fDTDHandler != null) {
1271             fDTDHandler.startConditional(type, augs);
1272         }
1273 
1274     } // startConditional(short)
1275 
1276     /**
1277      * The end of a conditional section.
1278      *
1279      * @param augs Additional information that may include infoset
1280      *                      augmentations.
1281      *
1282      * @throws XNIException Thrown by handler to signal an error.
1283      */
1284     public void endConditional(Augmentations augs) throws XNIException {
1285 
1286         // set state
1287         fInDTDIgnore = false;
1288 
1289         // call handlers
1290         if(fDTDGrammar != null)
1291             fDTDGrammar.endConditional(augs);
1292         if (fDTDHandler != null) {
1293             fDTDHandler.endConditional(augs);
1294         }
1295 
1296     } // endConditional()
1297 
1298     /**
1299      * The end of the DTD.
1300      *
1301      * @param augs Additional information that may include infoset
1302      *                      augmentations.
1303      *
1304      * @throws XNIException Thrown by handler to signal an error.
1305      */
1306     public void endDTD(Augmentations augs) throws XNIException {
1307 
1308 
1309         // save grammar
1310         if(fDTDGrammar != null) {
1311             fDTDGrammar.endDTD(augs);
1312             if(fGrammarPool != null)
1313                 fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_DTD, new Grammar[] {fDTDGrammar});
1314         }
1315         if (fValidation) {
1316             DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar: fGrammarBucket.getActiveGrammar());
1317 
1318             // VC : Notation Declared. for external entity declaration [Production 76].
1319             Iterator entities = fNDataDeclNotations.entrySet().iterator();
1320             while (entities.hasNext()) {
1321                 Map.Entry entry = (Map.Entry) entities.next();
1322                 String notation = (String) entry.getValue();
1323                 if (grammar.getNotationDeclIndex(notation) == -1) {
1324                     String entity = (String) entry.getKey();
1325                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1326                                                "MSG_NOTATION_NOT_DECLARED_FOR_UNPARSED_ENTITYDECL",
1327                                                new Object[]{entity, notation},
1328                                                XMLErrorReporter.SEVERITY_ERROR);
1329                 }
1330             }
1331 
1332             // VC: Notation Attributes:
1333             //     all notation names in the (attribute) declaration must be declared.
1334             Iterator notationVals = fNotationEnumVals.entrySet().iterator();
1335             while (notationVals.hasNext()) {
1336                 Map.Entry entry = (Map.Entry) notationVals.next();
1337                 String notation = (String) entry.getKey();
1338                 if (grammar.getNotationDeclIndex(notation) == -1) {
1339                     String attributeName = (String) entry.getValue();
1340                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1341                                                "MSG_NOTATION_NOT_DECLARED_FOR_NOTATIONTYPE_ATTRIBUTE",
1342                                                new Object[]{attributeName, notation},
1343                                                XMLErrorReporter.SEVERITY_ERROR);
1344                 }
1345             }
1346 
1347             // VC: No Notation on Empty Element
1348             // An attribute of type NOTATION must not be declared on an element declared EMPTY.
1349             Iterator elementsWithNotations = fTableOfNOTATIONAttributeNames.entrySet().iterator();
1350             while (elementsWithNotations.hasNext()) {
1351                 Map.Entry entry = (Map.Entry) elementsWithNotations.next();
1352                 String elementName = (String) entry.getKey();
1353                 int elementIndex = grammar.getElementDeclIndex(elementName);
1354                 if (grammar.getContentSpecType(elementIndex) == XMLElementDecl.TYPE_EMPTY) {
1355                     String attributeName = (String) entry.getValue();
1356                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1357                                                "NoNotationOnEmptyElement",
1358                                                new Object[]{elementName, attributeName},
1359                                                XMLErrorReporter.SEVERITY_ERROR);
1360                 }
1361             }
1362 
1363             // should be safe to release these references
1364             fTableOfIDAttributeNames = null;
1365             fTableOfNOTATIONAttributeNames = null;
1366 
1367             // check whether each element referenced in a content model is declared
1368             if (fWarnOnUndeclaredElemdef) {
1369                 checkDeclaredElements(grammar);
1370             }
1371         }
1372 
1373         // call handlers
1374         if (fDTDHandler != null) {
1375             fDTDHandler.endDTD(augs);
1376         }
1377 
1378     } // endDTD()
1379 
1380     // sets the XMLDTDSource of this handler
1381     public void setDTDSource(XMLDTDSource source ) {
1382         fDTDSource = source;
1383     } // setDTDSource(XMLDTDSource)
1384 
1385     // returns the XMLDTDSource of this handler
1386     public XMLDTDSource getDTDSource() {
1387         return fDTDSource;
1388     } // getDTDSource():  XMLDTDSource
1389 
1390     //
1391     // XMLDTDContentModelHandler methods
1392     //
1393 
1394     // sets the XMLContentModelDTDSource of this handler
1395     public void setDTDContentModelSource(XMLDTDContentModelSource source ) {
1396         fDTDContentModelSource = source;
1397     } // setDTDContentModelSource(XMLDTDContentModelSource)
1398 
1399     // returns the XMLDTDSource of this handler
1400     public XMLDTDContentModelSource getDTDContentModelSource() {
1401         return fDTDContentModelSource;
1402     } // getDTDContentModelSource():  XMLDTDContentModelSource
1403 
1404 
1405     /**
1406      * The start of a content model. Depending on the type of the content
1407      * model, specific methods may be called between the call to the
1408      * startContentModel method and the call to the endContentModel method.
1409      *
1410      * @param elementName The name of the element.
1411      * @param augs Additional information that may include infoset
1412      *                      augmentations.
1413      *
1414      * @throws XNIException Thrown by handler to signal an error.
1415      */
1416     public void startContentModel(String elementName, Augmentations augs)
1417         throws XNIException {
1418 
1419         if (fValidation) {
1420             fDTDElementDeclName = elementName;
1421             fMixedElementTypes.clear();
1422         }
1423 
1424         // call handlers
1425         if(fDTDGrammar != null)
1426             fDTDGrammar.startContentModel(elementName, augs);
1427         if (fDTDContentModelHandler != null) {
1428             fDTDContentModelHandler.startContentModel(elementName, augs);
1429         }
1430 
1431     } // startContentModel(String)
1432 
1433     /**
1434      * A content model of ANY.
1435      *
1436      * @param augs Additional information that may include infoset
1437      *                      augmentations.
1438      *
1439      * @throws XNIException Thrown by handler to signal an error.
1440      *
1441      * @see #empty
1442      * @see #startGroup
1443      */
1444     public void any(Augmentations augs) throws XNIException {
1445         if(fDTDGrammar != null)
1446             fDTDGrammar.any(augs);
1447         if (fDTDContentModelHandler != null) {
1448             fDTDContentModelHandler.any(augs);
1449         }
1450     } // any()
1451 
1452     /**
1453      * A content model of EMPTY.
1454      *
1455      * @param augs Additional information that may include infoset
1456      *                      augmentations.
1457      *
1458      * @throws XNIException Thrown by handler to signal an error.
1459      *
1460      * @see #any
1461      * @see #startGroup
1462      */
1463     public void empty(Augmentations augs) throws XNIException {
1464         if(fDTDGrammar != null)
1465             fDTDGrammar.empty(augs);
1466         if (fDTDContentModelHandler != null) {
1467             fDTDContentModelHandler.empty(augs);
1468         }
1469     } // empty()
1470 
1471     /**
1472      * A start of either a mixed or children content model. A mixed
1473      * content model will immediately be followed by a call to the
1474      * <code>pcdata()</code> method. A children content model will
1475      * contain additional groups and/or elements.
1476      *
1477      * @param augs Additional information that may include infoset
1478      *                      augmentations.
1479      *
1480      * @throws XNIException Thrown by handler to signal an error.
1481      *
1482      * @see #any
1483      * @see #empty
1484      */
1485     public void startGroup(Augmentations augs) throws XNIException {
1486 
1487         fMixed = false;
1488         // call handlers
1489         if(fDTDGrammar != null)
1490             fDTDGrammar.startGroup(augs);
1491         if (fDTDContentModelHandler != null) {
1492             fDTDContentModelHandler.startGroup(augs);
1493         }
1494 
1495     } // startGroup()
1496 
1497     /**
1498      * The appearance of "#PCDATA" within a group signifying a
1499      * mixed content model. This method will be the first called
1500      * following the content model's <code>startGroup()</code>.
1501      *
1502      * @param augs Additional information that may include infoset
1503      *                      augmentations.
1504      *
1505      * @throws XNIException Thrown by handler to signal an error.
1506      *
1507      * @see #startGroup
1508      */
1509     public void pcdata(Augmentations augs) {
1510         fMixed = true;
1511         if(fDTDGrammar != null)
1512             fDTDGrammar.pcdata(augs);
1513         if (fDTDContentModelHandler != null) {
1514             fDTDContentModelHandler.pcdata(augs);
1515         }
1516     } // pcdata()
1517 
1518     /**
1519      * A referenced element in a mixed or children content model.
1520      *
1521      * @param elementName The name of the referenced element.
1522      * @param augs Additional information that may include infoset
1523      *                      augmentations.
1524      *
1525      * @throws XNIException Thrown by handler to signal an error.
1526      */
1527     public void element(String elementName, Augmentations augs) throws XNIException {
1528 
1529         // check VC: No duplicate Types, in a single mixed-content declaration
1530         if (fMixed && fValidation) {
1531             if (fMixedElementTypes.contains(elementName)) {
1532                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1533                                            "DuplicateTypeInMixedContent",
1534                                            new Object[]{fDTDElementDeclName, elementName},
1535                                            XMLErrorReporter.SEVERITY_ERROR);
1536             }
1537             else {
1538                 fMixedElementTypes.add(elementName);
1539             }
1540         }
1541 
1542         // call handlers
1543         if(fDTDGrammar != null)
1544             fDTDGrammar.element(elementName, augs);
1545         if (fDTDContentModelHandler != null) {
1546             fDTDContentModelHandler.element(elementName, augs);
1547         }
1548 
1549     } // childrenElement(String)
1550 
1551     /**
1552      * The separator between choices or sequences of a mixed or children
1553      * content model.
1554      *
1555      * @param separator The type of children separator.
1556      * @param augs Additional information that may include infoset
1557      *                      augmentations.
1558      *
1559      * @throws XNIException Thrown by handler to signal an error.
1560      *
1561      * @see #SEPARATOR_CHOICE
1562      * @see #SEPARATOR_SEQUENCE
1563      */
1564     public void separator(short separator, Augmentations augs)
1565         throws XNIException {
1566 
1567         // call handlers
1568         if(fDTDGrammar != null)
1569             fDTDGrammar.separator(separator, augs);
1570         if (fDTDContentModelHandler != null) {
1571             fDTDContentModelHandler.separator(separator, augs);
1572         }
1573 
1574     } // separator(short)
1575 
1576     /**
1577      * The occurrence count for a child in a children content model or
1578      * for the mixed content model group.
1579      *
1580      * @param occurrence The occurrence count for the last element
1581      *                   or group.
1582      * @param augs Additional information that may include infoset
1583      *                      augmentations.
1584      *
1585      * @throws XNIException Thrown by handler to signal an error.
1586      *
1587      * @see #OCCURS_ZERO_OR_ONE
1588      * @see #OCCURS_ZERO_OR_MORE
1589      * @see #OCCURS_ONE_OR_MORE
1590      */
1591     public void occurrence(short occurrence, Augmentations augs)
1592         throws XNIException {
1593 
1594         // call handlers
1595         if(fDTDGrammar != null)
1596             fDTDGrammar.occurrence(occurrence, augs);
1597         if (fDTDContentModelHandler != null) {
1598             fDTDContentModelHandler.occurrence(occurrence, augs);
1599         }
1600 
1601     } // occurrence(short)
1602 
1603     /**
1604      * The end of a group for mixed or children content models.
1605      *
1606      * @param augs Additional information that may include infoset
1607      *                      augmentations.
1608      *
1609      * @throws XNIException Thrown by handler to signal an error.
1610      */
1611     public void endGroup(Augmentations augs) throws XNIException {
1612 
1613         // call handlers
1614         if(fDTDGrammar != null)
1615             fDTDGrammar.endGroup(augs);
1616         if (fDTDContentModelHandler != null) {
1617             fDTDContentModelHandler.endGroup(augs);
1618         }
1619 
1620     } // endGroup()
1621 
1622     /**
1623      * The end of a content model.
1624      *
1625      * @param augs Additional information that may include infoset
1626      *                      augmentations.
1627      *
1628      * @throws XNIException Thrown by handler to signal an error.
1629      */
1630     public void endContentModel(Augmentations augs) throws XNIException {
1631 
1632         // call handlers
1633         if(fDTDGrammar != null)
1634             fDTDGrammar.endContentModel(augs);
1635         if (fDTDContentModelHandler != null) {
1636             fDTDContentModelHandler.endContentModel(augs);
1637         }
1638 
1639     } // endContentModel()
1640 
1641     //
1642     // Private methods
1643     //
1644 
1645     /**
1646      * Normalize the attribute value of a non CDATA default attribute
1647      * collapsing sequences of space characters (x20)
1648      *
1649      * @param value The value to normalize
1650      * @return Whether the value was changed or not.
1651      */
1652     private boolean normalizeDefaultAttrValue(XMLString value) {
1653 
1654         boolean skipSpace = true; // skip leading spaces
1655         int current = value.offset;
1656         int end = value.offset + value.length;
1657         for (int i = value.offset; i < end; i++) {
1658             if (value.ch[i] == ' ') {
1659                 if (!skipSpace) {
1660                     // take the first whitespace as a space and skip the others
1661                     value.ch[current++] = ' ';
1662                     skipSpace = true;
1663                 }
1664                 else {
1665                     // just skip it.
1666                 }
1667             }
1668             else {
1669                 // simply shift non space chars if needed
1670                 if (current != i) {
1671                     value.ch[current] = value.ch[i];
1672                 }
1673                 current++;
1674                 skipSpace = false;
1675             }
1676         }
1677         if (current != end) {
1678             if (skipSpace) {
1679                 // if we finished on a space trim it
1680                 current--;
1681             }
1682             // set the new value length
1683             value.length = current - value.offset;
1684             return true;
1685         }
1686         return false;
1687     }
1688 
1689     protected boolean isValidNmtoken(String nmtoken) {
1690         return XMLChar.isValidNmtoken(nmtoken);
1691     } // isValidNmtoken(String):  boolean
1692 
1693     protected boolean isValidName(String name) {
1694         return XMLChar.isValidName(name);
1695     } // isValidName(String):  boolean
1696 
1697     /**
1698      * Checks that all elements referenced in content models have
1699      * been declared. This method calls out to the error handler
1700      * to indicate warnings.
1701      */
1702     private void checkDeclaredElements(DTDGrammar grammar) {
1703         int elementIndex = grammar.getFirstElementDeclIndex();
1704         XMLContentSpec contentSpec = new XMLContentSpec();
1705         while (elementIndex >= 0) {
1706             int type = grammar.getContentSpecType(elementIndex);
1707             if (type == XMLElementDecl.TYPE_CHILDREN || type == XMLElementDecl.TYPE_MIXED) {
1708                 checkDeclaredElements(grammar,
1709                         elementIndex,
1710                         grammar.getContentSpecIndex(elementIndex),
1711                         contentSpec);
1712             }
1713             elementIndex = grammar.getNextElementDeclIndex(elementIndex);
1714         }
1715     }
1716 
1717     /**
1718      * Does a recursive (if necessary) check on the specified element's
1719      * content spec to make sure that all children refer to declared
1720      * elements.
1721      */
1722     private void checkDeclaredElements(DTDGrammar grammar, int elementIndex,
1723             int contentSpecIndex, XMLContentSpec contentSpec) {
1724         grammar.getContentSpec(contentSpecIndex, contentSpec);
1725         if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
1726             String value = (String) contentSpec.value;
1727             if (value != null && grammar.getElementDeclIndex(value) == -1) {
1728                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1729                         "UndeclaredElementInContentSpec",
1730                         new Object[]{grammar.getElementDeclName(elementIndex).rawname, value},
1731                         XMLErrorReporter.SEVERITY_WARNING);
1732             }
1733         }
1734         // It's not a leaf, so we have to recurse its left and maybe right
1735         // nodes. Save both values before we recurse and trash the node.
1736         else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE)
1737                 || (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) {
1738             final int leftNode = ((int[])contentSpec.value)[0];
1739             final int rightNode = ((int[])contentSpec.otherValue)[0];
1740             //  Recurse on both children.
1741             checkDeclaredElements(grammar, elementIndex, leftNode, contentSpec);
1742             checkDeclaredElements(grammar, elementIndex, rightNode, contentSpec);
1743         }
1744         else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE
1745                 || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE
1746                 || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) {
1747             final int leftNode = ((int[])contentSpec.value)[0];
1748             checkDeclaredElements(grammar, elementIndex, leftNode, contentSpec);
1749         }
1750     }
1751 
1752 } // class XMLDTDProcessor