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