1 /*
   2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 
   5 /*
   6  * Copyright 2005 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xerces.internal.impl;
  22 import com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar;
  23 import java.io.EOFException;
  24 import java.io.IOException;
  25 
  26 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  27 
  28 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  29 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  30 import com.sun.org.apache.xerces.internal.util.XMLChar;
  31 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
  32 
  33 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
  34 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
  35 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  36 import com.sun.org.apache.xerces.internal.xni.XMLString;
  37 import com.sun.org.apache.xerces.internal.xni.XNIException;
  38 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  39 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  40 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  41 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDScanner;
  42 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  43 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  44 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  45 import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler;
  46 import com.sun.org.apache.xerces.internal.impl.Constants;
  47 import com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer;
  48 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
  49 import com.sun.xml.internal.stream.Entity;
  50 
  51 /**
  52  * This class is responsible for scanning the declarations found
  53  * in the internal and external subsets of a DTD in an XML document.
  54  * The scanner acts as the sources for the DTD information which is
  55  * communicated to the DTD handlers.
  56  * <p>
  57  * This component requires the following features and properties from the
  58  * component manager that uses it:
  59  * <ul>
  60  *  <li>http://xml.org/sax/features/validation</li>
  61  *  <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
  62  *  <li>http://apache.org/xml/properties/internal/symbol-table</li>
  63  *  <li>http://apache.org/xml/properties/internal/error-reporter</li>
  64  *  <li>http://apache.org/xml/properties/internal/entity-manager</li>
  65  * </ul>
  66  *
  67  * @author Arnaud  Le Hors, IBM
  68  * @author Andy Clark, IBM
  69  * @author Glenn Marcy, IBM
  70  * @author Eric Ye, IBM
  71  *
  72  * @version $Id: XMLDTDScannerImpl.java,v 1.8 2010-11-01 04:39:41 joehw Exp $
  73  */
  74 public class XMLDTDScannerImpl
  75 extends XMLScanner
  76 implements XMLDTDScanner, XMLComponent, XMLEntityHandler {
  77 
  78     //
  79     // Constants
  80     //
  81 
  82     // scanner states
  83 
  84     /** Scanner state: end of input. */
  85     protected static final int SCANNER_STATE_END_OF_INPUT = 0;
  86 
  87     /** Scanner state: text declaration. */
  88     protected static final int SCANNER_STATE_TEXT_DECL = 1;
  89 
  90     /** Scanner state: markup declaration. */
  91     protected static final int SCANNER_STATE_MARKUP_DECL = 2;
  92 
  93     // recognized features and properties
  94 
  95     /** Recognized features. */
  96     private static final String[] RECOGNIZED_FEATURES = {
  97         VALIDATION,
  98         NOTIFY_CHAR_REFS,
  99     };
 100 
 101     /** Feature defaults. */
 102     private static final Boolean[] FEATURE_DEFAULTS = {
 103         null,
 104         Boolean.FALSE,
 105     };
 106 
 107     /** Recognized properties. */
 108     private static final String[] RECOGNIZED_PROPERTIES = {
 109         SYMBOL_TABLE,
 110         ERROR_REPORTER,
 111         ENTITY_MANAGER,
 112     };
 113 
 114     /** Property defaults. */
 115     private static final Object[] PROPERTY_DEFAULTS = {
 116         null,
 117         null,
 118         null,
 119     };
 120 
 121     // debugging
 122 
 123     /** Debug scanner state. */
 124     private static final boolean DEBUG_SCANNER_STATE = false;
 125 
 126     //
 127     // Data
 128     //
 129 
 130     // handlers
 131 
 132     /** DTD handler. */
 133     public XMLDTDHandler fDTDHandler = null;
 134 
 135     /** DTD content model handler. */
 136     protected XMLDTDContentModelHandler fDTDContentModelHandler;
 137 
 138     // state
 139 
 140     /** Scanner state. */
 141     protected int fScannerState;
 142 
 143     /** Standalone. */
 144     protected boolean fStandalone;
 145 
 146     /** Seen external DTD. */
 147     protected boolean fSeenExternalDTD;
 148 
 149     /** Seen external parameter entity. */
 150     protected boolean fSeenExternalPE;
 151 
 152     // private data
 153 
 154     /** Start DTD called. */
 155     private boolean fStartDTDCalled;
 156 
 157     /** Default attribute */
 158     private XMLAttributesImpl fAttributes = new XMLAttributesImpl();
 159 
 160     /**
 161      * Stack of content operators (either '|' or ',') in children
 162      * content.
 163      */
 164     private int[] fContentStack = new int[5];
 165 
 166     /** Size of content stack. */
 167     private int fContentDepth;
 168 
 169     /** Parameter entity stack to check well-formedness. */
 170     private int[] fPEStack = new int[5];
 171 
 172 
 173     /** Parameter entity stack to report start/end entity calls. */
 174     private boolean[] fPEReport = new boolean[5];
 175 
 176     /** Number of opened parameter entities. */
 177     private int fPEDepth;
 178 
 179     /** Markup depth. */
 180     private int fMarkUpDepth;
 181 
 182     /** Number of opened external entities. */
 183     private int fExtEntityDepth;
 184 
 185     /** Number of opened include sections. */
 186     private int fIncludeSectDepth;
 187 
 188     // temporary variables
 189 
 190     /** Array of 3 strings. */
 191     private String[] fStrings = new String[3];
 192 
 193     /** String. */
 194     private XMLString fString = new XMLString();
 195 
 196     /** String buffer. */
 197     private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
 198 
 199     /** String buffer. */
 200     private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
 201 
 202     /** Literal text. */
 203     private XMLString fLiteral = new XMLString();
 204 
 205     /** Literal text. */
 206     private XMLString fLiteral2 = new XMLString();
 207 
 208     /** Enumeration values. */
 209     private String[] fEnumeration = new String[5];
 210 
 211     /** Enumeration values count. */
 212     private int fEnumerationCount;
 213 
 214     /** Ignore conditional section buffer. */
 215     private XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(128);
 216 
 217     /** Object contains grammar information for a non-validaing parser. */
 218     DTDGrammar nvGrammarInfo = null;
 219 
 220     boolean nonValidatingMode = false;
 221     //
 222     // Constructors
 223     //
 224 
 225     /** Default constructor. */
 226     public XMLDTDScannerImpl() {
 227     } // <init>()
 228 
 229     /** Constructor for he use of non-XMLComponentManagers. */
 230     public XMLDTDScannerImpl(SymbolTable symbolTable,
 231             XMLErrorReporter errorReporter, XMLEntityManager entityManager) {
 232         fSymbolTable = symbolTable;
 233         fErrorReporter = errorReporter;
 234         fEntityManager = entityManager;
 235         entityManager.setProperty(SYMBOL_TABLE, fSymbolTable);
 236     }
 237 
 238     //
 239     // XMLDTDScanner methods
 240     //
 241 
 242     /**
 243      * Sets the input source.
 244      *
 245      * @param inputSource The input source or null.
 246      *
 247      * @throws IOException Thrown on i/o error.
 248      */
 249     public void setInputSource(XMLInputSource inputSource) throws IOException {
 250         if (inputSource == null) {
 251             // no system id was available
 252             if (fDTDHandler != null) {
 253                 fDTDHandler.startDTD(null, null);
 254                 fDTDHandler.endDTD(null);
 255             }
 256             if (nonValidatingMode){
 257                 nvGrammarInfo.startDTD(null,null);
 258                 nvGrammarInfo.endDTD(null);
 259             }
 260             return;
 261         }
 262         fEntityManager.setEntityHandler(this);
 263         fEntityManager.startDTDEntity(inputSource);
 264     } // setInputSource(XMLInputSource)
 265 
 266 
 267     public void setLimitAnalyzer(XMLLimitAnalyzer limitAnalyzer) {
 268         fLimitAnalyzer = limitAnalyzer;
 269     }
 270 
 271     /**
 272      * Scans the external subset of the document.
 273      *
 274      * @param complete True if the scanner should scan the document
 275      *                 completely, pushing all events to the registered
 276      *                 document handler. A value of false indicates that
 277      *                 that the scanner should only scan the next portion
 278      *                 of the document and return. A scanner instance is
 279      *                 permitted to completely scan a document if it does
 280      *                 not support this "pull" scanning model.
 281      *
 282      * @return True if there is more to scan, false otherwise.
 283      */
 284     public boolean scanDTDExternalSubset(boolean complete)
 285     throws IOException, XNIException {
 286 
 287         fEntityManager.setEntityHandler(this);
 288         if (fScannerState == SCANNER_STATE_TEXT_DECL) {
 289             fSeenExternalDTD = true;
 290             boolean textDecl = scanTextDecl();
 291             if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
 292                 return false;
 293             }
 294             else {
 295                 // next state is markup decls regardless of whether there
 296                 // is a TextDecl or not
 297                 setScannerState(SCANNER_STATE_MARKUP_DECL);
 298                 if (textDecl && !complete) {
 299                     return true;
 300                 }
 301             }
 302         }
 303         // keep dispatching "events"
 304         do {
 305             if (!scanDecls(complete)) {
 306                 return false;
 307             }
 308         } while (complete);
 309 
 310         // return that there is more to scan
 311         return true;
 312 
 313     } // scanDTDExternalSubset(boolean):boolean
 314 
 315     /**
 316      * Scans the internal subset of the document.
 317      *
 318      * @param complete True if the scanner should scan the document
 319      *                 completely, pushing all events to the registered
 320      *                 document handler. A value of false indicates that
 321      *                 that the scanner should only scan the next portion
 322      *                 of the document and return. A scanner instance is
 323      *                 permitted to completely scan a document if it does
 324      *                 not support this "pull" scanning model.
 325      * @param standalone True if the document was specified as standalone.
 326      *                   This value is important for verifying certain
 327      *                   well-formedness constraints.
 328      * @param hasExternalDTD True if the document has an external DTD.
 329      *                       This allows the scanner to properly notify
 330      *                       the handler of the end of the DTD in the
 331      *                       absence of an external subset.
 332      *
 333      * @return True if there is more to scan, false otherwise.
 334      */
 335     public boolean scanDTDInternalSubset(boolean complete, boolean standalone,
 336     boolean hasExternalSubset)
 337     throws IOException, XNIException {
 338         // reset entity scanner
 339         //xxx:stax getText() is supposed to return only DTD internal subset
 340         //shouldn't we record position here before we go ahead ??
 341 
 342         fEntityScanner = (XMLEntityScanner)fEntityManager.getEntityScanner();
 343         fEntityManager.setEntityHandler(this);
 344         fStandalone = standalone;
 345         //System.out.println("state"+fScannerState);
 346         if (fScannerState == SCANNER_STATE_TEXT_DECL) {
 347             // call handler
 348             if (fDTDHandler != null) {
 349                 fDTDHandler.startDTD(fEntityScanner, null);
 350                 fStartDTDCalled = true;
 351             }
 352 
 353             if (nonValidatingMode){
 354                 fStartDTDCalled = true;
 355                 nvGrammarInfo.startDTD(fEntityScanner,null);
 356             }
 357             // set starting state for internal subset
 358             setScannerState(SCANNER_STATE_MARKUP_DECL);
 359         }
 360         // keep dispatching "events"
 361         do {
 362             if (!scanDecls(complete)) {
 363                 // call handler
 364                 if (fDTDHandler != null && hasExternalSubset == false) {
 365                     fDTDHandler.endDTD(null);
 366                 }
 367                 if (nonValidatingMode && hasExternalSubset == false ){
 368                     nvGrammarInfo.endDTD(null);
 369                 }
 370                 // we're done, set starting state for external subset
 371                 setScannerState(SCANNER_STATE_TEXT_DECL);
 372                 return false;
 373             }
 374         } while (complete);
 375 
 376         // return that there is more to scan
 377         return true;
 378 
 379     } // scanDTDInternalSubset(boolean,boolean,boolean):boolean
 380 
 381     //
 382     // XMLComponent methods
 383     //
 384 
 385     /**
 386      * reset
 387      *
 388      * @param componentManager
 389      */
 390     public void reset(XMLComponentManager componentManager)
 391     throws XMLConfigurationException {
 392 
 393         super.reset(componentManager);
 394         init();
 395 
 396     } // reset(XMLComponentManager)
 397 
 398     // this is made for something like XMLDTDLoader--XMLComponentManager-free operation...
 399     public void reset() {
 400         super.reset();
 401         init();
 402 
 403     }
 404 
 405     public void reset(PropertyManager props) {
 406         setPropertyManager(props);
 407         super.reset(props);
 408         init() ;
 409         nonValidatingMode = true;
 410         //Revisit : Create new grammar until we implement GrammarPool.
 411         nvGrammarInfo = new DTDGrammar(fSymbolTable);
 412     }
 413     /**
 414      * Returns a list of feature identifiers that are recognized by
 415      * this component. This method may return null if no features
 416      * are recognized by this component.
 417      */
 418     public String[] getRecognizedFeatures() {
 419         return (String[])(RECOGNIZED_FEATURES.clone());
 420     } // getRecognizedFeatures():String[]
 421 
 422     /**
 423      * Returns a list of property identifiers that are recognized by
 424      * this component. This method may return null if no properties
 425      * are recognized by this component.
 426      */
 427     public String[] getRecognizedProperties() {
 428         return (String[])(RECOGNIZED_PROPERTIES.clone());
 429     } // getRecognizedProperties():String[]
 430 
 431     /**
 432      * Returns the default state for a feature, or null if this
 433      * component does not want to report a default value for this
 434      * feature.
 435      *
 436      * @param featureId The feature identifier.
 437      *
 438      * @since Xerces 2.2.0
 439      */
 440     public Boolean getFeatureDefault(String featureId) {
 441         for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
 442             if (RECOGNIZED_FEATURES[i].equals(featureId)) {
 443                 return FEATURE_DEFAULTS[i];
 444             }
 445         }
 446         return null;
 447     } // getFeatureDefault(String):Boolean
 448 
 449     /**
 450      * Returns the default state for a property, or null if this
 451      * component does not want to report a default value for this
 452      * property.
 453      *
 454      * @param propertyId The property identifier.
 455      *
 456      * @since Xerces 2.2.0
 457      */
 458     public Object getPropertyDefault(String propertyId) {
 459         for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
 460             if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
 461                 return PROPERTY_DEFAULTS[i];
 462             }
 463         }
 464         return null;
 465     } // getPropertyDefault(String):Object
 466 
 467     //
 468     // XMLDTDSource methods
 469     //
 470 
 471     /**
 472      * setDTDHandler
 473      *
 474      * @param dtdHandler
 475      */
 476     public void setDTDHandler(XMLDTDHandler dtdHandler) {
 477         fDTDHandler = dtdHandler;
 478     } // setDTDHandler(XMLDTDHandler)
 479 
 480     /**
 481      * getDTDHandler
 482      *
 483      * @return the XMLDTDHandler
 484      */
 485     public XMLDTDHandler getDTDHandler() {
 486         return fDTDHandler;
 487     } // getDTDHandler():  XMLDTDHandler
 488 
 489     //
 490     // XMLDTDContentModelSource methods
 491     //
 492 
 493     /**
 494      * setDTDContentModelHandler
 495      *
 496      * @param dtdContentModelHandler
 497      */
 498     public void setDTDContentModelHandler(XMLDTDContentModelHandler
 499     dtdContentModelHandler) {
 500         fDTDContentModelHandler = dtdContentModelHandler;
 501     } // setDTDContentModelHandler
 502 
 503     /**
 504      * getDTDContentModelHandler
 505      *
 506      * @return XMLDTDContentModelHandler
 507      */
 508     public XMLDTDContentModelHandler getDTDContentModelHandler() {
 509         return fDTDContentModelHandler ;
 510     } // setDTDContentModelHandler
 511 
 512     //
 513     // XMLEntityHandler methods
 514     //
 515 
 516     /**
 517      * This method notifies of the start of an entity. The DTD has the
 518      * pseudo-name of "[dtd]" parameter entity names start with '%'; and
 519      * general entities are just specified by their name.
 520      *
 521      * @param name     The name of the entity.
 522      * @param identifier The resource identifier.
 523      * @param encoding The auto-detected IANA encoding name of the entity
 524      *                 stream. This value will be null in those situations
 525      *                 where the entity encoding is not auto-detected (e.g.
 526      *                 internal entities or a document entity that is
 527      *                 parsed from a java.io.Reader).
 528      * @param augs     Additional information that may include infoset augmentations
 529      *
 530      * @throws XNIException Thrown by handler to signal an error.
 531      */
 532     public void startEntity(String name,
 533                             XMLResourceIdentifier identifier,
 534                             String encoding, Augmentations augs) throws XNIException {
 535 
 536         super.startEntity(name, identifier, encoding, augs);
 537 
 538         boolean dtdEntity = name.equals("[dtd]");
 539         if (dtdEntity) {
 540             // call handler
 541             if (fDTDHandler != null && !fStartDTDCalled ) {
 542                 fDTDHandler.startDTD(fEntityScanner, null);
 543             }
 544             if (fDTDHandler != null) {
 545                 fDTDHandler.startExternalSubset(identifier,null);
 546             }
 547             fEntityManager.startExternalSubset();
 548             fEntityStore.startExternalSubset();
 549             fExtEntityDepth++;
 550         }
 551         else if (name.charAt(0) == '%') {
 552             pushPEStack(fMarkUpDepth, fReportEntity);
 553             if (fEntityScanner.isExternal()) {
 554                 fExtEntityDepth++;
 555             }
 556         }
 557 
 558         // call handler
 559         if (fDTDHandler != null && !dtdEntity && fReportEntity) {
 560             fDTDHandler.startParameterEntity(name, identifier, encoding, null);
 561         }
 562 
 563     } // startEntity(String,XMLResourceIdentifier,String)
 564 
 565     /**
 566      * This method notifies the end of an entity. The DTD has the pseudo-name
 567      * of "[dtd]" parameter entity names start with '%'; and general entities
 568      * are just specified by their name.
 569      *
 570      * @param name The name of the entity.
 571      *
 572      * @throws XNIException Thrown by handler to signal an error.
 573      */
 574     public void endEntity(String name, Augmentations augs)
 575     throws XNIException, IOException {
 576 
 577         super.endEntity(name, augs);
 578 
 579         // if there is no data after the doctype
 580         //
 581         if (fScannerState == SCANNER_STATE_END_OF_INPUT)
 582             return;
 583 
 584         // Handle end of PE
 585         boolean reportEntity = fReportEntity;
 586         if (name.startsWith("%")) {
 587             reportEntity = peekReportEntity();
 588             // check well-formedness of the entity
 589             int startMarkUpDepth = popPEStack();
 590             // throw fatalError if this entity was incomplete and
 591             // was a freestanding decl
 592             if(startMarkUpDepth == 0 &&
 593             startMarkUpDepth < fMarkUpDepth) {
 594                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 595                 "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL",
 596                 new Object[]{ fEntityManager.fCurrentEntity.name},
 597                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 598             }
 599             if (startMarkUpDepth != fMarkUpDepth) {
 600                 reportEntity = false;
 601                 if (fValidation) {
 602                     // Proper nesting of parameter entities is a Validity Constraint
 603                     // and must not be enforced when validation is off
 604                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 605                     "ImproperDeclarationNesting",
 606                     new Object[]{ name },
 607                     XMLErrorReporter.SEVERITY_ERROR);
 608                 }
 609             }
 610             if (fEntityScanner.isExternal()) {
 611                 fExtEntityDepth--;
 612             }
 613         }
 614 
 615         // call handler
 616         boolean dtdEntity = name.equals("[dtd]");
 617         if (fDTDHandler != null && !dtdEntity && reportEntity) {
 618             fDTDHandler.endParameterEntity(name, null);
 619         }
 620 
 621         // end DTD
 622         if (dtdEntity) {
 623             if (fIncludeSectDepth != 0) {
 624                 reportFatalError("IncludeSectUnterminated", null);
 625             }
 626             fScannerState = SCANNER_STATE_END_OF_INPUT;
 627             // call handler
 628             fEntityManager.endExternalSubset();
 629             fEntityStore.endExternalSubset();
 630 
 631             if (fDTDHandler != null) {
 632                 fDTDHandler.endExternalSubset(null);
 633                 fDTDHandler.endDTD(null);
 634             }
 635             fExtEntityDepth--;
 636         }
 637 
 638         //XML (Document Entity) is the last opened entity, however
 639         //if for some reason DTD Scanner receives this callback
 640         //there is something wrong (probably invalid XML), throw exception.
 641         //or
 642         //For standalone DTD loader, it might be the last opened entity
 643         //and if this is the last opened entity and fMarkUpDepth != 0 or
 644         //fIncludeSectDepth != 0 or fExtEntityDepth != 0 throw Exception
 645         if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.LAST_ENTITY))
 646             && ( fMarkUpDepth != 0 || fExtEntityDepth !=0 || fIncludeSectDepth != 0)){
 647             throw new EOFException();
 648         }
 649 
 650     } // endEntity(String)
 651 
 652     // helper methods
 653 
 654     /**
 655      * Sets the scanner state.
 656      *
 657      * @param state The new scanner state.
 658      */
 659     protected final void setScannerState(int state) {
 660 
 661         fScannerState = state;
 662         if (DEBUG_SCANNER_STATE) {
 663             System.out.print("### setScannerState: ");
 664             System.out.print(getScannerStateName(state));
 665             //System.out.println();
 666         }
 667 
 668     } // setScannerState(int)
 669 
 670     //
 671     // Private methods
 672     //
 673 
 674     /** Returns the scanner state name. */
 675     private static String getScannerStateName(int state) {
 676 
 677         if (DEBUG_SCANNER_STATE) {
 678             switch (state) {
 679                 case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT";
 680                 case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL";
 681                 case SCANNER_STATE_MARKUP_DECL: return "SCANNER_STATE_MARKUP_DECL";
 682             }
 683         }
 684 
 685         return "??? ("+state+')';
 686 
 687     } // getScannerStateName(int):String
 688 
 689     protected final boolean scanningInternalSubset() {
 690         return fExtEntityDepth == 0;
 691     }
 692 
 693     /**
 694      * start a parameter entity dealing with the textdecl if there is any
 695      *
 696      * @param name The name of the parameter entity to start (without the '%')
 697      * @param literal Whether this is happening within a literal
 698      */
 699     protected void startPE(String name, boolean literal)
 700     throws IOException, XNIException {
 701         int depth = fPEDepth;
 702         String pName = "%"+name;
 703         if (fValidation && !fEntityStore.isDeclaredEntity(pName)) {
 704             fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared",
 705             new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR);
 706         }
 707         fEntityManager.startEntity(fSymbolTable.addSymbol(pName),
 708         literal);
 709         // if we actually got a new entity and it's external
 710         // parse text decl if there is any
 711         if (depth != fPEDepth && fEntityScanner.isExternal()) {
 712             scanTextDecl();
 713         }
 714     }
 715 
 716     /**
 717      * Dispatch an XML "event".
 718      *
 719      * @param complete True if this method is intended to scan
 720      *                 and dispatch as much as possible.
 721      *
 722      * @return True if a TextDecl was scanned.
 723      *
 724      * @throws IOException  Thrown on i/o error.
 725      * @throws XNIException Thrown on parse error.
 726      *
 727      */
 728     protected final boolean scanTextDecl()
 729     throws IOException, XNIException {
 730 
 731         // scan XMLDecl
 732         boolean textDecl = false;
 733         if (fEntityScanner.skipString("<?xml")) {
 734             fMarkUpDepth++;
 735             // NOTE: special case where document starts with a PI
 736             //       whose name starts with "xml" (e.g. "xmlfoo")
 737             if (isValidNameChar(fEntityScanner.peekChar())) {
 738                 fStringBuffer.clear();
 739                 fStringBuffer.append("xml");
 740                 while (isValidNameChar(fEntityScanner.peekChar())) {
 741                     fStringBuffer.append((char)fEntityScanner.scanChar());
 742                 }
 743                 String target =
 744                 fSymbolTable.addSymbol(fStringBuffer.ch,
 745                 fStringBuffer.offset,
 746                 fStringBuffer.length);
 747                 scanPIData(target, fString);
 748             }
 749 
 750             // standard Text declaration
 751             else {
 752                 // pseudo-attribute values
 753                 String version = null;
 754                 String encoding = null;
 755 
 756                 scanXMLDeclOrTextDecl(true, fStrings);
 757                 textDecl = true;
 758                 fMarkUpDepth--;
 759 
 760                 version = fStrings[0];
 761                 encoding = fStrings[1];
 762 
 763                 fEntityScanner.setEncoding(encoding);
 764 
 765                 // call handler
 766                 if (fDTDHandler != null) {
 767                     fDTDHandler.textDecl(version, encoding, null);
 768                 }
 769             }
 770         }
 771         fEntityManager.fCurrentEntity.mayReadChunks = true;
 772 
 773         return textDecl;
 774 
 775     } // scanTextDecl(boolean):boolean
 776 
 777     /**
 778      * Scans a processing data. This is needed to handle the situation
 779      * where a document starts with a processing instruction whose
 780      * target name <em>starts with</em> "xml". (e.g. xmlfoo)
 781      *
 782      * @param target The PI target
 783      * @param data The string to fill in with the data
 784      */
 785     protected final void scanPIData(String target, XMLString data)
 786     throws IOException, XNIException {
 787         //Venu REVISIT
 788         //      super.scanPIData(target, data);
 789         fMarkUpDepth--;
 790 
 791         // call handler
 792         if (fDTDHandler != null) {
 793             fDTDHandler.processingInstruction(target, data, null);
 794         }
 795 
 796     } // scanPIData(String)
 797 
 798     /**
 799      * Scans a comment.
 800      * <p>
 801      * <pre>
 802      * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
 803      * </pre>
 804      * <p>
 805      * <strong>Note:</strong> Called after scanning past '&lt;!--'
 806      */
 807     protected final void scanComment() throws IOException, XNIException {
 808 
 809         fReportEntity = false;
 810         scanComment(fStringBuffer);
 811         fMarkUpDepth--;
 812 
 813         // call handler
 814         if (fDTDHandler != null) {
 815             fDTDHandler.comment(fStringBuffer, null);
 816         }
 817         fReportEntity = true;
 818 
 819     } // scanComment()
 820 
 821     /**
 822      * Scans an element declaration
 823      * <p>
 824      * <pre>
 825      * [45]    elementdecl    ::=    '&lt;!ELEMENT' S Name S contentspec S? '>'
 826      * [46]    contentspec    ::=    'EMPTY' | 'ANY' | Mixed | children
 827      * </pre>
 828      * <p>
 829      * <strong>Note:</strong> Called after scanning past '&lt;!ELEMENT'
 830      */
 831     protected final void scanElementDecl() throws IOException, XNIException {
 832 
 833         // spaces
 834         fReportEntity = false;
 835         if (!skipSeparator(true, !scanningInternalSubset())) {
 836             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL",
 837             null);
 838         }
 839 
 840         // element name
 841         String name = fEntityScanner.scanName();
 842         if (name == null) {
 843             reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL",
 844             null);
 845         }
 846 
 847         // spaces
 848         if (!skipSeparator(true, !scanningInternalSubset())) {
 849             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL",
 850             new Object[]{name});
 851         }
 852 
 853         // content model
 854         if (fDTDContentModelHandler != null) {
 855             fDTDContentModelHandler.startContentModel(name, null);
 856         }
 857         String contentModel = null;
 858         fReportEntity = true;
 859         if (fEntityScanner.skipString("EMPTY")) {
 860             contentModel = "EMPTY";
 861             // call handler
 862             if (fDTDContentModelHandler != null) {
 863                 fDTDContentModelHandler.empty(null);
 864             }
 865         }
 866         else if (fEntityScanner.skipString("ANY")) {
 867             contentModel = "ANY";
 868             // call handler
 869             if (fDTDContentModelHandler != null) {
 870                 fDTDContentModelHandler.any(null);
 871             }
 872         }
 873         else {
 874             if (!fEntityScanner.skipChar('(')) {
 875                 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
 876                 new Object[]{name});
 877             }
 878             if (fDTDContentModelHandler != null) {
 879                 fDTDContentModelHandler.startGroup(null);
 880             }
 881             fStringBuffer.clear();
 882             fStringBuffer.append('(');
 883             fMarkUpDepth++;
 884             skipSeparator(false, !scanningInternalSubset());
 885 
 886             // Mixed content model
 887             if (fEntityScanner.skipString("#PCDATA")) {
 888                 scanMixed(name);
 889             }
 890             else {              // children content
 891                 scanChildren(name);
 892             }
 893             contentModel = fStringBuffer.toString();
 894         }
 895 
 896         // call handler
 897         if (fDTDContentModelHandler != null) {
 898             fDTDContentModelHandler.endContentModel(null);
 899         }
 900 
 901         fReportEntity = false;
 902         skipSeparator(false, !scanningInternalSubset());
 903         // end
 904         if (!fEntityScanner.skipChar('>')) {
 905             reportFatalError("ElementDeclUnterminated", new Object[]{name});
 906         }
 907         fReportEntity = true;
 908         fMarkUpDepth--;
 909 
 910         // call handler
 911         if (fDTDHandler != null) {
 912             fDTDHandler.elementDecl(name, contentModel, null);
 913         }
 914         if (nonValidatingMode) nvGrammarInfo.elementDecl(name, contentModel, null);
 915     } // scanElementDecl()
 916 
 917     /**
 918      * scan Mixed content model
 919      * This assumes the content model has been parsed up to #PCDATA and
 920      * can simply append to fStringBuffer.
 921      * <pre>
 922      * [51]    Mixed    ::=    '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
 923      *                       | '(' S? '#PCDATA' S? ')'
 924      * </pre>
 925      *
 926      * @param elName The element type name this declaration is about.
 927      *
 928      * <strong>Note:</strong> Called after scanning past '(#PCDATA'.
 929      */
 930     private final void scanMixed(String elName)
 931     throws IOException, XNIException {
 932 
 933         String childName = null;
 934 
 935         fStringBuffer.append("#PCDATA");
 936         // call handler
 937         if (fDTDContentModelHandler != null) {
 938             fDTDContentModelHandler.pcdata(null);
 939         }
 940         skipSeparator(false, !scanningInternalSubset());
 941         while (fEntityScanner.skipChar('|')) {
 942             fStringBuffer.append('|');
 943             // call handler
 944             if (fDTDContentModelHandler != null) {
 945                 fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
 946                 null);
 947             }
 948             skipSeparator(false, !scanningInternalSubset());
 949 
 950             childName = fEntityScanner.scanName();
 951             if (childName == null) {
 952                 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT",
 953                 new Object[]{elName});
 954             }
 955             fStringBuffer.append(childName);
 956             // call handler
 957             if (fDTDContentModelHandler != null) {
 958                 fDTDContentModelHandler.element(childName, null);
 959             }
 960             skipSeparator(false, !scanningInternalSubset());
 961         }
 962         // The following check must be done in a single call (as opposed to one
 963         // for ')' and then one for '*') to guarantee that callbacks are
 964         // properly nested. We do not want to trigger endEntity too early in
 965         // case we cross the boundary of an entity between the two characters.
 966         if (fEntityScanner.skipString(")*")) {
 967             fStringBuffer.append(")*");
 968             // call handler
 969             if (fDTDContentModelHandler != null) {
 970                 fDTDContentModelHandler.endGroup(null);
 971                 fDTDContentModelHandler.occurrence(XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE,
 972                 null);
 973             }
 974         }
 975         else if (childName != null) {
 976             reportFatalError("MixedContentUnterminated",
 977             new Object[]{elName});
 978         }
 979         else if (fEntityScanner.skipChar(')')){
 980             fStringBuffer.append(')');
 981             // call handler
 982             if (fDTDContentModelHandler != null) {
 983                 fDTDContentModelHandler.endGroup(null);
 984             }
 985         }
 986         else {
 987             reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
 988             new Object[]{elName});
 989         }
 990         fMarkUpDepth--;
 991         // we are done
 992     }
 993 
 994     /**
 995      * scan children content model
 996      * This assumes it can simply append to fStringBuffer.
 997      * <pre>
 998      * [47]    children  ::=    (choice | seq) ('?' | '*' | '+')?
 999      * [48]    cp        ::=    (Name | choice | seq) ('?' | '*' | '+')?
1000      * [49]    choice    ::=    '(' S? cp ( S? '|' S? cp )+ S? ')'
1001      * [50]    seq       ::=    '(' S? cp ( S? ',' S? cp )* S? ')'
1002      * </pre>
1003      *
1004      * @param elName The element type name this declaration is about.
1005      *
1006      * <strong>Note:</strong> Called after scanning past the first open
1007      * paranthesis.
1008      */
1009     private final void scanChildren(String elName)
1010     throws IOException, XNIException {
1011 
1012         fContentDepth = 0;
1013         pushContentStack(0);
1014         int currentOp = 0;
1015         int c;
1016         while (true) {
1017             if (fEntityScanner.skipChar('(')) {
1018                 fMarkUpDepth++;
1019                 fStringBuffer.append('(');
1020                 // call handler
1021                 if (fDTDContentModelHandler != null) {
1022                     fDTDContentModelHandler.startGroup(null);
1023                 }
1024                 // push current op on stack and reset it
1025                 pushContentStack(currentOp);
1026                 currentOp = 0;
1027                 skipSeparator(false, !scanningInternalSubset());
1028                 continue;
1029             }
1030             skipSeparator(false, !scanningInternalSubset());
1031             String childName = fEntityScanner.scanName();
1032             if (childName == null) {
1033                 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
1034                 new Object[]{elName});
1035                 return;
1036             }
1037             // call handler
1038             if (fDTDContentModelHandler != null) {
1039                 fDTDContentModelHandler.element(childName, null);
1040             }
1041             fStringBuffer.append(childName);
1042             c = fEntityScanner.peekChar();
1043             if (c == '?' || c == '*' || c == '+') {
1044                 // call handler
1045                 if (fDTDContentModelHandler != null) {
1046                     short oc;
1047                     if (c == '?') {
1048                         oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1049                     }
1050                     else if (c == '*') {
1051                         oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1052                     }
1053                     else {
1054                         oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1055                     }
1056                     fDTDContentModelHandler.occurrence(oc, null);
1057                 }
1058                 fEntityScanner.scanChar();
1059                 fStringBuffer.append((char)c);
1060             }
1061             while (true) {
1062                 skipSeparator(false, !scanningInternalSubset());
1063                 c = fEntityScanner.peekChar();
1064                 if (c == ',' && currentOp != '|') {
1065                     currentOp = c;
1066                     // call handler
1067                     if (fDTDContentModelHandler != null) {
1068                         fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE,
1069                         null);
1070                     }
1071                     fEntityScanner.scanChar();
1072                     fStringBuffer.append(',');
1073                     break;
1074                 }
1075                 else if (c == '|' && currentOp != ',') {
1076                     currentOp = c;
1077                     // call handler
1078                     if (fDTDContentModelHandler != null) {
1079                         fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
1080                         null);
1081                     }
1082                     fEntityScanner.scanChar();
1083                     fStringBuffer.append('|');
1084                     break;
1085                 }
1086                 else if (c != ')') {
1087                     reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
1088                     new Object[]{elName});
1089                 }
1090                 // call handler
1091                 if (fDTDContentModelHandler != null) {
1092                     fDTDContentModelHandler.endGroup(null);
1093                 }
1094                 // restore previous op
1095                 currentOp = popContentStack();
1096                 short oc;
1097                 // The following checks must be done in a single call (as
1098                 // opposed to one for ')' and then one for '?', '*', and '+')
1099                 // to guarantee that callbacks are properly nested. We do not
1100                 // want to trigger endEntity too early in case we cross the
1101                 // boundary of an entity between the two characters.
1102                 if (fEntityScanner.skipString(")?")) {
1103                     fStringBuffer.append(")?");
1104                     // call handler
1105                     if (fDTDContentModelHandler != null) {
1106                         oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1107                         fDTDContentModelHandler.occurrence(oc, null);
1108                     }
1109                 }
1110                 else if (fEntityScanner.skipString(")+")) {
1111                     fStringBuffer.append(")+");
1112                     // call handler
1113                     if (fDTDContentModelHandler != null) {
1114                         oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1115                         fDTDContentModelHandler.occurrence(oc, null);
1116                     }
1117                 }
1118                 else if (fEntityScanner.skipString(")*")) {
1119                     fStringBuffer.append(")*");
1120                     // call handler
1121                     if (fDTDContentModelHandler != null) {
1122                         oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1123                         fDTDContentModelHandler.occurrence(oc, null);
1124                     }
1125                 }
1126                 else {
1127                     // no occurrence specified
1128                     fEntityScanner.scanChar();
1129                     fStringBuffer.append(')');
1130                 }
1131                 fMarkUpDepth--;
1132                 if (fContentDepth == 0) {
1133                     return;
1134                 }
1135             }
1136             skipSeparator(false, !scanningInternalSubset());
1137         }
1138     }
1139 
1140     /**
1141      * Scans an attlist declaration
1142      * <p>
1143      * <pre>
1144      * [52]  AttlistDecl    ::=   '&lt;!ATTLIST' S Name AttDef* S? '>'
1145      * [53]  AttDef         ::=   S Name S AttType S DefaultDecl
1146      * </pre>
1147      * <p>
1148      * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1149      */
1150     protected final void scanAttlistDecl() throws IOException, XNIException {
1151 
1152         // spaces
1153         fReportEntity = false;
1154         if (!skipSeparator(true, !scanningInternalSubset())) {
1155             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL",
1156             null);
1157         }
1158 
1159         // element name
1160         String elName = fEntityScanner.scanName();
1161         if (elName == null) {
1162             reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL",
1163             null);
1164         }
1165 
1166         // call handler
1167         if (fDTDHandler != null) {
1168             fDTDHandler.startAttlist(elName, null);
1169         }
1170 
1171         // spaces
1172         if (!skipSeparator(true, !scanningInternalSubset())) {
1173             // no space, is it the end yet?
1174             if (fEntityScanner.skipChar('>')) {
1175                 // yes, stop here
1176                 // call handler
1177                 if (fDTDHandler != null) {
1178                     fDTDHandler.endAttlist(null);
1179                 }
1180                 fMarkUpDepth--;
1181                 return;
1182             }
1183             else {
1184                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF",
1185                 new Object[]{elName});
1186             }
1187         }
1188 
1189         // definitions
1190         while (!fEntityScanner.skipChar('>')) {
1191             String name = fEntityScanner.scanName();
1192             if (name == null) {
1193                 reportFatalError("AttNameRequiredInAttDef",
1194                 new Object[]{elName});
1195             }
1196             // spaces
1197             if (!skipSeparator(true, !scanningInternalSubset())) {
1198                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF",
1199                 new Object[]{elName, name});
1200             }
1201             // type
1202             String type = scanAttType(elName, name);
1203 
1204             // spaces
1205             if (!skipSeparator(true, !scanningInternalSubset())) {
1206                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF",
1207                 new Object[]{elName, name});
1208             }
1209 
1210             // default decl
1211             String defaultType = scanAttDefaultDecl(elName, name,
1212             type,
1213             fLiteral, fLiteral2);
1214             // REVISIT: Should we do anything with the non-normalized
1215             //          default attribute value? -Ac
1216             // yes--according to bug 5073.  - neilg
1217             String[] enumr = null;
1218             if( fDTDHandler != null || nonValidatingMode){
1219                 if (fEnumerationCount != 0) {
1220                     enumr = new String[fEnumerationCount];
1221                     System.arraycopy(fEnumeration, 0, enumr,
1222                     0, fEnumerationCount);
1223                 }
1224             }
1225             // call handler
1226             // Determine whether the default value to be passed should be null.
1227             // REVISIT: should probably check whether fLiteral.ch is null instead. LM.
1228             if (defaultType!=null && (defaultType.equals("#REQUIRED") ||
1229             defaultType.equals("#IMPLIED"))) {
1230                 if (fDTDHandler != null){
1231                     fDTDHandler.attributeDecl(elName, name, type, enumr,
1232                     defaultType, null, null, null);
1233                 }
1234                 if(nonValidatingMode){
1235                     nvGrammarInfo.attributeDecl(elName, name, type, enumr,
1236                     defaultType, null, null, null);
1237 
1238                 }
1239             }
1240             else {
1241                 if (fDTDHandler != null){
1242                     fDTDHandler.attributeDecl(elName, name, type, enumr,
1243                     defaultType, fLiteral, fLiteral2, null);
1244                 }
1245                 if(nonValidatingMode){
1246                     nvGrammarInfo.attributeDecl(elName, name, type, enumr,
1247                     defaultType, fLiteral, fLiteral2, null);
1248                 }
1249             }
1250             skipSeparator(false, !scanningInternalSubset());
1251         }
1252 
1253         // call handler
1254         if (fDTDHandler != null) {
1255             fDTDHandler.endAttlist(null);
1256         }
1257         fMarkUpDepth--;
1258         fReportEntity = true;
1259 
1260     } // scanAttlistDecl()
1261 
1262     /**
1263      * Scans an attribute type definition
1264      * <p>
1265      * <pre>
1266      * [54]  AttType        ::=   StringType | TokenizedType | EnumeratedType
1267      * [55]  StringType     ::=   'CDATA'
1268      * [56]  TokenizedType  ::=   'ID'
1269      *                          | 'IDREF'
1270      *                          | 'IDREFS'
1271      *                          | 'ENTITY'
1272      *                          | 'ENTITIES'
1273      *                          | 'NMTOKEN'
1274      *                          | 'NMTOKENS'
1275      * [57]  EnumeratedType ::=    NotationType | Enumeration
1276      * [58]  NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
1277      * [59]  Enumeration    ::=    '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
1278      * </pre>
1279      * <p>
1280      * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1281      *
1282      * @param elName The element type name this declaration is about.
1283      * @param atName The attribute name this declaration is about.
1284      */
1285     private final String scanAttType(String elName, String atName)
1286     throws IOException, XNIException {
1287 
1288         String type = null;
1289         fEnumerationCount = 0;
1290         /*
1291          * Watchout: the order here is important: when a string happens to
1292          * be a substring of another string, the longer one needs to be
1293          * looked for first!!
1294          */
1295         if (fEntityScanner.skipString("CDATA")) {
1296             type = "CDATA";
1297         }
1298         else if (fEntityScanner.skipString("IDREFS")) {
1299             type = "IDREFS";
1300         }
1301         else if (fEntityScanner.skipString("IDREF")) {
1302             type = "IDREF";
1303         }
1304         else if (fEntityScanner.skipString("ID")) {
1305             type = "ID";
1306         }
1307         else if (fEntityScanner.skipString("ENTITY")) {
1308             type = "ENTITY";
1309         }
1310         else if (fEntityScanner.skipString("ENTITIES")) {
1311             type = "ENTITIES";
1312         }
1313         else if (fEntityScanner.skipString("NMTOKENS")) {
1314             type = "NMTOKENS";
1315         }
1316         else if (fEntityScanner.skipString("NMTOKEN")) {
1317             type = "NMTOKEN";
1318         }
1319         else if (fEntityScanner.skipString("NOTATION")) {
1320             type = "NOTATION";
1321             // spaces
1322             if (!skipSeparator(true, !scanningInternalSubset())) {
1323                 reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE",
1324                 new Object[]{elName, atName});
1325             }
1326             // open paren
1327             int c = fEntityScanner.scanChar();
1328             if (c != '(') {
1329                 reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE",
1330                 new Object[]{elName, atName});
1331             }
1332             fMarkUpDepth++;
1333             do {
1334                 skipSeparator(false, !scanningInternalSubset());
1335                 String aName = fEntityScanner.scanName();
1336                 if (aName == null) {
1337                     reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE",
1338                     new Object[]{elName, atName});
1339                 }
1340                 ensureEnumerationSize(fEnumerationCount + 1);
1341                 fEnumeration[fEnumerationCount++] = aName;
1342                 skipSeparator(false, !scanningInternalSubset());
1343                 c = fEntityScanner.scanChar();
1344             } while (c == '|');
1345             if (c != ')') {
1346                 reportFatalError("NotationTypeUnterminated",
1347                 new Object[]{elName, atName});
1348             }
1349             fMarkUpDepth--;
1350         }
1351         else {              // Enumeration
1352             type = "ENUMERATION";
1353             // open paren
1354             int c = fEntityScanner.scanChar();
1355             if (c != '(') {
1356                 //                       "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL",
1357                 reportFatalError("AttTypeRequiredInAttDef",
1358                 new Object[]{elName, atName});
1359             }
1360             fMarkUpDepth++;
1361             do {
1362                 skipSeparator(false, !scanningInternalSubset());
1363                 String token = fEntityScanner.scanNmtoken();
1364                 if (token == null) {
1365                     reportFatalError("MSG_NMTOKEN_REQUIRED_IN_ENUMERATION",
1366                     new Object[]{elName, atName});
1367                 }
1368                 ensureEnumerationSize(fEnumerationCount + 1);
1369                 fEnumeration[fEnumerationCount++] = token;
1370                 skipSeparator(false, !scanningInternalSubset());
1371                 c = fEntityScanner.scanChar();
1372             } while (c == '|');
1373             if (c != ')') {
1374                 reportFatalError("EnumerationUnterminated",
1375                 new Object[]{elName, atName});
1376             }
1377             fMarkUpDepth--;
1378         }
1379         return type;
1380 
1381     } // scanAttType():String
1382 
1383 
1384     /**
1385      * Scans an attribute default declaration
1386      * <p>
1387      * <pre>
1388      * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
1389      * </pre>
1390      *
1391      * @param name The name of the attribute being scanned.
1392      * @param defaultVal The string to fill in with the default value.
1393      */
1394     protected final String scanAttDefaultDecl(String elName, String atName,
1395     String type,
1396     XMLString defaultVal,
1397     XMLString nonNormalizedDefaultVal)
1398     throws IOException, XNIException {
1399 
1400         String defaultType = null;
1401         fString.clear();
1402         defaultVal.clear();
1403         if (fEntityScanner.skipString("#REQUIRED")) {
1404             defaultType = "#REQUIRED";
1405         }
1406         else if (fEntityScanner.skipString("#IMPLIED")) {
1407             defaultType = "#IMPLIED";
1408         }
1409         else {
1410             if (fEntityScanner.skipString("#FIXED")) {
1411                 defaultType = "#FIXED";
1412                 // spaces
1413                 if (!skipSeparator(true, !scanningInternalSubset())) {
1414                     reportFatalError("MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL",
1415                     new Object[]{elName, atName});
1416                 }
1417             }
1418             // AttValue
1419             boolean isVC = !fStandalone  &&  (fSeenExternalDTD || fSeenExternalPE) ;
1420             scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName,
1421             fAttributes, 0, isVC);
1422         }
1423         return defaultType;
1424 
1425     } // ScanAttDefaultDecl
1426 
1427     /**
1428      * Scans an entity declaration
1429      * <p>
1430      * <pre>
1431      * [70]    EntityDecl  ::=    GEDecl | PEDecl
1432      * [71]    GEDecl      ::=    '&lt;!ENTITY' S Name S EntityDef S? '>'
1433      * [72]    PEDecl      ::=    '&lt;!ENTITY' S '%' S Name S PEDef S? '>'
1434      * [73]    EntityDef   ::=    EntityValue | (ExternalID NDataDecl?)
1435      * [74]    PEDef       ::=    EntityValue | ExternalID
1436      * [75]    ExternalID  ::=    'SYSTEM' S SystemLiteral
1437      *                          | 'PUBLIC' S PubidLiteral S SystemLiteral
1438      * [76]    NDataDecl   ::=    S 'NDATA' S Name
1439      * </pre>
1440      * <p>
1441      * <strong>Note:</strong> Called after scanning past '&lt;!ENTITY'
1442      */
1443     private final void scanEntityDecl() throws IOException, XNIException {
1444 
1445         boolean isPEDecl = false;
1446         boolean sawPERef = false;
1447         fReportEntity = false;
1448         if (fEntityScanner.skipSpaces()) {
1449             if (!fEntityScanner.skipChar('%')) {
1450                 isPEDecl = false; // <!ENTITY x "x">
1451             }
1452             else if (skipSeparator(true, !scanningInternalSubset())) {
1453                 // <!ENTITY % x "x">
1454                 isPEDecl = true;
1455             }
1456             else if (scanningInternalSubset()) {
1457                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1458                 null);
1459                 isPEDecl = true;
1460             }
1461             else if (fEntityScanner.peekChar() == '%') {
1462                 // <!ENTITY %%x; "x"> is legal
1463                 skipSeparator(false, !scanningInternalSubset());
1464                 isPEDecl = true;
1465             }
1466             else {
1467                 sawPERef = true;
1468             }
1469         }
1470         else if (scanningInternalSubset() || !fEntityScanner.skipChar('%')) {
1471             // <!ENTITY[^ ]...> or <!ENTITY[^ %]...>
1472             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1473             null);
1474             isPEDecl = false;
1475         }
1476         else if (fEntityScanner.skipSpaces()) {
1477             // <!ENTITY% ...>
1478             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL",
1479             null);
1480             isPEDecl = false;
1481         }
1482         else {
1483             sawPERef = true;
1484         }
1485         if (sawPERef) {
1486             while (true) {
1487                 String peName = fEntityScanner.scanName();
1488                 if (peName == null) {
1489                     reportFatalError("NameRequiredInPEReference", null);
1490                 }
1491                 else if (!fEntityScanner.skipChar(';')) {
1492                     reportFatalError("SemicolonRequiredInPEReference",
1493                     new Object[]{peName});
1494                 }
1495                 else {
1496                     startPE(peName, false);
1497                 }
1498                 fEntityScanner.skipSpaces();
1499                 if (!fEntityScanner.skipChar('%'))
1500                     break;
1501                 if (!isPEDecl) {
1502                     if (skipSeparator(true, !scanningInternalSubset())) {
1503                         isPEDecl = true;
1504                         break;
1505                     }
1506                     isPEDecl = fEntityScanner.skipChar('%');
1507                 }
1508             }
1509         }
1510 
1511         // name
1512         String name = fEntityScanner.scanName();
1513         if (name == null) {
1514             reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null);
1515         }
1516 
1517         // spaces
1518         if (!skipSeparator(true, !scanningInternalSubset())) {
1519             reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL",
1520             new Object[]{name});
1521         }
1522 
1523         // external id
1524         scanExternalID(fStrings, false);
1525         String systemId = fStrings[0];
1526         String publicId = fStrings[1];
1527 
1528         if (isPEDecl && systemId != null) {
1529             fSeenExternalPE = true;
1530         }
1531 
1532         String notation = null;
1533         // NDATA
1534         boolean sawSpace = skipSeparator(true, !scanningInternalSubset());
1535         if (!isPEDecl && fEntityScanner.skipString("NDATA")) {
1536             // check whether there was space before NDATA
1537             if (!sawSpace) {
1538                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL",
1539                 new Object[]{name});
1540             }
1541 
1542             // spaces
1543             if (!skipSeparator(true, !scanningInternalSubset())) {
1544                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL",
1545                 new Object[]{name});
1546             }
1547             notation = fEntityScanner.scanName();
1548             if (notation == null) {
1549                 reportFatalError("MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL",
1550                 new Object[]{name});
1551             }
1552         }
1553 
1554         // internal entity
1555         if (systemId == null) {
1556             scanEntityValue(name, isPEDecl, fLiteral, fLiteral2);
1557             // since we need it's value anyway, let's snag it so it doesn't get corrupted
1558             // if a new load takes place before we store the entity values
1559             fStringBuffer.clear();
1560             fStringBuffer2.clear();
1561             fStringBuffer.append(fLiteral.ch, fLiteral.offset, fLiteral.length);
1562             fStringBuffer2.append(fLiteral2.ch, fLiteral2.offset, fLiteral2.length);
1563         }
1564 
1565         // skip possible trailing space
1566         skipSeparator(false, !scanningInternalSubset());
1567 
1568         // end
1569         if (!fEntityScanner.skipChar('>')) {
1570             reportFatalError("EntityDeclUnterminated", new Object[]{name});
1571         }
1572         fMarkUpDepth--;
1573 
1574         // register entity and make callback
1575         if (isPEDecl) {
1576             name = "%" + name;
1577         }
1578         if (systemId != null) {
1579             String baseSystemId = fEntityScanner.getBaseSystemId();
1580             if (notation != null) {
1581                 fEntityStore.addUnparsedEntity(name, publicId, systemId, baseSystemId, notation);
1582             }
1583             else {
1584                 fEntityStore.addExternalEntity(name, publicId, systemId,
1585                 baseSystemId);
1586             }
1587             if (fDTDHandler != null) {
1588                 //Venu Revisit : why false has been removed in expandSYstem
1589                 fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId ));
1590 
1591                 if (notation != null) {
1592                     fDTDHandler.unparsedEntityDecl(name, fResourceIdentifier,
1593                     notation, null);
1594                 }
1595                 else {
1596                     fDTDHandler.externalEntityDecl(name, fResourceIdentifier, null);
1597                 }
1598             }
1599         }
1600         else {
1601             fEntityStore.addInternalEntity(name, fStringBuffer.toString());
1602             if (fDTDHandler != null) {
1603                 fDTDHandler.internalEntityDecl(name, fStringBuffer, fStringBuffer2, null);
1604             }
1605         }
1606         fReportEntity = true;
1607 
1608     } // scanEntityDecl()
1609 
1610     /**
1611      * Scans an entity value.
1612      *
1613      * @param value The string to fill in with the value.
1614      * @param nonNormalizedValue The string to fill in with the
1615      *                           non-normalized value.
1616      *
1617      * <strong>Note:</strong> This method uses fString, fStringBuffer (through
1618      * the use of scanCharReferenceValue), and fStringBuffer2, anything in them
1619      * at the time of calling is lost.
1620      */
1621     protected final void scanEntityValue(String entityName, boolean isPEDecl, XMLString value,
1622     XMLString nonNormalizedValue)
1623     throws IOException, XNIException {
1624         int quote = fEntityScanner.scanChar();
1625         if (quote != '\'' && quote != '"') {
1626             reportFatalError("OpenQuoteMissingInDecl", null);
1627         }
1628         // store at which depth of entities we start
1629         int entityDepth = fEntityDepth;
1630 
1631         XMLString literal = fString;
1632         XMLString literal2 = fString;
1633         int countChar = 0;
1634         if (fLimitAnalyzer == null ) {
1635             fLimitAnalyzer = new XMLLimitAnalyzer();
1636          }
1637         fLimitAnalyzer.startEntity(entityName);
1638 
1639         if (fEntityScanner.scanLiteral(quote, fString) != quote) {
1640             fStringBuffer.clear();
1641             fStringBuffer2.clear();
1642             do {
1643                 if (isPEDecl && fLimitAnalyzer != null) {
1644                     checkLimit("%" + entityName, fString.length + countChar);
1645                 }
1646                 countChar = 0;
1647                 fStringBuffer.append(fString);
1648                 fStringBuffer2.append(fString);
1649                 if (fEntityScanner.skipChar('&')) {
1650                     if (fEntityScanner.skipChar('#')) {
1651                         fStringBuffer2.append("&#");
1652                         scanCharReferenceValue(fStringBuffer, fStringBuffer2);
1653                     }
1654                     else {
1655                         fStringBuffer.append('&');
1656                         fStringBuffer2.append('&');
1657                         String eName = fEntityScanner.scanName();
1658                         if (eName == null) {
1659                             reportFatalError("NameRequiredInReference",
1660                             null);
1661                         }
1662                         else {
1663                             fStringBuffer.append(eName);
1664                             fStringBuffer2.append(eName);
1665                         }
1666                         if (!fEntityScanner.skipChar(';')) {
1667                             reportFatalError("SemicolonRequiredInReference",
1668                             new Object[]{eName});
1669                         }
1670                         else {
1671                             fStringBuffer.append(';');
1672                             fStringBuffer2.append(';');
1673                         }
1674                     }
1675                 }
1676                 else if (fEntityScanner.skipChar('%')) {
1677                     while (true) {
1678                         fStringBuffer2.append('%');
1679                         String peName = fEntityScanner.scanName();
1680                         if (peName == null) {
1681                             reportFatalError("NameRequiredInPEReference",
1682                             null);
1683                         }
1684                         else if (!fEntityScanner.skipChar(';')) {
1685                             reportFatalError("SemicolonRequiredInPEReference",
1686                             new Object[]{peName});
1687                         }
1688                         else {
1689                             if (scanningInternalSubset()) {
1690                                 reportFatalError("PEReferenceWithinMarkup",
1691                                 new Object[]{peName});
1692                             }
1693                             fStringBuffer2.append(peName);
1694                             fStringBuffer2.append(';');
1695                         }
1696                         startPE(peName, true);
1697                         // REVISIT: [Q] Why do we skip spaces here? -Ac
1698                         // REVISIT: This will make returning the non-
1699                         //          normalized value harder. -Ac
1700                         fEntityScanner.skipSpaces();
1701                         if (!fEntityScanner.skipChar('%'))
1702                             break;
1703                     }
1704                 }
1705                 else {
1706                     countChar++;
1707                     int c = fEntityScanner.peekChar();
1708                     if (XMLChar.isHighSurrogate(c)) {
1709                         scanSurrogates(fStringBuffer2);
1710                     }
1711                     else if (isInvalidLiteral(c)) {
1712                         reportFatalError("InvalidCharInLiteral",
1713                         new Object[]{Integer.toHexString(c)});
1714                         fEntityScanner.scanChar();
1715                     }
1716                     // if it's not the delimiting quote or if it is but from a
1717                     // different entity than the one this literal started from,
1718                     // simply append the character to our buffer
1719                     else if (c != quote || entityDepth != fEntityDepth) {
1720                         fStringBuffer.append((char)c);
1721                         fStringBuffer2.append((char)c);
1722                         fEntityScanner.scanChar();
1723                     }
1724                 }
1725             } while (fEntityScanner.scanLiteral(quote, fString) != quote);
1726             fStringBuffer.append(fString);
1727             fStringBuffer2.append(fString);
1728             literal = fStringBuffer;
1729             literal2 = fStringBuffer2;
1730         } else {
1731             if (isPEDecl) {
1732                 checkLimit("%" + entityName, literal);
1733         }
1734         }
1735         value.setValues(literal);
1736         nonNormalizedValue.setValues(literal2);
1737         if (fLimitAnalyzer != null) {
1738             fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName);
1739         }
1740 
1741         if (!fEntityScanner.skipChar(quote)) {
1742             reportFatalError("CloseQuoteMissingInDecl", null);
1743         }
1744     } // scanEntityValue(XMLString,XMLString):void
1745 
1746     /**
1747      * Scans a notation declaration
1748      * <p>
1749      * <pre>
1750      * [82] NotationDecl ::= '&lt;!NOTATION' S Name S (ExternalID|PublicID) S? '>'
1751      * [83]  PublicID    ::= 'PUBLIC' S PubidLiteral
1752      * </pre>
1753      * <p>
1754      * <strong>Note:</strong> Called after scanning past '&lt;!NOTATION'
1755      */
1756     private final void scanNotationDecl() throws IOException, XNIException {
1757 
1758         // spaces
1759         fReportEntity = false;
1760         if (!skipSeparator(true, !scanningInternalSubset())) {
1761             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL",
1762             null);
1763         }
1764 
1765         // notation name
1766         String name = fEntityScanner.scanName();
1767         if (name == null) {
1768             reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL",
1769             null);
1770         }
1771 
1772         // spaces
1773         if (!skipSeparator(true, !scanningInternalSubset())) {
1774             reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL",
1775             new Object[]{name});
1776         }
1777 
1778         // external id
1779         scanExternalID(fStrings, true);
1780         String systemId = fStrings[0];
1781         String publicId = fStrings[1];
1782         String baseSystemId = fEntityScanner.getBaseSystemId();
1783 
1784         if (systemId == null && publicId == null) {
1785             reportFatalError("ExternalIDorPublicIDRequired",
1786             new Object[]{name});
1787         }
1788 
1789         // skip possible trailing space
1790         skipSeparator(false, !scanningInternalSubset());
1791 
1792         // end
1793         if (!fEntityScanner.skipChar('>')) {
1794             reportFatalError("NotationDeclUnterminated", new Object[]{name});
1795         }
1796         fMarkUpDepth--;
1797 
1798         fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId ));
1799         if (nonValidatingMode) nvGrammarInfo.notationDecl(name, fResourceIdentifier, null);
1800         // call handler
1801         if (fDTDHandler != null) {
1802             //Venu Revisit wby false has been removed.
1803             //fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false));
1804             fDTDHandler.notationDecl(name, fResourceIdentifier, null);
1805         }
1806         fReportEntity = true;
1807 
1808     } // scanNotationDecl()
1809 
1810     /**
1811      * Scans a conditional section. If it's a section to ignore the whole
1812      * section gets scanned through and this method only returns after the
1813      * closing bracket has been found. When it's an include section though, it
1814      * returns to let the main loop take care of scanning it. In that case the
1815      * end of the section if handled by the main loop (scanDecls).
1816      * <p>
1817      * <pre>
1818      * [61] conditionalSect   ::= includeSect | ignoreSect
1819      * [62] includeSect       ::= '&lt;![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
1820      * [63] ignoreSect   ::= '&lt;![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
1821      * [64] ignoreSectContents ::= Ignore ('&lt;![' ignoreSectContents ']]>' Ignore)*
1822      * [65] Ignore            ::=    Char* - (Char* ('&lt;![' | ']]>') Char*)
1823      * </pre>
1824      * <p>
1825      * <strong>Note:</strong> Called after scanning past '&lt;![' */
1826     private final void scanConditionalSect(int currPEDepth)
1827     throws IOException, XNIException {
1828 
1829         fReportEntity = false;
1830         skipSeparator(false, !scanningInternalSubset());
1831 
1832         if (fEntityScanner.skipString("INCLUDE")) {
1833             skipSeparator(false, !scanningInternalSubset());
1834             if(currPEDepth != fPEDepth && fValidation) {
1835                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1836                 "INVALID_PE_IN_CONDITIONAL",
1837                 new Object[]{ fEntityManager.fCurrentEntity.name},
1838                 XMLErrorReporter.SEVERITY_ERROR);
1839             }
1840             // call handler
1841             if (!fEntityScanner.skipChar('[')) {
1842                 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1843             }
1844 
1845             if (fDTDHandler != null) {
1846                 fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_INCLUDE,
1847                 null);
1848             }
1849             fIncludeSectDepth++;
1850             // just stop there and go back to the main loop
1851             fReportEntity = true;
1852         }
1853         else if (fEntityScanner.skipString("IGNORE")) {
1854             skipSeparator(false, !scanningInternalSubset());
1855             if(currPEDepth != fPEDepth && fValidation) {
1856                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1857                 "INVALID_PE_IN_CONDITIONAL",
1858                 new Object[]{ fEntityManager.fCurrentEntity.name},
1859                 XMLErrorReporter.SEVERITY_ERROR);
1860             }
1861             // call handler
1862             if (fDTDHandler != null) {
1863                 fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE,
1864                 null);
1865             }
1866             if (!fEntityScanner.skipChar('[')) {
1867                 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1868             }
1869             fReportEntity = true;
1870             int initialDepth = ++fIncludeSectDepth;
1871             if (fDTDHandler != null) {
1872                 fIgnoreConditionalBuffer.clear();
1873             }
1874             while (true) {
1875                 if (fEntityScanner.skipChar('<')) {
1876                     if (fDTDHandler != null) {
1877                         fIgnoreConditionalBuffer.append('<');
1878                     }
1879                     //
1880                     // These tests are split so that we handle cases like
1881                     // '<<![' and '<!<![' which we might otherwise miss.
1882                     //
1883                     if (fEntityScanner.skipChar('!')) {
1884                         if(fEntityScanner.skipChar('[')) {
1885                             if (fDTDHandler != null) {
1886                                 fIgnoreConditionalBuffer.append("![");
1887                             }
1888                             fIncludeSectDepth++;
1889                         } else {
1890                             if (fDTDHandler != null) {
1891                                 fIgnoreConditionalBuffer.append("!");
1892                             }
1893                         }
1894                     }
1895                 }
1896                 else if (fEntityScanner.skipChar(']')) {
1897                     if (fDTDHandler != null) {
1898                         fIgnoreConditionalBuffer.append(']');
1899                     }
1900                     //
1901                     // The same thing goes for ']<![' and '<]]>', etc.
1902                     //
1903                     if (fEntityScanner.skipChar(']')) {
1904                         if (fDTDHandler != null) {
1905                             fIgnoreConditionalBuffer.append(']');
1906                         }
1907                         while (fEntityScanner.skipChar(']')) {
1908                             /* empty loop body */
1909                             if (fDTDHandler != null) {
1910                                 fIgnoreConditionalBuffer.append(']');
1911                             }
1912                         }
1913                         if (fEntityScanner.skipChar('>')) {
1914                             if (fIncludeSectDepth-- == initialDepth) {
1915                                 fMarkUpDepth--;
1916                                 // call handler
1917                                 if (fDTDHandler != null) {
1918                                     fLiteral.setValues(fIgnoreConditionalBuffer.ch, 0,
1919                                     fIgnoreConditionalBuffer.length - 2);
1920                                     fDTDHandler.ignoredCharacters(fLiteral, null);
1921                                     fDTDHandler.endConditional(null);
1922                                 }
1923                                 return;
1924                             } else if(fDTDHandler != null) {
1925                                 fIgnoreConditionalBuffer.append('>');
1926                             }
1927                         }
1928                     }
1929                 }
1930                 else {
1931                     int c = fEntityScanner.scanChar();
1932                     if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
1933                         reportFatalError("IgnoreSectUnterminated", null);
1934                         return;
1935                     }
1936                     if (fDTDHandler != null) {
1937                         fIgnoreConditionalBuffer.append((char)c);
1938                     }
1939                 }
1940             }
1941         }
1942         else {
1943             reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1944         }
1945 
1946     } // scanConditionalSect()
1947 
1948     /**
1949      * Dispatch an XML "event".
1950      *
1951      * @param complete True if this method is intended to scan
1952      *                 and dispatch as much as possible.
1953      *
1954      * @return True if there is more to scan.
1955      *
1956      * @throws IOException  Thrown on i/o error.
1957      * @throws XNIException Thrown on parse error.
1958      *
1959      */
1960     protected final boolean scanDecls(boolean complete)
1961     throws IOException, XNIException {
1962 
1963         skipSeparator(false, true);
1964         boolean again = true;
1965         //System.out.println("scanDecls"+fScannerState);
1966         while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) {
1967             again = complete;
1968             if (fEntityScanner.skipChar('<')) {
1969                 fMarkUpDepth++;
1970                 if (fEntityScanner.skipChar('?')) {
1971                     fStringBuffer.clear();
1972                     scanPI(fStringBuffer);
1973                     fMarkUpDepth--; // we're done with this decl
1974                 }
1975                 else if (fEntityScanner.skipChar('!')) {
1976                     if (fEntityScanner.skipChar('-')) {
1977                         if (!fEntityScanner.skipChar('-')) {
1978                             reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1979                             null);
1980                         } else {
1981                             scanComment();
1982                         }
1983                     }
1984                     else if (fEntityScanner.skipString("ELEMENT")) {
1985                         scanElementDecl();
1986                     }
1987                     else if (fEntityScanner.skipString("ATTLIST")) {
1988                         scanAttlistDecl();
1989                     }
1990                     else if (fEntityScanner.skipString("ENTITY")) {
1991                         scanEntityDecl();
1992                     }
1993                     else if (fEntityScanner.skipString("NOTATION")) {
1994                         scanNotationDecl();
1995                     }
1996                     else if (fEntityScanner.skipChar('[') &&
1997                     !scanningInternalSubset()) {
1998                         scanConditionalSect(fPEDepth);
1999                     }
2000                     else {
2001                         fMarkUpDepth--;
2002                         reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
2003                         null);
2004                     }
2005                 }
2006                 else {
2007                     fMarkUpDepth--;
2008                     reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
2009                 }
2010             }
2011             else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']')) {
2012                 // end of conditional section?
2013                 if (!fEntityScanner.skipChar(']')
2014                 || !fEntityScanner.skipChar('>')) {
2015                     reportFatalError("IncludeSectUnterminated", null);
2016                 }
2017                 // call handler
2018                 if (fDTDHandler != null) {
2019                     fDTDHandler.endConditional(null);
2020                 }
2021                 // decreaseMarkupDepth();
2022                 fIncludeSectDepth--;
2023                 fMarkUpDepth--;
2024             }
2025             else if (scanningInternalSubset() &&
2026             fEntityScanner.peekChar() == ']') {
2027                 // this is the end of the internal subset, let's stop here
2028                 return false;
2029             }
2030             else if (fEntityScanner.skipSpaces()) {
2031                 // simply skip
2032             }
2033             else {
2034                 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
2035             }
2036             skipSeparator(false, true);
2037         }
2038         return fScannerState != SCANNER_STATE_END_OF_INPUT;
2039     }
2040 
2041     /**
2042      * Skip separator. This is typically just whitespace but it can also be one
2043      * or more parameter entity references.
2044      * <p>
2045      * If there are some it "expands them" by calling the corresponding entity
2046      * from the entity manager.
2047      * <p>
2048      * This is recursive and will process has many refs as possible.
2049      *
2050      * @param spaceRequired Specify whether some leading whitespace should be
2051      *                      found
2052      * @param lookForPERefs Specify whether parameter entity references should
2053      *                      be looked for
2054      * @return True if any leading whitespace was found or the end of a
2055      *         parameter entity was crossed.
2056      */
2057     private boolean skipSeparator(boolean spaceRequired, boolean lookForPERefs)
2058     throws IOException, XNIException {
2059         int depth = fPEDepth;
2060         boolean sawSpace = fEntityScanner.skipSpaces();
2061         if (!lookForPERefs || !fEntityScanner.skipChar('%')) {
2062             return !spaceRequired || sawSpace || (depth != fPEDepth);
2063         }
2064         while (true) {
2065             String name = fEntityScanner.scanName();
2066             if (name == null) {
2067                 reportFatalError("NameRequiredInPEReference", null);
2068             }
2069             else if (!fEntityScanner.skipChar(';')) {
2070                 reportFatalError("SemicolonRequiredInPEReference",
2071                 new Object[]{name});
2072             }
2073             startPE(name, false);
2074             fEntityScanner.skipSpaces();
2075             if (!fEntityScanner.skipChar('%'))
2076                 return true;
2077         }
2078     }
2079 
2080 
2081     /*
2082      * Element Children Content Stack
2083      */
2084     private final void pushContentStack(int c) {
2085         if (fContentStack.length == fContentDepth) {
2086             int[] newStack = new int[fContentDepth * 2];
2087             System.arraycopy(fContentStack, 0, newStack, 0, fContentDepth);
2088             fContentStack = newStack;
2089         }
2090         fContentStack[fContentDepth++] = c;
2091     }
2092 
2093     private final int popContentStack() {
2094         return fContentStack[--fContentDepth];
2095     }
2096 
2097 
2098     /*
2099      * Parameter Entity Stack
2100      */
2101     private final void pushPEStack(int depth, boolean report) {
2102         if (fPEStack.length == fPEDepth) {
2103             int[] newIntStack = new int[fPEDepth * 2];
2104             System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth);
2105             fPEStack = newIntStack;
2106             // report end/start calls
2107             boolean[] newBooleanStack = new boolean[fPEDepth * 2];
2108             System.arraycopy(fPEReport, 0, newBooleanStack, 0, fPEDepth);
2109             fPEReport = newBooleanStack;
2110 
2111         }
2112         fPEReport[fPEDepth] = report;
2113         fPEStack[fPEDepth++] = depth;
2114     }
2115 
2116     /** pop the stack */
2117     private final int popPEStack() {
2118         return fPEStack[--fPEDepth];
2119     }
2120 
2121     /** look at the top of the stack */
2122     private final boolean peekReportEntity() {
2123         return fPEReport[fPEDepth-1];
2124     }
2125 
2126 
2127     /*
2128      * Utility method
2129      */
2130     private final void ensureEnumerationSize(int size) {
2131         if (fEnumeration.length == size) {
2132             String[] newEnum = new String[size * 2];
2133             System.arraycopy(fEnumeration, 0, newEnum, 0, size);
2134             fEnumeration = newEnum;
2135         }
2136     }
2137 
2138     // private methods
2139     private void init() {
2140         // reset state related data
2141         fStartDTDCalled = false;
2142         fExtEntityDepth = 0;
2143         fIncludeSectDepth = 0;
2144         fMarkUpDepth = 0;
2145         fPEDepth = 0;
2146 
2147         fStandalone = false;
2148         fSeenExternalDTD = false;
2149         fSeenExternalPE = false;
2150 
2151         // set starting state
2152         setScannerState(SCANNER_STATE_TEXT_DECL);
2153         //new SymbolTable());
2154 
2155         fLimitAnalyzer = new XMLLimitAnalyzer();
2156     }
2157 
2158     /**
2159      * Add the count of the content buffer and check if the accumulated
2160      * value exceeds the limit
2161      * @param entityName entity name
2162      * @param buffer content buffer
2163      */
2164     private void checkLimit(String entityName, XMLString buffer) {
2165         checkLimit(entityName, buffer.length);
2166     }
2167 
2168     /**
2169      * Add the count and check limit
2170      * @param entityName entity name
2171      * @param len length of the buffer
2172      */
2173     private void checkLimit(String entityName, int len) {
2174         if (fLimitAnalyzer == null) {
2175             fLimitAnalyzer = new XMLLimitAnalyzer();
2176         }
2177         fLimitAnalyzer.addValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName, len);
2178         if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
2179                     fSecurityManager.debugPrint(fLimitAnalyzer);
2180             reportFatalError("MaxEntitySizeLimit", new Object[]{entityName,
2181                 fLimitAnalyzer.getValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT),
2182                 fSecurityManager.getLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT),
2183                 fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT)});
2184         }
2185         if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
2186             fSecurityManager.debugPrint(fLimitAnalyzer);
2187             reportFatalError("TotalEntitySizeLimit",
2188                 new Object[]{fLimitAnalyzer.getTotalValue(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT),
2189                 fSecurityManager.getLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT),
2190                 fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT)});
2191         }
2192 
2193     }
2194 
2195     public DTDGrammar getGrammar(){
2196         return nvGrammarInfo;
2197     }
2198 
2199 } // class XMLDTDScannerImpl