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