1 /*
   2  * Copyright (c) 2003, 2006, 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 
  23 
  24 import com.sun.xml.internal.stream.Entity;
  25 import com.sun.xml.internal.stream.StaxXMLInputSource;
  26 import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
  27 import java.io.EOFException;
  28 import java.io.IOException;
  29 import javax.xml.stream.XMLInputFactory;
  30 import javax.xml.stream.events.XMLEvent;
  31 
  32 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
  33 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
  34 import com.sun.org.apache.xerces.internal.util.XMLChar;
  35 import com.sun.org.apache.xerces.internal.util.XMLResourceIdentifierImpl;
  36 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
  37 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  38 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  39 import com.sun.org.apache.xerces.internal.xni.XMLString;
  40 import com.sun.org.apache.xerces.internal.xni.XNIException;
  41 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  42 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  43 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  44 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDScanner;
  45 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  46 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDDescription;
  47 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentScanner;
  48 
  49 
  50 /**
  51  * This class is responsible for scanning XML document structure
  52  * and content.
  53  *
  54  * This class has been modified as per the new design which is more suited to
  55  * efficiently build pull parser. Lot of improvements have been done and
  56  * the code has been added to support stax functionality/features.
  57  *
  58  * @author Neeraj Bajaj, Sun Microsystems
  59  * @author K.Venugopal, Sun Microsystems
  60  * @author Glenn Marcy, IBM
  61  * @author Andy Clark, IBM
  62  * @author Arnaud  Le Hors, IBM
  63  * @author Eric Ye, IBM
  64  * @author Sunitha Reddy, Sun Microsystems
  65  *
  66  * Refer to the table in unit-test javax.xml.stream.XMLStreamReaderTest.SupportDTD for changes
  67  * related to property SupportDTD.
  68  * @author Joe Wang, Sun Microsystems
  69  * @version $Id: XMLDocumentScannerImpl.java,v 1.17 2010-11-01 04:39:41 joehw Exp $
  70  */
  71 public class XMLDocumentScannerImpl
  72         extends XMLDocumentFragmentScannerImpl{
  73 
  74     //
  75     // Constants
  76     //
  77 
  78     // scanner states
  79 
  80     /** Scanner state: XML declaration. */
  81     protected static final int SCANNER_STATE_XML_DECL = 42;
  82 
  83     /** Scanner state: prolog. */
  84     protected static final int SCANNER_STATE_PROLOG = 43;
  85 
  86     /** Scanner state: trailing misc. */
  87     protected static final int SCANNER_STATE_TRAILING_MISC = 44;
  88 
  89     /** Scanner state: DTD internal declarations. */
  90     protected static final int SCANNER_STATE_DTD_INTERNAL_DECLS = 45;
  91 
  92     /** Scanner state: open DTD external subset. */
  93     protected static final int SCANNER_STATE_DTD_EXTERNAL = 46;
  94 
  95     /** Scanner state: DTD external declarations. */
  96     protected static final int SCANNER_STATE_DTD_EXTERNAL_DECLS = 47;
  97 
  98     /** Scanner state: NO MORE ELEMENTS. */
  99     protected static final int SCANNER_STATE_NO_SUCH_ELEMENT_EXCEPTION = 48;
 100 
 101     // feature identifiers
 102 
 103     /** Property identifier document scanner: */
 104     protected static final String DOCUMENT_SCANNER =
 105             Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_SCANNER_PROPERTY;
 106 
 107     /** Feature identifier: load external DTD. */
 108     protected static final String LOAD_EXTERNAL_DTD =
 109             Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE;
 110 
 111     /** Feature identifier: load external DTD. */
 112     protected static final String DISALLOW_DOCTYPE_DECL_FEATURE =
 113             Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE;
 114 
 115     // property identifiers
 116 
 117     /** Property identifier: DTD scanner. */
 118     protected static final String DTD_SCANNER =
 119             Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_SCANNER_PROPERTY;
 120 
 121     // property identifier:  ValidationManager
 122     protected static final String VALIDATION_MANAGER =
 123             Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
 124 
 125     /** property identifier:  NamespaceContext */
 126     protected static final String NAMESPACE_CONTEXT =
 127         Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY;
 128 
 129     // recognized features and properties
 130 
 131     /** Recognized features. */
 132     private static final String[] RECOGNIZED_FEATURES = {
 133         LOAD_EXTERNAL_DTD,
 134                 DISALLOW_DOCTYPE_DECL_FEATURE,
 135     };
 136 
 137     /** Feature defaults. */
 138     private static final Boolean[] FEATURE_DEFAULTS = {
 139         Boolean.TRUE,
 140                 Boolean.FALSE,
 141     };
 142 
 143     /** Recognized properties. */
 144     private static final String[] RECOGNIZED_PROPERTIES = {
 145         DTD_SCANNER,
 146                 VALIDATION_MANAGER
 147     };
 148 
 149     /** Property defaults. */
 150     private static final Object[] PROPERTY_DEFAULTS = {
 151         null,
 152                 null
 153     };
 154 
 155     //
 156     // Data((Boolean)propertyManager.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue();
 157     //
 158 
 159     // properties
 160 
 161     /** DTD scanner. */
 162     protected XMLDTDScanner fDTDScanner = null;
 163 
 164     /** Validation manager . */
 165     //xxx: fValidationManager code needs to be added yet!
 166     protected ValidationManager fValidationManager;
 167 
 168     protected XMLStringBuffer fDTDDecl = null;
 169     protected boolean fReadingDTD = false;
 170     protected boolean fAddedListener = false;
 171 
 172     // protected data
 173 
 174     // other info
 175 
 176     /** Doctype name. */
 177     protected String fDoctypeName;
 178 
 179     /** Doctype declaration public identifier. */
 180     protected String fDoctypePublicId;
 181 
 182     /** Doctype declaration system identifier. */
 183     protected String fDoctypeSystemId;
 184 
 185     /** Namespace support. */
 186     protected NamespaceContext fNamespaceContext = new NamespaceSupport();
 187 
 188     // features
 189 
 190     /** Load external DTD. */
 191     protected boolean fLoadExternalDTD = true;
 192 
 193     // state
 194 
 195     /** Seen doctype declaration. */
 196     protected boolean fSeenDoctypeDecl;
 197 
 198     protected boolean fScanEndElement;
 199 
 200     //protected int fScannerLastState ;
 201 
 202     // drivers
 203 
 204     /** XML declaration driver. */
 205     protected Driver fXMLDeclDriver = new XMLDeclDriver();
 206 
 207     /** Prolog driver. */
 208     protected Driver fPrologDriver = new PrologDriver();
 209 
 210     /** DTD driver. */
 211     protected Driver fDTDDriver = null ;
 212 
 213     /** Trailing miscellaneous section driver. */
 214     protected Driver fTrailingMiscDriver = new TrailingMiscDriver();
 215     protected int fStartPos = 0;
 216     protected int fEndPos = 0;
 217     protected boolean fSeenInternalSubset= false;
 218     // temporary variables
 219 
 220     /** Array of 3 strings. */
 221     private String[] fStrings = new String[3];
 222 
 223     /** External subset source. */
 224     private XMLInputSource fExternalSubsetSource = null;
 225 
 226     /** A DTD Description. */
 227     private final XMLDTDDescription fDTDDescription = new XMLDTDDescription(null, null, null, null, null);
 228 
 229     /** String. */
 230     private XMLString fString = new XMLString();
 231 
 232     private static final char [] DOCTYPE = {'D','O','C','T','Y','P','E'};
 233     private static final char [] COMMENTSTRING = {'-','-'};
 234 
 235     //
 236     // Constructors
 237     //
 238 
 239     /** Default constructor. */
 240     public XMLDocumentScannerImpl() {} // <init>()
 241 
 242 
 243     //
 244     // XMLDocumentScanner methods
 245     //
 246 
 247 
 248     /**
 249      * Sets the input source.
 250      *
 251      * @param inputSource The input source.
 252      *
 253      * @throws IOException Thrown on i/o error.
 254      */
 255     public void setInputSource(XMLInputSource inputSource) throws IOException {
 256         fEntityManager.setEntityHandler(this);
 257         //this starts a new entity and sets the current entity to the document entity.
 258         fEntityManager.startDocumentEntity(inputSource);
 259         // fDocumentSystemId = fEntityManager.expandSystemId(inputSource.getSystemId());
 260         setScannerState(XMLEvent.START_DOCUMENT);
 261     } // setInputSource(XMLInputSource)
 262 
 263 
 264 
 265     /**return the state of the scanner */
 266     public int getScannetState(){
 267         return fScannerState ;
 268     }
 269 
 270 
 271 
 272 
 273     public void reset(PropertyManager propertyManager) {
 274         super.reset(propertyManager);
 275         // other settings
 276         fDoctypeName = null;
 277         fDoctypePublicId = null;
 278         fDoctypeSystemId = null;
 279         fSeenDoctypeDecl = false;
 280         fNamespaceContext.reset();
 281         fSupportDTD = ((Boolean)propertyManager.getProperty(XMLInputFactory.SUPPORT_DTD)).booleanValue();
 282 
 283         // xerces features
 284         fLoadExternalDTD = !((Boolean)propertyManager.getProperty(Constants.ZEPHYR_PROPERTY_PREFIX + Constants.IGNORE_EXTERNAL_DTD)).booleanValue();
 285         setScannerState(XMLEvent.START_DOCUMENT);
 286         setDriver(fXMLDeclDriver);
 287         fSeenInternalSubset = false;
 288         if(fDTDScanner != null){
 289             ((XMLDTDScannerImpl)fDTDScanner).reset(propertyManager);
 290         }
 291         fEndPos = 0;
 292         fStartPos = 0;
 293         if(fDTDDecl != null){
 294             fDTDDecl.clear();
 295         }
 296 
 297     }
 298 
 299     /**
 300      * Resets the component. The component can query the component manager
 301      * about any features and properties that affect the operation of the
 302      * component.
 303      *
 304      * @param componentManager The component manager.
 305      *
 306      * @throws SAXException Thrown by component on initialization error.
 307      *                      For example, if a feature or property is
 308      *                      required for the operation of the component, the
 309      *                      component manager may throw a
 310      *                      SAXNotRecognizedException or a
 311      *                      SAXNotSupportedException.
 312      */
 313     public void reset(XMLComponentManager componentManager)
 314     throws XMLConfigurationException {
 315 
 316         super.reset(componentManager);
 317 
 318         // other settings
 319         fDoctypeName = null;
 320         fDoctypePublicId = null;
 321         fDoctypeSystemId = null;
 322         fSeenDoctypeDecl = false;
 323         fExternalSubsetSource = null;
 324 
 325         // xerces features
 326         fLoadExternalDTD = componentManager.getFeature(LOAD_EXTERNAL_DTD, true);
 327         fDisallowDoctype = componentManager.getFeature(DISALLOW_DOCTYPE_DECL_FEATURE, false);
 328 
 329         fNamespaces = componentManager.getFeature(NAMESPACES, true);
 330 
 331         fSeenInternalSubset = false;
 332         // xerces properties
 333         fDTDScanner = (XMLDTDScanner)componentManager.getProperty(DTD_SCANNER);
 334 
 335         fValidationManager = (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER, null);
 336 
 337         try {
 338             fNamespaceContext = (NamespaceContext)componentManager.getProperty(NAMESPACE_CONTEXT);
 339         }
 340         catch (XMLConfigurationException e) { }
 341         if (fNamespaceContext == null) {
 342             fNamespaceContext = new NamespaceSupport();
 343         }
 344         fNamespaceContext.reset();
 345 
 346         fEndPos = 0;
 347         fStartPos = 0;
 348         if(fDTDDecl != null)
 349             fDTDDecl.clear();
 350 
 351 
 352         //fEntityScanner.registerListener((XMLBufferListener)componentManager.getProperty(DOCUMENT_SCANNER));
 353 
 354         // setup driver
 355         setScannerState(SCANNER_STATE_XML_DECL);
 356         setDriver(fXMLDeclDriver);
 357 
 358     } // reset(XMLComponentManager)
 359 
 360 
 361     /**
 362      * Returns a list of feature identifiers that are recognized by
 363      * this component. This method may return null if no features
 364      * are recognized by this component.
 365      */
 366     public String[] getRecognizedFeatures() {
 367         String[] featureIds = super.getRecognizedFeatures();
 368         int length = featureIds != null ? featureIds.length : 0;
 369         String[] combinedFeatureIds = new String[length + RECOGNIZED_FEATURES.length];
 370         if (featureIds != null) {
 371             System.arraycopy(featureIds, 0, combinedFeatureIds, 0, featureIds.length);
 372         }
 373         System.arraycopy(RECOGNIZED_FEATURES, 0, combinedFeatureIds, length, RECOGNIZED_FEATURES.length);
 374         return combinedFeatureIds;
 375     } // getRecognizedFeatures():String[]
 376 
 377     /**
 378      * Sets the state of a feature. This method is called by the component
 379      * manager any time after reset when a feature changes state.
 380      * <p>
 381      * <strong>Note:</strong> Components should silently ignore features
 382      * that do not affect the operation of the component.
 383      *
 384      * @param featureId The feature identifier.
 385      * @param state     The state of the feature.
 386      *
 387      * @throws SAXNotRecognizedException The component should not throw
 388      *                                   this exception.
 389      * @throws SAXNotSupportedException The component should not throw
 390      *                                  this exception.
 391      */
 392     public void setFeature(String featureId, boolean state)
 393     throws XMLConfigurationException {
 394 
 395         super.setFeature(featureId, state);
 396 
 397         // Xerces properties
 398         if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) {
 399             final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length();
 400 
 401             if (suffixLength == Constants.LOAD_EXTERNAL_DTD_FEATURE.length() &&
 402                 featureId.endsWith(Constants.LOAD_EXTERNAL_DTD_FEATURE)) {
 403                 fLoadExternalDTD = state;
 404                 return;
 405             }
 406             else if (suffixLength == Constants.DISALLOW_DOCTYPE_DECL_FEATURE.length() &&
 407                 featureId.endsWith(Constants.DISALLOW_DOCTYPE_DECL_FEATURE)) {
 408                 fDisallowDoctype = state;
 409                 return;
 410             }
 411         }
 412 
 413     } // setFeature(String,boolean)
 414 
 415     /**
 416      * Returns a list of property identifiers that are recognized by
 417      * this component. This method may return null if no properties
 418      * are recognized by this component.
 419      */
 420     public String[] getRecognizedProperties() {
 421         String[] propertyIds = super.getRecognizedProperties();
 422         int length = propertyIds != null ? propertyIds.length : 0;
 423         String[] combinedPropertyIds = new String[length + RECOGNIZED_PROPERTIES.length];
 424         if (propertyIds != null) {
 425             System.arraycopy(propertyIds, 0, combinedPropertyIds, 0, propertyIds.length);
 426         }
 427         System.arraycopy(RECOGNIZED_PROPERTIES, 0, combinedPropertyIds, length, RECOGNIZED_PROPERTIES.length);
 428         return combinedPropertyIds;
 429     } // getRecognizedProperties():String[]
 430 
 431     /**
 432      * Sets the value of a property. This method is called by the component
 433      * manager any time after reset when a property changes value.
 434      * <p>
 435      * <strong>Note:</strong> Components should silently ignore properties
 436      * that do not affect the operation of the component.
 437      *
 438      * @param propertyId The property identifier.
 439      * @param value      The value of the property.
 440      *
 441      * @throws SAXNotRecognizedException The component should not throw
 442      *                                   this exception.
 443      * @throws SAXNotSupportedException The component should not throw
 444      *                                  this exception.
 445      */
 446     public void setProperty(String propertyId, Object value)
 447     throws XMLConfigurationException {
 448 
 449         super.setProperty(propertyId, value);
 450 
 451         // Xerces properties
 452         if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
 453             final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length();
 454 
 455             if (suffixLength == Constants.DTD_SCANNER_PROPERTY.length() &&
 456                 propertyId.endsWith(Constants.DTD_SCANNER_PROPERTY)) {
 457                 fDTDScanner = (XMLDTDScanner)value;
 458             }
 459             if (suffixLength == Constants.NAMESPACE_CONTEXT_PROPERTY.length() &&
 460                 propertyId.endsWith(Constants.NAMESPACE_CONTEXT_PROPERTY)) {
 461                 if (value != null) {
 462                     fNamespaceContext = (NamespaceContext)value;
 463                 }
 464             }
 465 
 466             return;
 467         }
 468 
 469     } // setProperty(String,Object)
 470 
 471     /**
 472      * Returns the default state for a feature, or null if this
 473      * component does not want to report a default value for this
 474      * feature.
 475      *
 476      * @param featureId The feature identifier.
 477      *
 478      * @since Xerces 2.2.0
 479      */
 480     public Boolean getFeatureDefault(String featureId) {
 481 
 482         for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
 483             if (RECOGNIZED_FEATURES[i].equals(featureId)) {
 484                 return FEATURE_DEFAULTS[i];
 485             }
 486         }
 487         return super.getFeatureDefault(featureId);
 488     } // getFeatureDefault(String):Boolean
 489 
 490     /**
 491      * Returns the default state for a property, or null if this
 492      * component does not want to report a default value for this
 493      * property.
 494      *
 495      * @param propertyId The property identifier.
 496      *
 497      * @since Xerces 2.2.0
 498      */
 499     public Object getPropertyDefault(String propertyId) {
 500         for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
 501             if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
 502                 return PROPERTY_DEFAULTS[i];
 503             }
 504         }
 505         return super.getPropertyDefault(propertyId);
 506     } // getPropertyDefault(String):Object
 507 
 508     //
 509     // XMLEntityHandler methods
 510     //
 511 
 512     /**
 513      * This method notifies of the start of an entity. The DTD has the
 514      * pseudo-name of "[dtd]" parameter entity names start with '%'; and
 515      * general entities are just specified by their name.
 516      *
 517      * @param name     The name of the entity.
 518      * @param identifier The resource identifier.
 519      * @param encoding The auto-detected IANA encoding name of the entity
 520      *                 stream. This value will be null in those situations
 521      *                 where the entity encoding is not auto-detected (e.g.
 522      *                 internal entities or a document entity that is
 523      *                 parsed from a java.io.Reader).
 524      *
 525      * @throws XNIException Thrown by handler to signal an error.
 526      */
 527     public void startEntity(String name,
 528             XMLResourceIdentifier identifier,
 529             String encoding, Augmentations augs) throws XNIException {
 530 
 531         super.startEntity(name, identifier, encoding,augs);
 532 
 533         //register current document scanner as a listener for XMLEntityScanner
 534         fEntityScanner.registerListener(this);
 535 
 536         // prepare to look for a TextDecl if external general entity
 537         if (!name.equals("[xml]") && fEntityScanner.isExternal()) {
 538             // Don't do this if we're skipping the entity!
 539             if (augs == null || !((Boolean) augs.getItem(Constants.ENTITY_SKIPPED)).booleanValue()) {
 540                 setScannerState(SCANNER_STATE_TEXT_DECL);
 541             }
 542         }
 543 
 544         // call handler
 545         /** comment this part.. LOCATOR problem.. */
 546         if (fDocumentHandler != null && name.equals("[xml]")) {
 547             fDocumentHandler.startDocument(fEntityScanner, encoding, fNamespaceContext, null);
 548         }
 549 
 550     } // startEntity(String,identifier,String)
 551 
 552 
 553     /**
 554      * This method notifies the end of an entity. The DTD has the pseudo-name
 555      * of "[dtd]" parameter entity names start with '%'; and general entities
 556      * are just specified by their name.
 557      *
 558      * @param name The name of the entity.
 559      *
 560      * @throws XNIException Thrown by handler to signal an error.
 561      */
 562     public void endEntity(String name, Augmentations augs) throws IOException, XNIException {
 563 
 564         super.endEntity(name, augs);
 565 
 566         if(name.equals("[xml]")){
 567             //if fMarkupDepth has reached 0.
 568             //and driver is fTrailingMiscDriver (which
 569             //handles end of document in normal case)
 570             //set the scanner state of SCANNER_STATE_TERMINATED
 571             if(fMarkupDepth == 0 && fDriver == fTrailingMiscDriver){
 572                 //set the scanner set to SCANNER_STATE_TERMINATED
 573                 setScannerState(SCANNER_STATE_TERMINATED) ;
 574             } else{
 575                 //else we have reached the end of document prematurely
 576                 //so throw EOFException.
 577                 throw new java.io.EOFException();
 578             }
 579 
 580             //this is taken care in wrapper which generates XNI callbacks, There are no next events
 581 
 582             //if (fDocumentHandler != null) {
 583                 //fDocumentHandler.endDocument(null);
 584             //}
 585         }
 586     } // endEntity(String)
 587 
 588 
 589     public XMLStringBuffer getDTDDecl(){
 590         Entity entity = fEntityScanner.getCurrentEntity();
 591         fDTDDecl.append(((Entity.ScannedEntity)entity).ch,fStartPos , fEndPos-fStartPos);
 592         if(fSeenInternalSubset)
 593             fDTDDecl.append("]>");
 594         return fDTDDecl;
 595     }
 596 
 597     public String getCharacterEncodingScheme(){
 598         return fDeclaredEncoding;
 599     }
 600 
 601     /** return the next state on the input
 602      *
 603      * @return int
 604      */
 605 
 606     public int next() throws IOException, XNIException {
 607         return fDriver.next();
 608     }
 609 
 610     //getNamespaceContext
 611     public NamespaceContext getNamespaceContext(){
 612         return fNamespaceContext ;
 613     }
 614 
 615 
 616 
 617     //
 618     // Protected methods
 619     //
 620 
 621     // driver factory methods
 622 
 623     /** Creates a content driver. */
 624     protected Driver createContentDriver() {
 625         return new ContentDriver();
 626     } // createContentDriver():Driver
 627 
 628     // scanning methods
 629 
 630     /** Scans a doctype declaration. */
 631     protected boolean scanDoctypeDecl(boolean supportDTD) throws IOException, XNIException {
 632 
 633         // spaces
 634         if (!fEntityScanner.skipSpaces()) {
 635             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ROOT_ELEMENT_TYPE_IN_DOCTYPEDECL",
 636                     null);
 637         }
 638 
 639         // root element name
 640         fDoctypeName = fEntityScanner.scanName();
 641         if (fDoctypeName == null) {
 642             reportFatalError("MSG_ROOT_ELEMENT_TYPE_REQUIRED", null);
 643         }
 644 
 645         // external id
 646         if (fEntityScanner.skipSpaces()) {
 647             scanExternalID(fStrings, false);
 648             fDoctypeSystemId = fStrings[0];
 649             fDoctypePublicId = fStrings[1];
 650             fEntityScanner.skipSpaces();
 651         }
 652 
 653         fHasExternalDTD = fDoctypeSystemId != null;
 654 
 655         // Attempt to locate an external subset with an external subset resolver.
 656         if (supportDTD && !fHasExternalDTD && fExternalSubsetResolver != null) {
 657             fDTDDescription.setValues(null, null, fEntityManager.getCurrentResourceIdentifier().getExpandedSystemId(), null);
 658             fDTDDescription.setRootName(fDoctypeName);
 659             fExternalSubsetSource = fExternalSubsetResolver.getExternalSubset(fDTDDescription);
 660             fHasExternalDTD = fExternalSubsetSource != null;
 661         }
 662 
 663         // call handler
 664         if (supportDTD && fDocumentHandler != null) {
 665             // NOTE: I don't like calling the doctypeDecl callback until
 666             //       end of the *full* doctype line (including internal
 667             //       subset) is parsed correctly but SAX2 requires that
 668             //       it knows the root element name and public and system
 669             //       identifier for the startDTD call. -Ac
 670             if (fExternalSubsetSource == null) {
 671                 fDocumentHandler.doctypeDecl(fDoctypeName, fDoctypePublicId, fDoctypeSystemId, null);
 672             }
 673             else {
 674                 fDocumentHandler.doctypeDecl(fDoctypeName, fExternalSubsetSource.getPublicId(), fExternalSubsetSource.getSystemId(), null);
 675             }
 676         }
 677 
 678         // is there an internal subset?
 679         boolean internalSubset = true;
 680         if (!fEntityScanner.skipChar('[')) {
 681             internalSubset = false;
 682             fEntityScanner.skipSpaces();
 683             if (!fEntityScanner.skipChar('>')) {
 684                 reportFatalError("DoctypedeclUnterminated", new Object[]{fDoctypeName});
 685             }
 686             fMarkupDepth--;
 687         }
 688         return internalSubset;
 689 
 690     } // scanDoctypeDecl():boolean
 691 
 692     //
 693     // Private methods
 694     //
 695     /** Set the scanner state after scanning DTD */
 696     protected void setEndDTDScanState() {
 697         setScannerState(SCANNER_STATE_PROLOG);
 698         setDriver(fPrologDriver);
 699         fEntityManager.setEntityHandler(XMLDocumentScannerImpl.this);
 700         fReadingDTD=false;
 701     }
 702 
 703     /** Returns the scanner state name. */
 704     protected String getScannerStateName(int state) {
 705 
 706         switch (state) {
 707             case SCANNER_STATE_XML_DECL: return "SCANNER_STATE_XML_DECL";
 708             case SCANNER_STATE_PROLOG: return "SCANNER_STATE_PROLOG";
 709             case SCANNER_STATE_TRAILING_MISC: return "SCANNER_STATE_TRAILING_MISC";
 710             case SCANNER_STATE_DTD_INTERNAL_DECLS: return "SCANNER_STATE_DTD_INTERNAL_DECLS";
 711             case SCANNER_STATE_DTD_EXTERNAL: return "SCANNER_STATE_DTD_EXTERNAL";
 712             case SCANNER_STATE_DTD_EXTERNAL_DECLS: return "SCANNER_STATE_DTD_EXTERNAL_DECLS";
 713         }
 714         return super.getScannerStateName(state);
 715 
 716     } // getScannerStateName(int):String
 717 
 718     //
 719     // Classes
 720     //
 721 
 722     /**
 723      * Driver to handle XMLDecl scanning.
 724      *
 725      * This class has been modified as per the new design which is more suited to
 726      * efficiently build pull parser. Lots of performance improvements have been done and
 727      * the code has been added to support stax functionality/features.
 728      *
 729      * @author Neeraj Bajaj, Sun Microsystems.
 730      *
 731      * @author Andy Clark, IBM
 732      */
 733     protected final class XMLDeclDriver
 734             implements Driver {
 735 
 736         //
 737         // Driver methods
 738         //
 739 
 740 
 741         public int next() throws IOException, XNIException {
 742             if(DEBUG_NEXT){
 743                 System.out.println("NOW IN XMLDeclDriver");
 744             }
 745 
 746             // next driver is prolog regardless of whether there
 747             // is an XMLDecl in this document
 748             setScannerState(SCANNER_STATE_PROLOG);
 749             setDriver(fPrologDriver);
 750 
 751             //System.out.println("fEntityScanner = " + fEntityScanner);
 752             // scan XMLDecl
 753             try {
 754                 if (fEntityScanner.skipString(xmlDecl)) {
 755                     fMarkupDepth++;
 756                     // NOTE: special case where document starts with a PI
 757                     //       whose name starts with "xml" (e.g. "xmlfoo")
 758                     if (XMLChar.isName(fEntityScanner.peekChar())) {
 759                         fStringBuffer.clear();
 760                         fStringBuffer.append("xml");
 761                         while (XMLChar.isName(fEntityScanner.peekChar())) {
 762                             fStringBuffer.append((char)fEntityScanner.scanChar());
 763                         }
 764                         String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
 765                         //this function should fill the data.. and set the fEvent object to this event.
 766                         fContentBuffer.clear() ;
 767                         scanPIData(target, fContentBuffer);
 768                         //REVISIT:where else we can set this value to 'true'
 769                         fEntityManager.fCurrentEntity.mayReadChunks = true;
 770                         //return PI event since PI was encountered
 771                         return XMLEvent.PROCESSING_INSTRUCTION ;
 772                     }
 773                     // standard XML declaration
 774                     else {
 775                         scanXMLDeclOrTextDecl(false);
 776                         //REVISIT:where else we can set this value to 'true'
 777                         fEntityManager.fCurrentEntity.mayReadChunks = true;
 778                         return XMLEvent.START_DOCUMENT;
 779                     }
 780                 } else{
 781                     //REVISIT:where else we can set this value to 'true'
 782                     fEntityManager.fCurrentEntity.mayReadChunks = true;
 783                     //In both case return the START_DOCUMENT. ony difference is that first block will
 784                     //cosume the XML declaration if any.
 785                     return XMLEvent.START_DOCUMENT;
 786                 }
 787 
 788 
 789                 //START_OF_THE_DOCUMENT
 790 
 791 
 792             }
 793 
 794             // premature end of file
 795             catch (EOFException e) {
 796                 reportFatalError("PrematureEOF", null);
 797                 return -1;
 798                 //throw e;
 799             }
 800 
 801         }
 802     } // class XMLDeclDriver
 803 
 804     /**
 805      * Driver to handle prolog scanning.
 806      *
 807      * @author Andy Clark, IBM
 808      */
 809     protected final class PrologDriver
 810             implements Driver {
 811 
 812         /**
 813          * Drives the parser to the next state/event on the input. Parser is guaranteed
 814          * to stop at the next state/event.
 815          *
 816          * Internally XML document is divided into several states. Each state represents
 817          * a sections of XML document. When this functions returns normally, it has read
 818          * the section of XML document and returns the state corresponding to section of
 819          * document which has been read. For optimizations, a particular driver
 820          * can read ahead of the section of document (state returned) just read and
 821          * can maintain a different internal state.
 822          *
 823          * @return state representing the section of document just read.
 824          *
 825          * @throws IOException  Thrown on i/o error.
 826          * @throws XNIException Thrown on parse error.
 827          */
 828 
 829         public int next() throws IOException, XNIException {
 830             //System.out.println("here in next");
 831 
 832             if(DEBUG_NEXT){
 833                 System.out.println("NOW IN PrologDriver");
 834             }
 835             try {
 836                 do {
 837                     switch (fScannerState) {
 838                         case SCANNER_STATE_PROLOG: {
 839                             fEntityScanner.skipSpaces();
 840                             if (fEntityScanner.skipChar('<')) {
 841                                 setScannerState(SCANNER_STATE_START_OF_MARKUP);
 842                             } else if (fEntityScanner.skipChar('&')) {
 843                                 setScannerState(SCANNER_STATE_REFERENCE);
 844                             } else {
 845                                 setScannerState(SCANNER_STATE_CONTENT);
 846                             }
 847                             break;
 848                         }
 849 
 850                         case SCANNER_STATE_START_OF_MARKUP: {
 851                             fMarkupDepth++;
 852 
 853                             if (fEntityScanner.skipChar('?')) {
 854                                 setScannerState(SCANNER_STATE_PI);
 855                             } else if (fEntityScanner.skipChar('!')) {
 856                                 if (fEntityScanner.skipChar('-')) {
 857                                     if (!fEntityScanner.skipChar('-')) {
 858                                         reportFatalError("InvalidCommentStart",
 859                                                 null);
 860                                     }
 861                                     setScannerState(SCANNER_STATE_COMMENT);
 862                                 } else if (fEntityScanner.skipString(DOCTYPE)) {
 863                                     setScannerState(SCANNER_STATE_DOCTYPE);
 864                                     Entity entity = fEntityScanner.getCurrentEntity();
 865                                     if(entity instanceof Entity.ScannedEntity){
 866                                         fStartPos=((Entity.ScannedEntity)entity).position;
 867                                     }
 868                                     fReadingDTD=true;
 869                                     if(fDTDDecl == null)
 870                                         fDTDDecl = new XMLStringBuffer();
 871                                     fDTDDecl.append("<!DOCTYPE");
 872 
 873                                 } else {
 874                                     reportFatalError("MarkupNotRecognizedInProlog",
 875                                             null);
 876                                 }
 877                             } else if (XMLChar.isNameStart(fEntityScanner.peekChar())) {
 878                                 setScannerState(SCANNER_STATE_ROOT_ELEMENT);
 879                                 setDriver(fContentDriver);
 880                                 //from now onwards this would be handled by fContentDriver,in the same next() call
 881                                 return fContentDriver.next();
 882 
 883                             } else {
 884                                 reportFatalError("MarkupNotRecognizedInProlog",
 885                                         null);
 886                             }
 887                             break;
 888                         }
 889                     }
 890                 } while (fScannerState == SCANNER_STATE_PROLOG || fScannerState == SCANNER_STATE_START_OF_MARKUP );
 891 
 892                 switch(fScannerState){
 893                     /**
 894                     //this part is handled by FragmentContentHandler
 895                     case SCANNER_STATE_ROOT_ELEMENT: {
 896                         //we have read '<' and beginning of reading the start element tag
 897                         setScannerState(SCANNER_STATE_START_ELEMENT_TAG);
 898                         setDriver(fContentDriver);
 899                         //from now onwards this would be handled by fContentDriver,in the same next() call
 900                         return fContentDriver.next();
 901                     }
 902                      */
 903                     case SCANNER_STATE_COMMENT: {
 904                         //this function fills the data..
 905                         scanComment();
 906                         setScannerState(SCANNER_STATE_PROLOG);
 907                         return XMLEvent.COMMENT;
 908                         //setScannerState(SCANNER_STATE_PROLOG);
 909                         //break;
 910                     }
 911                     case SCANNER_STATE_PI: {
 912                         fContentBuffer.clear() ;
 913                         scanPI(fContentBuffer);
 914                         setScannerState(SCANNER_STATE_PROLOG);
 915                         return XMLEvent.PROCESSING_INSTRUCTION;
 916                     }
 917 
 918                     case SCANNER_STATE_DOCTYPE: {
 919                         if (fDisallowDoctype) {
 920                             reportFatalError("DoctypeNotAllowed", null);
 921                         }
 922 
 923 
 924                         if (fSeenDoctypeDecl) {
 925                             reportFatalError("AlreadySeenDoctype", null);
 926                         }
 927                         fSeenDoctypeDecl = true;
 928 
 929                         // scanDoctypeDecl() sends XNI doctypeDecl event that
 930                         // in SAX is converted to startDTD() event.
 931                         if (scanDoctypeDecl(fSupportDTD)) {
 932                             //allow parsing of entity decls to continue in order to stay well-formed
 933                             setScannerState(SCANNER_STATE_DTD_INTERNAL_DECLS);
 934                             fSeenInternalSubset = true;
 935                             if(fDTDDriver == null){
 936                                 fDTDDriver = new DTDDriver();
 937                             }
 938                             setDriver(fContentDriver);
 939                             //always return DTD event, the event however, will not contain any entities
 940                             return fDTDDriver.next();
 941                         }
 942 
 943                         if(fSeenDoctypeDecl){
 944                             Entity entity = fEntityScanner.getCurrentEntity();
 945                             if(entity instanceof Entity.ScannedEntity){
 946                                 fEndPos = ((Entity.ScannedEntity)entity).position;
 947                             }
 948                             fReadingDTD = false;
 949                         }
 950 
 951                         // handle external subset
 952                         if (fDoctypeSystemId != null) {
 953                             if (((fValidation || fLoadExternalDTD)
 954                                 && (fValidationManager == null || !fValidationManager.isCachedDTD()))) {
 955                             if (fSupportDTD)
 956                                 setScannerState(SCANNER_STATE_DTD_EXTERNAL);
 957                             else
 958                                 setScannerState(SCANNER_STATE_PROLOG);
 959                             setDriver(fContentDriver);
 960                             if(fDTDDriver == null)
 961                                 fDTDDriver = new DTDDriver();
 962                             return fDTDDriver.next();
 963 
 964                             }
 965                         }
 966                         else if (fExternalSubsetSource != null) {
 967                             if (((fValidation || fLoadExternalDTD)
 968                                 && (fValidationManager == null || !fValidationManager.isCachedDTD()))) {
 969                                 // This handles the case of a DOCTYPE that had neither an internal subset or an external subset.
 970                                 fDTDScanner.setInputSource(fExternalSubsetSource);
 971                                 fExternalSubsetSource = null;
 972                             if (fSupportDTD)
 973                                 setScannerState(SCANNER_STATE_DTD_EXTERNAL_DECLS);
 974                             else
 975                                 setScannerState(SCANNER_STATE_PROLOG);
 976                             setDriver(fContentDriver);
 977                             if(fDTDDriver == null)
 978                                 fDTDDriver = new DTDDriver();
 979                             return fDTDDriver.next();
 980                             }
 981                         }
 982 
 983                         // Send endDTD() call if:
 984                         // a) systemId is null or if an external subset resolver could not locate an external subset.
 985                         // b) "load-external-dtd" and validation are false
 986                         // c) DTD grammar is cached
 987 
 988                         // in XNI this results in 3 events:  doctypeDecl, startDTD, endDTD
 989                         // in SAX this results in 2 events: startDTD, endDTD
 990                         if (fDTDScanner != null) {
 991                             fDTDScanner.setInputSource(null);
 992                         }
 993                         setScannerState(SCANNER_STATE_PROLOG);
 994                         return XMLEvent.DTD;
 995                     }
 996 
 997                     case SCANNER_STATE_CONTENT: {
 998                         reportFatalError("ContentIllegalInProlog", null);
 999                         fEntityScanner.scanChar();
1000                     }
1001                     case SCANNER_STATE_REFERENCE: {
1002                         reportFatalError("ReferenceIllegalInProlog", null);
1003                     }
1004 
1005                     /**
1006                      * if (complete) {
1007                      * if (fEntityScanner.scanChar() != '<') {
1008                      * reportFatalError("RootElementRequired", null);
1009                      * }
1010                      * setScannerState(SCANNER_STATE_ROOT_ELEMENT);
1011                      * setDriver(fContentDriver);
1012                      * }
1013                      */
1014                 }
1015             }
1016             // premature end of file
1017             catch (EOFException e) {
1018                 reportFatalError("PrematureEOF", null);
1019                 //xxx  what should be returned here.... ???
1020                 return -1 ;
1021                 //throw e;
1022             }
1023             //xxx  what should be returned here.... ???
1024             return -1;
1025 
1026         }
1027 
1028 
1029     } // class PrologDriver
1030 
1031     /**
1032      * Driver to handle the internal and external DTD subsets.
1033      *
1034      * @author Andy Clark, IBM
1035      */
1036     protected final class DTDDriver
1037             implements Driver {
1038 
1039         //
1040         // Driver methods
1041         //
1042 
1043         public int next() throws IOException, XNIException{
1044             // throw new XNIException("DTD Parsing is currently not supported");
1045             if(DEBUG_NEXT){
1046                 System.out.println("Now in DTD Driver");
1047             }
1048 
1049             dispatch(true);
1050 
1051             if(DEBUG_NEXT){
1052                 System.out.println("After calling dispatch(true) -- At this point whole DTD is read.");
1053             }
1054 
1055             //xxx: remove this hack and align this with reusing DTD components
1056             //currently this routine will only be executed from Stax
1057             if(fPropertyManager != null){
1058                 dtdGrammarUtil =  new DTDGrammarUtil(((XMLDTDScannerImpl)fDTDScanner).getGrammar(),fSymbolTable, fNamespaceContext);
1059             }
1060 
1061             return XMLEvent.DTD ;
1062         }
1063 
1064         /**
1065          * Dispatch an XML "event".
1066          *
1067          * @param complete True if this driver is intended to scan
1068          *                 and dispatch as much as possible.
1069          *
1070          * @return True if there is more to dispatch either from this
1071          *          or a another driver.
1072          *
1073          * @throws IOException  Thrown on i/o error.
1074          * @throws XNIException Thrown on parse error.
1075          */
1076         public boolean dispatch(boolean complete)
1077         throws IOException, XNIException {
1078             fEntityManager.setEntityHandler(null);
1079             try {
1080                 boolean again;
1081                 XMLResourceIdentifierImpl resourceIdentifier = new XMLResourceIdentifierImpl();
1082                 if( fDTDScanner == null){
1083 
1084                     if (fEntityManager.getEntityScanner() instanceof XML11EntityScanner){
1085                         fDTDScanner = new XML11DTDScannerImpl();
1086                     } else
1087 
1088                     fDTDScanner = new XMLDTDScannerImpl();
1089 
1090                     ((XMLDTDScannerImpl)fDTDScanner).reset(fPropertyManager);
1091                 }
1092                 do {
1093                     again = false;
1094                     switch (fScannerState) {
1095                         case SCANNER_STATE_DTD_INTERNAL_DECLS: {
1096                             // REVISIT: Should there be a feature for
1097                             //          the "complete" parameter?
1098                             boolean completeDTD = true;
1099 
1100                             boolean moreToScan = fDTDScanner.scanDTDInternalSubset(completeDTD, fStandalone, fHasExternalDTD && fLoadExternalDTD);
1101                             Entity entity = fEntityScanner.getCurrentEntity();
1102                             if(entity instanceof Entity.ScannedEntity){
1103                                 fEndPos=((Entity.ScannedEntity)entity).position;
1104                             }
1105                             fReadingDTD=false;
1106                             if (!moreToScan) {
1107                                 // end doctype declaration
1108                                 if (!fEntityScanner.skipChar(']')) {
1109                                     reportFatalError("EXPECTED_SQUARE_BRACKET_TO_CLOSE_INTERNAL_SUBSET",
1110                                             null);
1111                                 }
1112                                 fEntityScanner.skipSpaces();
1113                                 if (!fEntityScanner.skipChar('>')) {
1114                                     reportFatalError("DoctypedeclUnterminated", new Object[]{fDoctypeName});
1115                                 }
1116                                 fMarkupDepth--;
1117 
1118                                 if (!fSupportDTD) {
1119                                     //simply reset the entity store without having to mess around
1120                                     //with the DTD Scanner code
1121                                     fEntityStore = fEntityManager.getEntityStore();
1122                                     fEntityStore.reset();
1123                                 } else {
1124                                     // scan external subset next unless we are ignoring DTDs
1125                                     if (fDoctypeSystemId != null && (fValidation || fLoadExternalDTD)) {
1126                                         setScannerState(SCANNER_STATE_DTD_EXTERNAL);
1127                                         break;
1128                                     }
1129                                 }
1130 
1131                                 setEndDTDScanState();
1132                                 return true;
1133 
1134                             }
1135                             break;
1136                         }
1137                         case SCANNER_STATE_DTD_EXTERNAL: {
1138                             /**
1139                             fDTDDescription.setValues(fDoctypePublicId, fDoctypeSystemId, null, null);
1140                             fDTDDescription.setRootName(fDoctypeName);
1141                             XMLInputSource xmlInputSource =
1142                                 fEntityManager.resolveEntity(fDTDDescription);
1143                             fDTDScanner.setInputSource(xmlInputSource);
1144                             setScannerState(SCANNER_STATE_DTD_EXTERNAL_DECLS);
1145                             again = true;
1146                             break;
1147                              */
1148 
1149                             resourceIdentifier.setValues(fDoctypePublicId, fDoctypeSystemId, null, null);
1150                             XMLInputSource xmlInputSource = null ;
1151                             StaxXMLInputSource staxInputSource =  fEntityManager.resolveEntityAsPerStax(resourceIdentifier);
1152                             xmlInputSource = staxInputSource.getXMLInputSource();
1153                             fDTDScanner.setInputSource(xmlInputSource);
1154                             setScannerState(SCANNER_STATE_DTD_EXTERNAL_DECLS);
1155                             again = true;
1156                             break;
1157                         }
1158                         case SCANNER_STATE_DTD_EXTERNAL_DECLS: {
1159                             // REVISIT: Should there be a feature for
1160                             //          the "complete" parameter?
1161                             boolean completeDTD = true;
1162                             boolean moreToScan = fDTDScanner.scanDTDExternalSubset(completeDTD);
1163                             if (!moreToScan) {
1164                                 setEndDTDScanState();
1165                                 return true;
1166                             }
1167                             break;
1168                         }
1169                         case SCANNER_STATE_PROLOG : {
1170                             // skip entity decls
1171                             setEndDTDScanState();
1172                             return true;
1173                         }
1174                         default: {
1175                             throw new XNIException("DTDDriver#dispatch: scanner state="+fScannerState+" ("+getScannerStateName(fScannerState)+')');
1176                         }
1177                     }
1178                 } while (complete || again);
1179             }
1180 
1181             // premature end of file
1182             catch (EOFException e) {
1183                 e.printStackTrace();
1184                 reportFatalError("PrematureEOF", null);
1185                 return false;
1186                 //throw e;
1187             }
1188 
1189             // cleanup
1190             finally {
1191                 fEntityManager.setEntityHandler(XMLDocumentScannerImpl.this);
1192             }
1193 
1194             return true;
1195 
1196         }
1197 
1198         // dispatch(boolean):boolean
1199 
1200     } // class DTDDriver
1201 
1202     /**
1203      * Driver to handle content scanning.
1204      *
1205      * @author Andy Clark, IBM
1206      * @author Eric Ye, IBM
1207      */
1208     protected class ContentDriver
1209             extends FragmentContentDriver {
1210 
1211         //
1212         // Protected methods
1213         //
1214 
1215         // hooks
1216 
1217         // NOTE: These hook methods are added so that the full document
1218         //       scanner can share the majority of code with this class.
1219 
1220         /**
1221          * Scan for DOCTYPE hook. This method is a hook for subclasses
1222          * to add code to handle scanning for a the "DOCTYPE" string
1223          * after the string "<!" has been scanned.
1224          *
1225          * @return True if the "DOCTYPE" was scanned; false if "DOCTYPE"
1226          *          was not scanned.
1227          */
1228         protected boolean scanForDoctypeHook()
1229         throws IOException, XNIException {
1230 
1231             if (fEntityScanner.skipString(DOCTYPE)) {
1232                 setScannerState(SCANNER_STATE_DOCTYPE);
1233                 //                fEntityScanner.markStartOfDTD();
1234                 return true;
1235             }
1236             return false;
1237 
1238         } // scanForDoctypeHook():boolean
1239 
1240         /**
1241          * Element depth iz zero. This methos is a hook for subclasses
1242          * to add code to handle when the element depth hits zero. When
1243          * scanning a document fragment, an element depth of zero is
1244          * normal. However, when scanning a full XML document, the
1245          * scanner must handle the trailing miscellanous section of
1246          * the document after the end of the document's root element.
1247          *
1248          * @return True if the caller should stop and return true which
1249          *          allows the scanner to switch to a new scanning
1250          *          driver. A return value of false indicates that
1251          *          the content driver should continue as normal.
1252          */
1253         protected boolean elementDepthIsZeroHook()
1254         throws IOException, XNIException {
1255 
1256             setScannerState(SCANNER_STATE_TRAILING_MISC);
1257             setDriver(fTrailingMiscDriver);
1258             return true;
1259 
1260         } // elementDepthIsZeroHook():boolean
1261 
1262         /**
1263          * Scan for root element hook. This method is a hook for
1264          * subclasses to add code that handles scanning for the root
1265          * element. When scanning a document fragment, there is no
1266          * "root" element. However, when scanning a full XML document,
1267          * the scanner must handle the root element specially.
1268          *
1269          * @return True if the caller should stop and return true which
1270          *          allows the scanner to switch to a new scanning
1271          *          driver. A return value of false indicates that
1272          *          the content driver should continue as normal.
1273          */
1274         protected boolean scanRootElementHook()
1275         throws IOException, XNIException {
1276 
1277             if (scanStartElement()) {
1278                 setScannerState(SCANNER_STATE_TRAILING_MISC);
1279                 setDriver(fTrailingMiscDriver);
1280                 return true;
1281             }
1282             return false;
1283 
1284         } // scanRootElementHook():boolean
1285 
1286         /**
1287          * End of file hook. This method is a hook for subclasses to
1288          * add code that handles the end of file. The end of file in
1289          * a document fragment is OK if the markup depth is zero.
1290          * However, when scanning a full XML document, an end of file
1291          * is always premature.
1292          */
1293         protected void endOfFileHook(EOFException e)
1294         throws IOException, XNIException {
1295 
1296             reportFatalError("PrematureEOF", null);
1297             // in case continue-after-fatal-error set, should not do this...
1298             //throw e;
1299 
1300         } // endOfFileHook()
1301 
1302         protected void resolveExternalSubsetAndRead()
1303         throws IOException, XNIException {
1304 
1305             fDTDDescription.setValues(null, null, fEntityManager.getCurrentResourceIdentifier().getExpandedSystemId(), null);
1306             fDTDDescription.setRootName(fElementQName.rawname);
1307             XMLInputSource src = fExternalSubsetResolver.getExternalSubset(fDTDDescription);
1308 
1309             if (src != null) {
1310                 fDoctypeName = fElementQName.rawname;
1311                 fDoctypePublicId = src.getPublicId();
1312                 fDoctypeSystemId = src.getSystemId();
1313                 // call document handler
1314                 if (fDocumentHandler != null) {
1315                     // This inserts a doctypeDecl event into the stream though no
1316                     // DOCTYPE existed in the instance document.
1317                     fDocumentHandler.doctypeDecl(fDoctypeName, fDoctypePublicId, fDoctypeSystemId, null);
1318                 }
1319                 try {
1320                     fDTDScanner.setInputSource(src);
1321                     while (fDTDScanner.scanDTDExternalSubset(true));
1322                 } finally {
1323                     fEntityManager.setEntityHandler(XMLDocumentScannerImpl.this);
1324                 }
1325             }
1326         } // resolveExternalSubsetAndRead()
1327 
1328 
1329 
1330     } // class ContentDriver
1331 
1332     /**
1333      * Driver to handle trailing miscellaneous section scanning.
1334      *
1335      * @author Andy Clark, IBM
1336      * @author Eric Ye, IBM
1337      */
1338     protected final class TrailingMiscDriver
1339             implements Driver {
1340 
1341         //
1342         // Driver methods
1343         //
1344         public int next() throws IOException, XNIException{
1345             //this could for cases like <foo/>
1346             //look at scanRootElementHook
1347             if(fEmptyElement){
1348                 fEmptyElement = false;
1349                 return XMLEvent.END_ELEMENT;
1350             }
1351 
1352             try {
1353                 if(fScannerState == SCANNER_STATE_TERMINATED){
1354                     return XMLEvent.END_DOCUMENT ;}
1355                 do {
1356                     switch (fScannerState) {
1357                         case SCANNER_STATE_TRAILING_MISC: {
1358 
1359                             fEntityScanner.skipSpaces();
1360                             //we should have reached the end of the document in
1361                             //most cases.
1362                             if(fScannerState == SCANNER_STATE_TERMINATED ){
1363                                 return XMLEvent.END_DOCUMENT ;
1364                             }
1365                             if (fEntityScanner.skipChar('<')) {
1366                                 setScannerState(SCANNER_STATE_START_OF_MARKUP);
1367                             } else {
1368                                 setScannerState(SCANNER_STATE_CONTENT);
1369                             }
1370                             break;
1371                         }
1372                         case SCANNER_STATE_START_OF_MARKUP: {
1373                             fMarkupDepth++;
1374                             if (fEntityScanner.skipChar('?')) {
1375                                 setScannerState(SCANNER_STATE_PI);
1376                             } else if (fEntityScanner.skipChar('!')) {
1377                                 setScannerState(SCANNER_STATE_COMMENT);
1378                             } else if (fEntityScanner.skipChar('/')) {
1379                                 reportFatalError("MarkupNotRecognizedInMisc",
1380                                         null);
1381                             } else if (XMLChar.isNameStart(fEntityScanner.peekChar())) {
1382                                 reportFatalError("MarkupNotRecognizedInMisc",
1383                                         null);
1384                                 scanStartElement();
1385                                 setScannerState(SCANNER_STATE_CONTENT);
1386                             } else {
1387                                 reportFatalError("MarkupNotRecognizedInMisc",
1388                                         null);
1389                             }
1390                             break;
1391                         }
1392                     }
1393                 }while(fScannerState == SCANNER_STATE_START_OF_MARKUP || fScannerState == SCANNER_STATE_TRAILING_MISC);
1394                 if(DEBUG_NEXT){
1395                     System.out.println("State set by deciding while loop [TrailingMiscellaneous] is = " + getScannerStateName(fScannerState));
1396                 }
1397                 switch (fScannerState){
1398                     case SCANNER_STATE_PI: {
1399                         fContentBuffer.clear();
1400                         scanPI(fContentBuffer);
1401                         setScannerState(SCANNER_STATE_TRAILING_MISC);
1402                         return XMLEvent.PROCESSING_INSTRUCTION ;
1403                     }
1404                     case SCANNER_STATE_COMMENT: {
1405                         if (!fEntityScanner.skipString(COMMENTSTRING)) {
1406                             reportFatalError("InvalidCommentStart", null);
1407                         }
1408                         scanComment();
1409                         setScannerState(SCANNER_STATE_TRAILING_MISC);
1410                         return XMLEvent.COMMENT;
1411                     }
1412                     case SCANNER_STATE_CONTENT: {
1413                         int ch = fEntityScanner.peekChar();
1414                         if (ch == -1) {
1415                             setScannerState(SCANNER_STATE_TERMINATED);
1416                             return XMLEvent.END_DOCUMENT ;
1417                         } else{
1418                             reportFatalError("ContentIllegalInTrailingMisc",
1419                                     null);
1420                             fEntityScanner.scanChar();
1421                             setScannerState(SCANNER_STATE_TRAILING_MISC);
1422                             return XMLEvent.CHARACTERS;
1423                         }
1424 
1425                     }
1426                     case SCANNER_STATE_REFERENCE: {
1427                         reportFatalError("ReferenceIllegalInTrailingMisc",
1428                                 null);
1429                         setScannerState(SCANNER_STATE_TRAILING_MISC);
1430                         return XMLEvent.ENTITY_REFERENCE ;
1431                     }
1432                     case SCANNER_STATE_TERMINATED: {
1433                         //there can't be any element after SCANNER_STATE_TERMINATED or when the parser
1434                         //has reached the end of document
1435                         setScannerState(SCANNER_STATE_NO_SUCH_ELEMENT_EXCEPTION);
1436                         //xxx what to do when the scanner has reached the terminating state.
1437                         return XMLEvent.END_DOCUMENT ;
1438                     }
1439                     case SCANNER_STATE_NO_SUCH_ELEMENT_EXCEPTION:{
1440                         throw new java.util.NoSuchElementException("No more events to be parsed");
1441                     }
1442                     default: throw new XNIException("Scanner State " + fScannerState + " not Recognized ");
1443                 }//switch
1444 
1445             } catch (EOFException e) {
1446                 // NOTE: This is the only place we're allowed to reach
1447                 //       the real end of the document stream. Unless the
1448                 //       end of file was reached prematurely.
1449                 if (fMarkupDepth != 0) {
1450                     reportFatalError("PrematureEOF", null);
1451                     return -1;
1452                     //throw e;
1453                 }
1454                 //System.out.println("EOFException thrown") ;
1455                 setScannerState(SCANNER_STATE_TERMINATED);
1456             }
1457 
1458             return XMLEvent.END_DOCUMENT;
1459 
1460         }//next
1461 
1462     } // class TrailingMiscDriver
1463 
1464     /**
1465      * Implements XMLBufferListener interface.
1466      */
1467 
1468 
1469     /**
1470      * receives callbacks from {@link XMLEntityReader } when buffer
1471      * is being changed.
1472      * @param refreshPosition
1473      */
1474     public void refresh(int refreshPosition){
1475         super.refresh(refreshPosition);
1476         if(fReadingDTD){
1477             Entity entity = fEntityScanner.getCurrentEntity();
1478             if(entity instanceof Entity.ScannedEntity){
1479                 fEndPos=((Entity.ScannedEntity)entity).position;
1480             }
1481             fDTDDecl.append(((Entity.ScannedEntity)entity).ch,fStartPos , fEndPos-fStartPos);
1482             fStartPos = refreshPosition;
1483         }
1484     }
1485 
1486 } // class XMLDocumentScannerImpl