1 /*
   2  * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.org.apache.xerces.internal.impl;
  27 
  28 import com.sun.xml.internal.stream.Entity;
  29 import com.sun.xml.internal.stream.StaxErrorReporter;
  30 import com.sun.xml.internal.stream.XMLEntityStorage;
  31 import com.sun.xml.internal.stream.events.EntityDeclarationImpl;
  32 import com.sun.xml.internal.stream.events.NotationDeclarationImpl;
  33 import javax.xml.namespace.NamespaceContext;
  34 import com.sun.org.apache.xerces.internal.xni.XNIException;
  35 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  36 import javax.xml.XMLConstants;
  37 import javax.xml.namespace.QName;
  38 import javax.xml.stream.Location;
  39 import javax.xml.stream.events.XMLEvent;
  40 import com.sun.org.apache.xerces.internal.util.NamespaceContextWrapper;
  41 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  42 import com.sun.xml.internal.stream.dtd.nonvalidating.XMLNotationDecl;
  43 import com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar;
  44 import java.io.BufferedInputStream;
  45 import java.io.BufferedReader;
  46 import java.io.IOException;
  47 import java.io.InputStream;
  48 import java.io.Reader;
  49 import java.util.ArrayList;
  50 import java.util.Enumeration;
  51 import java.util.Iterator;
  52 import java.util.List;
  53 import javax.xml.stream.XMLInputFactory;
  54 import javax.xml.stream.XMLStreamConstants;
  55 import javax.xml.stream.XMLStreamException;
  56 import com.sun.org.apache.xerces.internal.util.XMLChar;
  57 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
  58 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
  59 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  60 
  61 /** This class implements javax.xml.stream.XMLStreamReader. It makes use of XML*Scanner classes to
  62  * derive most of its functionality. If desired, Application can reuse this instance by calling
  63  * reset() and setInputSource().
  64  *
  65  * @author Neeraj Bajaj Sun Microsystems,Inc.
  66  * @author K.Venugopal Sun Microsystems,Inc.
  67  * @author Sunitha Reddy Sun Microsystems,Inc.
  68  */
  69 public class XMLStreamReaderImpl implements javax.xml.stream.XMLStreamReader {
  70 
  71     /** Property identifier: entity manager. */
  72     protected static final String ENTITY_MANAGER =
  73     Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
  74 
  75     /** Property identifier: Error Reporter. */
  76     protected static final String ERROR_REPORTER =
  77     Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
  78 
  79     /** Property identifier: Symbol table. */
  80     protected static final String SYMBOL_TABLE =
  81     Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
  82 
  83     protected static final String READER_IN_DEFINED_STATE =
  84     Constants.READER_IN_DEFINED_STATE;
  85 
  86     private SymbolTable fSymbolTable = new SymbolTable();
  87 
  88     /** Document scanner. */
  89     protected XMLDocumentScannerImpl fScanner = new XMLNSDocumentScannerImpl();
  90 
  91     //make Global NamespaceContextWrapper object,  fScanner.getNamespaceContext() is dynamic object and ita value changes
  92     //as per the state of the parser.
  93     protected NamespaceContextWrapper fNamespaceContextWrapper = new NamespaceContextWrapper((NamespaceSupport)fScanner.getNamespaceContext()) ;
  94     protected XMLEntityManager fEntityManager = new XMLEntityManager();
  95     protected StaxErrorReporter fErrorReporter = new StaxErrorReporter();
  96 
  97 
  98     /** Entity scanner, this alwasy works on last entity that was opened. */
  99     protected XMLEntityScanner fEntityScanner = null;
 100 
 101     /** Input Source */
 102     protected XMLInputSource fInputSource = null;
 103     /** Store properties*/
 104     protected PropertyManager fPropertyManager = null ;
 105 
 106     /** current event type */
 107     private int fEventType ;
 108     /** debug flag*/
 109     static final boolean DEBUG = false ;
 110     /** more to scan */
 111     private boolean fReuse = true;
 112     private boolean fReaderInDefinedState = true ;
 113     private boolean fBindNamespaces = true;
 114     private String fDTDDecl = null;
 115     private String versionStr = null;
 116 
 117     /**
 118      * @param inputStream
 119      * @param props
 120      * @throws XMLStreamException
 121      */
 122     public XMLStreamReaderImpl(InputStream inputStream, PropertyManager props) throws  XMLStreamException {
 123         init(props);
 124         //publicId, systemid, baseSystemId, inputStream, enocding
 125         XMLInputSource inputSource = new XMLInputSource(null,null,null,inputStream,null);
 126         //pass the input source to document scanner impl.
 127         setInputSource(inputSource);
 128     }
 129 
 130     public XMLDocumentScannerImpl getScanner(){
 131         System.out.println("returning scanner");
 132         return fScanner;
 133     }
 134     /**
 135      * @param systemid
 136      * @param props
 137      * @throws XMLStreamException
 138      */
 139     public XMLStreamReaderImpl(String systemid, PropertyManager props) throws  XMLStreamException {
 140         init(props);
 141         //publicId, systemid, baseSystemId, inputStream, enocding
 142         XMLInputSource inputSource = new XMLInputSource(null, systemid, null, false);
 143         //pass the input source to document scanner impl.
 144         setInputSource(inputSource);
 145     }
 146 
 147 
 148     /**
 149      * @param inputStream
 150      * @param encoding
 151      * @param props
 152      * @throws XMLStreamException
 153      */
 154     public XMLStreamReaderImpl(InputStream inputStream, String encoding, PropertyManager props ) throws  XMLStreamException {
 155         init(props);
 156         //publicId, systemid, baseSystemId, inputStream, enocding
 157         XMLInputSource inputSource = new XMLInputSource(null,null,null, new BufferedInputStream(inputStream),encoding );
 158         //pass the input source to document scanner impl.
 159         setInputSource(inputSource);
 160     }
 161 
 162     /**
 163      * @param reader
 164      * @param props
 165      * @throws XMLStreamException
 166      */
 167     public XMLStreamReaderImpl(Reader reader, PropertyManager props) throws  XMLStreamException {
 168         init(props);
 169         //publicId, systemid, baseSystemId, inputStream, enocding
 170         //xxx: Using buffered reader
 171         XMLInputSource inputSource = new XMLInputSource(null,null,null,new BufferedReader(reader),null);
 172         //pass the input source to document scanner impl.
 173         setInputSource(inputSource);
 174     }
 175 
 176     /**
 177      * @param inputSource
 178      * @param props
 179      * @throws XMLStreamException
 180      */
 181     public XMLStreamReaderImpl(XMLInputSource inputSource, PropertyManager props) throws  XMLStreamException {
 182         init(props);
 183         //pass the input source to document scanner impl.
 184         setInputSource(inputSource);
 185     }
 186 
 187     /**
 188      * @param inputSource
 189      * @throws XMLStreamException
 190      */
 191     public void setInputSource(XMLInputSource inputSource ) throws XMLStreamException {
 192         //once setInputSource() is called this instance is busy parsing the inputsource supplied
 193         //this instances is free for reuse if parser has reached END_DOCUMENT state or application has
 194         //called close()
 195         fReuse = false;
 196 
 197         try{
 198 
 199             fScanner.setInputSource(inputSource) ;
 200             //XMLStreamReader should be in defined state
 201             if(fReaderInDefinedState){
 202                 fEventType = fScanner.next();
 203                 if (versionStr == null)
 204                     versionStr = getVersion();
 205 
 206                 if (fEventType == XMLStreamConstants.START_DOCUMENT && versionStr != null && versionStr.equals("1.1")){
 207                     switchToXML11Scanner();
 208                 }
 209 
 210             }
 211         }catch(java.io.IOException ex){
 212             throw new XMLStreamException(ex);
 213         } catch(XNIException ex){ //Issue 56 XNIException not caught
 214             throw new XMLStreamException(ex.getMessage(), getLocation(), ex.getException());
 215         }
 216     }//setInputSource
 217 
 218     void init(PropertyManager propertyManager) throws XMLStreamException {
 219         fPropertyManager = propertyManager;
 220         //set Stax internal properties -- Note that these instances are being created in XMLReaderImpl.
 221         //1.SymbolTable
 222         //2.XMLMessageFormatter
 223         //3.XMLEntityManager
 224         //4. call reset()
 225         //1.
 226         propertyManager.setProperty(SYMBOL_TABLE,  fSymbolTable ) ;
 227         //2.
 228         propertyManager.setProperty(ERROR_REPORTER,  fErrorReporter ) ;
 229         //3.
 230         propertyManager.setProperty(ENTITY_MANAGER, fEntityManager);
 231         //4.
 232         reset();
 233     }
 234 
 235     /** This function tells if this instances is available for reuse.
 236      * One must call reset() and setInputSource() to be able to reuse
 237      * this instance.
 238      */
 239     public boolean canReuse(){
 240         if(DEBUG){
 241             System.out.println("fReuse = " + fReuse);
 242             System.out.println("fEventType = " + getEventTypeString(fEventType) );
 243         }
 244         //when parsing begins, fReuse is set to false
 245         //fReuse is set to 'true' when application calls close()
 246         return fReuse;
 247     }
 248 
 249     /**
 250      * Resets this instance so that this instance is ready for reuse.
 251      */
 252     public void reset(){
 253         fReuse = true;
 254         fEventType = 0 ;
 255         //reset entity manager
 256         fEntityManager.reset(fPropertyManager);
 257         //reset the scanner
 258         fScanner.reset(fPropertyManager);
 259         //REVISIT:this is too ugly -- we are getting XMLEntityManager and XMLEntityReader from
 260         //property manager, it should be only XMLEntityManager
 261         fDTDDecl = null;
 262         fEntityScanner = (XMLEntityScanner)fEntityManager.getEntityScanner()  ;
 263         //default value for this property is true. However, this should be false when using XMLEventReader... Ugh..
 264         //because XMLEventReader should not have defined state.
 265         fReaderInDefinedState = ((Boolean)fPropertyManager.getProperty(READER_IN_DEFINED_STATE)).booleanValue();
 266         fBindNamespaces = ((Boolean)fPropertyManager.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue();
 267         versionStr = null;
 268     }
 269 
 270 
 271     /** Frees any resources associated with this Reader. This method does not close the underlying input source.
 272      * @throws XMLStreamException if there are errors freeing associated resources
 273      */
 274     public void close() throws XMLStreamException {
 275         //xxx: Check what this function is intended to do.
 276         //reset();
 277         fReuse = true ;
 278     }
 279 
 280 
 281     /** Returns the character encoding declared on the xml declaration Returns null if none was declared
 282      * @return the encoding declared in the document or null
 283      */
 284     public String getCharacterEncodingScheme() {
 285         return fScanner.getCharacterEncodingScheme();
 286 
 287     }
 288 
 289 
 290     /**
 291      * @return
 292      */
 293     public int getColumnNumber() {
 294         return fEntityScanner.getColumnNumber();
 295     }//getColumnNumber
 296 
 297     /** Return input encoding if known or null if unknown.
 298      * @return the encoding of this instance or null
 299      */
 300     public String getEncoding() {
 301         return fEntityScanner.getEncoding();
 302     }//getEncoding
 303 
 304     /** Returns the current value of the parse event as a string, this returns the string value of a CHARACTERS event, returns the value of a COMMENT, the replacement value for an ENTITY_REFERENCE, the string value of a CDATA section, the string value for a SPACE event, or the String value of the internal subset of the DTD. If an ENTITY_REFERENCE has been resolved, any character data will be reported as CHARACTERS events.
 305      * @return the current text or null
 306      */
 307     public int getEventType() {
 308         return fEventType ;
 309     }//getEventType
 310 
 311     /**
 312      * @return
 313      */
 314     public int getLineNumber() {
 315         return fEntityScanner.getLineNumber() ;
 316     }//getLineNumber
 317 
 318     public String getLocalName() {
 319         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT){
 320             //xxx check whats the value of fCurrentElement
 321             return fScanner.getElementQName().localpart ;
 322         }
 323         else if(fEventType == XMLEvent.ENTITY_REFERENCE){
 324             return fScanner.getEntityName();
 325         }
 326         throw new IllegalStateException("Method getLocalName() cannot be called for " +
 327             getEventTypeString(fEventType) + " event.");
 328     }//getLocalName()
 329 
 330     /**
 331      * @return
 332      */
 333     public String getNamespaceURI() {
 334         //doesn't take care of Attribute as separte event
 335         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT){
 336             return fScanner.getElementQName().uri ;
 337         }
 338         return null ;
 339     }//getNamespaceURI
 340 
 341     /** Get the data section of a processing instruction
 342      * @return the data or null
 343      */
 344 
 345     public String getPIData() {
 346         if( fEventType == XMLEvent.PROCESSING_INSTRUCTION){
 347             return fScanner.getPIData().toString();
 348         }
 349         else throw new java.lang.IllegalStateException("Current state of the parser is " + getEventTypeString(fEventType) +
 350         " But Expected state is " + XMLEvent.PROCESSING_INSTRUCTION  ) ;
 351     }//getPIData
 352 
 353 
 354     /** Get the target of a processing instruction
 355      * @return the target or null
 356      */
 357     public String getPITarget() {
 358         if( fEventType == XMLEvent.PROCESSING_INSTRUCTION){
 359             return fScanner.getPITarget();
 360         }
 361         else throw new java.lang.IllegalStateException("Current state of the parser is " + getEventTypeString(fEventType) +
 362         " But Expected state is " + XMLEvent.PROCESSING_INSTRUCTION  ) ;
 363 
 364     }//getPITarget
 365 
 366 
 367     /**
 368     * @return the prefix of the current event, or null if the event does
 369     * not have a prefix. For START_ELEMENT and END_ELEMENT, return
 370     * XMLConstants.DEFAULT_NS_PREFIX when no prefix is available.
 371     */
 372     public String getPrefix() {
 373         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT){
 374             String prefix = fScanner.getElementQName().prefix;
 375             return prefix == null ? XMLConstants.DEFAULT_NS_PREFIX : prefix;
 376         }
 377         return null ;
 378     }//getPrefix()
 379 
 380 
 381 
 382     /**
 383      * @return
 384      */
 385     public char[] getTextCharacters() {
 386         if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
 387                  || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE){
 388              return fScanner.getCharacterData().ch;
 389          } else{
 390              throw new IllegalStateException("Current state = " + getEventTypeString(fEventType)
 391              + " is not among the states " + getEventTypeString(XMLEvent.CHARACTERS) + " , "
 392                      + getEventTypeString(XMLEvent.COMMENT) + " , " + getEventTypeString(XMLEvent.CDATA)
 393                      + " , " + getEventTypeString(XMLEvent.SPACE) +" valid for getTextCharacters() " ) ;
 394          }
 395     }
 396 
 397     /**
 398      * @return
 399      */
 400     public int getTextLength() {
 401         if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
 402                  || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE){
 403              return fScanner.getCharacterData().length;
 404          } else{
 405              throw new IllegalStateException("Current state = " + getEventTypeString(fEventType)
 406              + " is not among the states " + getEventTypeString(XMLEvent.CHARACTERS) + " , "
 407                      + getEventTypeString(XMLEvent.COMMENT) + " , " + getEventTypeString(XMLEvent.CDATA)
 408                      + " , " + getEventTypeString(XMLEvent.SPACE) +" valid for getTextLength() " ) ;
 409          }
 410 
 411    }
 412 
 413     /**
 414      * @return
 415      */
 416     public int getTextStart() {
 417         if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE){
 418              return  fScanner.getCharacterData().offset;
 419          } else{
 420              throw new IllegalStateException("Current state = " + getEventTypeString(fEventType)
 421              + " is not among the states " + getEventTypeString(XMLEvent.CHARACTERS) + " , "
 422                      + getEventTypeString(XMLEvent.COMMENT) + " , " + getEventTypeString(XMLEvent.CDATA)
 423                      + " , " + getEventTypeString(XMLEvent.SPACE) +" valid for getTextStart() " ) ;
 424          }
 425     }
 426 
 427     /**
 428      * @return
 429      */
 430     public String getValue() {
 431         if(fEventType == XMLEvent.PROCESSING_INSTRUCTION){
 432             return fScanner.getPIData().toString();
 433         } else if(fEventType == XMLEvent.COMMENT){
 434             return fScanner.getComment();
 435         } else if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT){
 436             return fScanner.getElementQName().localpart ;
 437         } else if(fEventType == XMLEvent.CHARACTERS){
 438             return fScanner.getCharacterData().toString();
 439         }
 440         return null;
 441     }//getValue()
 442 
 443     /** Get the XML language version of the current document being parsed */
 444     public String getVersion() {
 445         //apply SAP's patch: the default version in the scanner was set to 1.0 because of DOM and SAX
 446         //so this patch is a workaround of the difference between StAX and DOM
 447         // SAPJVM: Return null if the XML version has not been declared (as specified in the JavaDoc).
 448 
 449         String version = fEntityScanner.getXMLVersion();
 450 
 451         return "1.0".equals(version) && !fEntityScanner.xmlVersionSetExplicitly ? null : version;
 452     }
 453 
 454     /**
 455      * @return
 456      */
 457     public boolean hasAttributes() {
 458         return fScanner.getAttributeIterator().getLength() > 0 ? true : false ;
 459     }
 460 
 461     /** this Funtion returns true if the current event has name */
 462     public boolean hasName() {
 463         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT) {
 464             return true;
 465         }  else {
 466             return false;
 467         }
 468     }//hasName()
 469 
 470     /**
 471      * @throws XMLStreamException
 472      * @return
 473      */
 474     public boolean hasNext() throws XMLStreamException {
 475         //the scanner returns -1 when it detects a broken stream
 476         if (fEventType == -1) return false;
 477         //we can check in scanners if the scanner state is not set to
 478         //terminating, we still have more events.
 479         return fEventType != XMLEvent.END_DOCUMENT;
 480     }
 481 
 482     /**
 483      * @return
 484      */
 485     public boolean hasValue() {
 486         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT
 487         || fEventType == XMLEvent.ENTITY_REFERENCE || fEventType == XMLEvent.PROCESSING_INSTRUCTION
 488         || fEventType == XMLEvent.COMMENT || fEventType == XMLEvent.CHARACTERS) {
 489             return true;
 490         } else {
 491             return false;
 492         }
 493 
 494     }
 495 
 496     /**
 497      * @return
 498      */
 499     public boolean isEndElement() {
 500         return fEventType == XMLEvent.END_ELEMENT;
 501     }
 502 
 503     /**
 504      * @return
 505      */
 506     public boolean isStandalone() {
 507         return fScanner.isStandAlone();
 508     }
 509 
 510     /**
 511      * @return
 512      */
 513     public boolean isStartElement() {
 514         return fEventType == XMLEvent.START_ELEMENT;
 515     }
 516 
 517     /**
 518      *  Returns true if the cursor points to a character data event that consists of all whitespace
 519      *  Application calling this method needs to cache the value and avoid calling this method again
 520      *  for the same event.
 521      * @return
 522      */
 523     public boolean isWhiteSpace() {
 524         if(isCharacters() || (fEventType == XMLStreamConstants.CDATA)){
 525             char [] ch = this.getTextCharacters();
 526             final int start = this.getTextStart();
 527             final int end = start + this.getTextLength();
 528             for (int i = start; i < end; i++){
 529                 if(!XMLChar.isSpace(ch[i])){
 530                     return false;
 531                 }
 532             }
 533             return true;
 534         }
 535         return false;
 536     }
 537 
 538 
 539 
 540     /**
 541      * @throws XMLStreamException
 542      * @return
 543      */
 544     public int next() throws XMLStreamException {
 545         if( !hasNext() ) {
 546             if (fEventType != -1) {
 547                 throw new java.util.NoSuchElementException( "END_DOCUMENT reached: no more elements on the stream." );
 548             } else {
 549                 throw new XMLStreamException( "Error processing input source. The input stream is not complete." );
 550             }
 551         }
 552         try {
 553             fEventType = fScanner.next();
 554 
 555             if (versionStr == null) {
 556                 versionStr = getVersion();
 557             }
 558 
 559             if (fEventType == XMLStreamConstants.START_DOCUMENT
 560                     && versionStr != null
 561                     && versionStr.equals("1.1")) {
 562                 switchToXML11Scanner();
 563             }
 564 
 565             return fEventType;
 566         } catch (IOException ex) {
 567             // if this error occured trying to resolve the external DTD subset
 568             // and IS_VALIDATING == false, then this is not an XML error
 569             if (fScanner.fScannerState == fScanner.SCANNER_STATE_DTD_EXTERNAL) {
 570                 Boolean isValidating = (Boolean) fPropertyManager.getProperty(
 571                         XMLInputFactory.IS_VALIDATING);
 572                 if (isValidating != null
 573                         && !isValidating.booleanValue()) {
 574                     // ignore the error, set scanner to known state
 575                     fEventType = XMLEvent.DTD;
 576                     fScanner.setScannerState(fScanner.SCANNER_STATE_PROLOG);
 577                     fScanner.setDriver(fScanner.fPrologDriver);
 578                     if (fDTDDecl == null
 579                             || fDTDDecl.length() == 0) {
 580                         fDTDDecl = "<!-- "
 581                                 + "Exception scanning External DTD Subset.  "
 582                                 + "True contents of DTD cannot be determined.  "
 583                                 + "Processing will continue as XMLInputFactory.IS_VALIDATING == false."
 584                                 + " -->";
 585                     }
 586                     return XMLEvent.DTD;
 587                 }
 588             }
 589 
 590             // else real error
 591             throw new XMLStreamException(ex.getMessage(), getLocation(), ex);
 592         } catch (XNIException ex) {
 593             throw new XMLStreamException(
 594                     ex.getMessage(),
 595                     getLocation(),
 596                     ex.getException());
 597         }
 598     } //next()
 599 
 600     private void switchToXML11Scanner() throws IOException{
 601 
 602         int oldEntityDepth = fScanner.fEntityDepth;
 603         com.sun.org.apache.xerces.internal.xni.NamespaceContext oldNamespaceContext = fScanner.fNamespaceContext;
 604 
 605         fScanner = new XML11NSDocumentScannerImpl();
 606 
 607         //get the new scanner state to old scanner's previous state
 608         fScanner.reset(fPropertyManager);
 609         fScanner.setPropertyManager(fPropertyManager);
 610         fEntityScanner = (XMLEntityScanner)fEntityManager.getEntityScanner()  ;
 611         fEntityManager.fCurrentEntity.mayReadChunks = true;
 612         fScanner.setScannerState(XMLEvent.START_DOCUMENT);
 613 
 614         fScanner.fEntityDepth = oldEntityDepth;
 615         fScanner.fNamespaceContext = oldNamespaceContext;
 616         fEventType = fScanner.next();
 617     }
 618 
 619 
 620 
 621     final static String getEventTypeString(int eventType) {
 622         switch (eventType){
 623             case XMLEvent.START_ELEMENT:
 624                 return "START_ELEMENT";
 625             case XMLEvent.END_ELEMENT:
 626                 return "END_ELEMENT";
 627             case XMLEvent.PROCESSING_INSTRUCTION:
 628                 return "PROCESSING_INSTRUCTION";
 629             case XMLEvent.CHARACTERS:
 630                 return "CHARACTERS";
 631             case XMLEvent.COMMENT:
 632                 return "COMMENT";
 633             case XMLEvent.START_DOCUMENT:
 634                 return "START_DOCUMENT";
 635             case XMLEvent.END_DOCUMENT:
 636                 return "END_DOCUMENT";
 637             case XMLEvent.ENTITY_REFERENCE:
 638                 return "ENTITY_REFERENCE";
 639             case XMLEvent.ATTRIBUTE:
 640                 return "ATTRIBUTE";
 641             case XMLEvent.DTD:
 642                 return "DTD";
 643             case XMLEvent.CDATA:
 644                 return "CDATA";
 645             case XMLEvent.SPACE:
 646                 return "SPACE";
 647         }
 648         return "UNKNOWN_EVENT_TYPE, " + String.valueOf(eventType);
 649     }
 650 
 651     /** Returns the count of attributes on this START_ELEMENT,
 652      * this method is only valid on a START_ELEMENT or ATTRIBUTE.  This
 653      * count excludes namespace definitions.  Attribute indices are
 654      * zero-based.
 655      * @return returns the number of attributes
 656      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 657      */
 658     public int getAttributeCount() {
 659         //xxx: recognize SAX properties namespace, namespace-prefix to get XML Namespace declarations
 660         //does length includes namespace declarations ?
 661 
 662         //State should be either START_ELEMENT or ATTRIBUTE
 663         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 664             return fScanner.getAttributeIterator().getLength() ;
 665         } else{
 666             throw new java.lang.IllegalStateException( "Current state is not among the states "
 667                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 668                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 669                      + "valid for getAttributeCount()") ;
 670         }
 671     }//getAttributeCount
 672 
 673     /** Returns the localName of the attribute at the provided
 674      * index
 675      * @param index the position of the attribute
 676      * @return the localName of the attribute
 677      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 678      */
 679     public QName getAttributeName(int index) {
 680         //State should be either START_ELEMENT or ATTRIBUTE
 681         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 682             return convertXNIQNametoJavaxQName(fScanner.getAttributeIterator().getQualifiedName(index)) ;
 683         } else{
 684             throw new java.lang.IllegalStateException("Current state is not among the states "
 685                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 686                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 687                      + "valid for getAttributeName()") ;
 688         }
 689     }//getAttributeName
 690 
 691     /**
 692      * @param index
 693      * @return
 694      */
 695     public String getAttributeLocalName(int index) {
 696         //State should be either START_ELEMENT or ATTRIBUTE
 697         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 698             return fScanner.getAttributeIterator().getLocalName(index) ;
 699         } else{
 700             throw new java.lang.IllegalStateException() ;
 701         }
 702     }//getAttributeName
 703 
 704     /** Returns the namespace of the attribute at the provided
 705      * index
 706      * @param index the position of the attribute
 707      * @return the namespace URI (can be null)
 708      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 709      */
 710     public String getAttributeNamespace(int index) {
 711         //State should be either START_ELEMENT or ATTRIBUTE
 712         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 713             return fScanner.getAttributeIterator().getURI(index);
 714         } else{
 715             throw new java.lang.IllegalStateException("Current state is not among the states "
 716                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 717                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 718                      + "valid for getAttributeNamespace()") ;
 719         }
 720 
 721     }//getAttributeNamespace
 722 
 723     /** Returns the prefix of this attribute at the
 724      * provided index
 725      * @param index the position of the attribute
 726      * @return the prefix of the attribute
 727      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 728      */
 729     public String getAttributePrefix(int index) {
 730         //State should be either START_ELEMENT or ATTRIBUTE
 731         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 732             return fScanner.getAttributeIterator().getPrefix(index);
 733         } else{
 734             throw new java.lang.IllegalStateException("Current state is not among the states "
 735                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 736                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 737                      + "valid for getAttributePrefix()") ;
 738         }
 739     }//getAttributePrefix
 740 
 741     /** Returns the qname of the attribute at the provided index
 742      *
 743      * @param index the position of the attribute
 744      * @return the QName of the attribute
 745      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 746      */
 747     public javax.xml.namespace.QName getAttributeQName(int index) {
 748         //State should be either START_ELEMENT or ATTRIBUTE
 749         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 750             // create new object at runtime..
 751             String localName = fScanner.getAttributeIterator().getLocalName(index) ;
 752             String uri = fScanner.getAttributeIterator().getURI(index) ;
 753             return new javax.xml.namespace.QName(uri, localName) ;
 754         } else{
 755             throw new java.lang.IllegalStateException("Current state is not among the states "
 756                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 757                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 758                      + "valid for getAttributeQName()") ;
 759         }
 760     }//getAttributeQName
 761 
 762     /** Returns the XML type of the attribute at the provided
 763      * index
 764      * @param index the position of the attribute
 765      * @return the XML type of the attribute
 766      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 767      */
 768     public String getAttributeType(int index) {
 769         //State should be either START_ELEMENT or ATTRIBUTE
 770         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 771             return fScanner.getAttributeIterator().getType(index) ;
 772         } else{
 773             throw new java.lang.IllegalStateException("Current state is not among the states "
 774                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 775                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 776                      + "valid for getAttributeType()") ;
 777         }
 778 
 779     }//getAttributeType
 780 
 781     /** Returns the value of the attribute at the
 782      * index
 783      * @param index the position of the attribute
 784      * @return the attribute value
 785      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 786      */
 787     public String getAttributeValue(int index) {
 788         //State should be either START_ELEMENT or ATTRIBUTE
 789         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 790             return fScanner.getAttributeIterator().getValue(index) ;
 791         } else{
 792             throw new java.lang.IllegalStateException("Current state is not among the states "
 793                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 794                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 795                      + "valid for getAttributeValue()") ;
 796         }
 797 
 798     }//getAttributeValue
 799 
 800     /**
 801      * @param namespaceURI
 802      * @param localName
 803      * @return
 804      */
 805     public String getAttributeValue(String namespaceURI, String localName) {
 806         //State should be either START_ELEMENT or ATTRIBUTE
 807         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 808             XMLAttributesImpl attributes = fScanner.getAttributeIterator();
 809             if (namespaceURI == null) { //sjsxp issue 70
 810                 return attributes.getValue(attributes.getIndexByLocalName(localName)) ;
 811             } else {
 812                 return fScanner.getAttributeIterator().getValue(
 813                         namespaceURI.length() == 0 ? null : namespaceURI, localName) ;
 814             }
 815 
 816         } else{
 817             throw new java.lang.IllegalStateException("Current state is not among the states "
 818                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 819                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 820                      + "valid for getAttributeValue()") ;
 821         }
 822 
 823     }
 824 
 825     /** Reads the content of a text-only element. Precondition:
 826      * the current event is START_ELEMENT. Postcondition:
 827      * The current event is the corresponding END_ELEMENT.
 828      * @throws XMLStreamException if the current event is not a START_ELEMENT or if
 829      * a non text element is encountered
 830      */
 831     public String getElementText() throws XMLStreamException {
 832 
 833         if(getEventType() != XMLStreamConstants.START_ELEMENT) {
 834             throw new XMLStreamException(
 835             "parser must be on START_ELEMENT to read next text", getLocation());
 836         }
 837         int eventType = next();
 838         StringBuffer content = new StringBuffer();
 839         while(eventType != XMLStreamConstants.END_ELEMENT ) {
 840             if(eventType == XMLStreamConstants.CHARACTERS
 841             || eventType == XMLStreamConstants.CDATA
 842             || eventType == XMLStreamConstants.SPACE
 843             || eventType == XMLStreamConstants.ENTITY_REFERENCE) {
 844                 content.append(getText());
 845             } else if(eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
 846             || eventType == XMLStreamConstants.COMMENT) {
 847                 // skipping
 848             } else if(eventType == XMLStreamConstants.END_DOCUMENT) {
 849                 throw new XMLStreamException("unexpected end of document when reading element text content");
 850             } else if(eventType == XMLStreamConstants.START_ELEMENT) {
 851                 throw new XMLStreamException(
 852                 "elementGetText() function expects text only elment but START_ELEMENT was encountered.", getLocation());
 853             } else {
 854                 throw new XMLStreamException(
 855                 "Unexpected event type "+ eventType, getLocation());
 856             }
 857             eventType = next();
 858         }
 859         return content.toString();
 860     }
 861 
 862     /** Return the current location of the processor.
 863      * If the Location is unknown the processor should return
 864      * an implementation of Location that returns -1 for the
 865      * location and null for the publicId and systemId.
 866      * The location information is only valid until next() is
 867      * called.
 868      */
 869     public Location getLocation() {
 870         return new Location() {
 871             String _systemId = fEntityScanner.getExpandedSystemId();
 872             String _publicId = fEntityScanner.getPublicId();
 873             int _offset = fEntityScanner.getCharacterOffset();
 874             int _columnNumber = fEntityScanner.getColumnNumber();
 875             int _lineNumber = fEntityScanner.getLineNumber();
 876             public String getLocationURI(){
 877                 return _systemId;
 878             }
 879 
 880             public int getCharacterOffset(){
 881                 return _offset;
 882             }
 883 
 884             public int getColumnNumber() {
 885                 return _columnNumber;
 886             }
 887 
 888             public int getLineNumber(){
 889                 return _lineNumber;
 890             }
 891 
 892             public String getPublicId(){
 893                 return _publicId;
 894             }
 895 
 896             public String getSystemId(){
 897                 return _systemId;
 898             }
 899 
 900             public String toString(){
 901                 StringBuffer sbuffer = new StringBuffer() ;
 902                 sbuffer.append("Line number = " + getLineNumber());
 903                 sbuffer.append("\n") ;
 904                 sbuffer.append("Column number = " + getColumnNumber());
 905                 sbuffer.append("\n") ;
 906                 sbuffer.append("System Id = " + getSystemId());
 907                 sbuffer.append("\n") ;
 908                 sbuffer.append("Public Id = " + getPublicId());
 909                 sbuffer.append("\n") ;
 910                 sbuffer.append("Location Uri= " + getLocationURI());
 911                 sbuffer.append("\n") ;
 912                 sbuffer.append("CharacterOffset = " + getCharacterOffset());
 913                 sbuffer.append("\n") ;
 914                 return sbuffer.toString();
 915             }
 916         } ;
 917 
 918     }
 919 
 920     /** Returns a QName for the current START_ELEMENT or END_ELEMENT event
 921      * @return the QName for the current START_ELEMENT or END_ELEMENT event
 922      */
 923     public javax.xml.namespace.QName getName() {
 924         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT)
 925             return convertXNIQNametoJavaxQName(fScanner.getElementQName());
 926         else
 927             throw new java.lang.IllegalStateException("Illegal to call getName() "+
 928             "when event type is "+ getEventTypeString(fEventType) + "."
 929                      + " Valid states are " + getEventTypeString(XMLEvent.START_ELEMENT) + ", "
 930                      + getEventTypeString(XMLEvent.END_ELEMENT));
 931     }
 932 
 933     /** Returns a read only namespace context for the current
 934      * position.  The context is transient and only valid until
 935      * a call to next() changes the state of the reader.
 936      * @return return a namespace context
 937      */
 938     public NamespaceContext getNamespaceContext() {
 939         return fNamespaceContextWrapper ;
 940     }
 941 
 942     /** Returns the count of namespaces declared on this START_ELEMENT or END_ELEMENT,
 943      * this method is only valid on a START_ELEMENT, END_ELEMENT or NAMESPACE. On
 944      * an END_ELEMENT the count is of the namespaces that are about to go
 945      * out of scope.  This is the equivalent of the information reported
 946      * by SAX callback for an end element event.
 947      * @return returns the number of namespace declarations on this specific element
 948      * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT or NAMESPACE
 949      */
 950     public int getNamespaceCount() {
 951         //namespaceContext is dynamic object.
 952         //REVISIT: check if it specifies all conditions mentioned in the javadoc
 953         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT || fEventType == XMLEvent.NAMESPACE){
 954             return fScanner.getNamespaceContext().getDeclaredPrefixCount() ;
 955         } else{
 956             throw new IllegalStateException("Current event state is " + getEventTypeString(fEventType)
 957              + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
 958              + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
 959                      + getEventTypeString(XMLEvent.NAMESPACE)
 960              + " valid for getNamespaceCount()." );
 961         }
 962     }
 963 
 964     /** Returns the prefix for the namespace declared at the
 965      * index.  Returns null if this is the default namespace
 966      * declaration
 967      *
 968      * @param index the position of the namespace declaration
 969      * @return returns the namespace prefix
 970      * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT or NAMESPACE
 971      */
 972     public String getNamespacePrefix(int index) {
 973         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT || fEventType == XMLEvent.NAMESPACE){
 974             //namespaceContext is dynamic object.
 975             String prefix = fScanner.getNamespaceContext().getDeclaredPrefixAt(index) ;
 976             return prefix.equals("") ? null : prefix ;
 977         }
 978         else{
 979             throw new IllegalStateException("Current state " + getEventTypeString(fEventType)
 980              + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
 981              + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
 982                      + getEventTypeString(XMLEvent.NAMESPACE)
 983              + " valid for getNamespacePrefix()." );
 984         }
 985     }
 986 
 987     /** Returns the uri for the namespace declared at the
 988      * index.
 989      *
 990      * @param index the position of the namespace declaration
 991      * @return returns the namespace uri
 992      * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT or NAMESPACE
 993      */
 994     public String getNamespaceURI(int index) {
 995         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT || fEventType == XMLEvent.NAMESPACE){
 996             //namespaceContext is dynamic object.
 997             return fScanner.getNamespaceContext().getURI(fScanner.getNamespaceContext().getDeclaredPrefixAt(index));
 998         }
 999         else{
1000             throw new IllegalStateException("Current state " + getEventTypeString(fEventType)
1001              + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
1002              + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
1003                      + getEventTypeString(XMLEvent.NAMESPACE)
1004              + " valid for getNamespaceURI()." );
1005         }
1006 
1007     }
1008 
1009     /** Get the value of a feature/property from the underlying implementation
1010      * @param name The name of the property, may not be null
1011      * @return The value of the property
1012      * @throws IllegalArgumentException if name is null
1013      */
1014     public Object getProperty(java.lang.String name) throws java.lang.IllegalArgumentException {
1015         if(name == null) throw new java.lang.IllegalArgumentException() ;
1016         if (fPropertyManager != null ){
1017             if(name.equals(fPropertyManager.STAX_NOTATIONS)){
1018                 return getNotationDecls();
1019             }else if(name.equals(fPropertyManager.STAX_ENTITIES)){
1020                 return getEntityDecls();
1021             }else
1022                 return fPropertyManager.getProperty(name);
1023         }
1024         return null;
1025     }
1026 
1027     /** Returns the current value of the parse event as a string,
1028      * this returns the string value of a CHARACTERS event,
1029      * returns the value of a COMMENT, the replacement value
1030      * for an ENTITY_REFERENCE,
1031      * or the String value of the DTD
1032      * @return the current text or null
1033      * @throws java.lang.IllegalStateException if this state is not
1034      * a valid text state.
1035      */
1036     public String getText() {
1037         if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
1038                 || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE){
1039             //this requires creation of new string
1040             //fEventType == XMLEvent.ENTITY_REFERENCE
1041             return fScanner.getCharacterData().toString() ;
1042         } else if(fEventType == XMLEvent.ENTITY_REFERENCE){
1043             String name = fScanner.getEntityName();
1044             if(name != null){
1045                 if(fScanner.foundBuiltInRefs)
1046                     return fScanner.getCharacterData().toString();
1047 
1048                 XMLEntityStorage entityStore = fEntityManager.getEntityStore();
1049                 Entity en = entityStore.getEntity(name);
1050                 if(en == null)
1051                     return null;
1052                 if(en.isExternal())
1053                     return ((Entity.ExternalEntity)en).entityLocation.getExpandedSystemId();
1054                 else
1055                     return ((Entity.InternalEntity)en).text;
1056             }else
1057                 return null;
1058         }
1059         else if(fEventType == XMLEvent.DTD){
1060                 if(fDTDDecl != null){
1061                     return fDTDDecl;
1062                 }
1063                 XMLStringBuffer tmpBuffer = fScanner.getDTDDecl();
1064                 fDTDDecl = tmpBuffer.toString();
1065                 return fDTDDecl;
1066         } else{
1067                 throw new IllegalStateException("Current state " + getEventTypeString(fEventType)
1068                      + " is not among the states" + getEventTypeString(XMLEvent.CHARACTERS) + ", "
1069                      + getEventTypeString(XMLEvent.COMMENT) + ", "
1070                      + getEventTypeString(XMLEvent.CDATA) + ", "
1071                      + getEventTypeString(XMLEvent.SPACE) + ", "
1072                      + getEventTypeString(XMLEvent.ENTITY_REFERENCE) + ", "
1073                      + getEventTypeString(XMLEvent.DTD) + " valid for getText() " ) ;
1074         }
1075     }//getText
1076 
1077 
1078     /** Test if the current event is of the given type and if the namespace and name match the current namespace and name of the current event.
1079      * If the namespaceURI is null it is not checked for equality, if the localName is null it is not checked for equality.
1080      * @param type the event type
1081      * @param namespaceURI the uri of the event, may be null
1082      * @param localName the localName of the event, may be null
1083      * @throws XMLStreamException if the required values are not matched.
1084      */
1085     public void require(int type, String namespaceURI, String localName) throws XMLStreamException {
1086         if( type != fEventType)
1087              throw new XMLStreamException("Event type " + getEventTypeString(type) + " specified did " +
1088                      "not match with current parser event " + getEventTypeString(fEventType));
1089           if( namespaceURI != null && !namespaceURI.equals(getNamespaceURI()) )
1090              throw new XMLStreamException("Namespace URI " + namespaceURI +" specified did not match " +
1091                      "with current namespace URI");
1092           if(localName != null && !localName.equals(getLocalName()))
1093              throw new XMLStreamException("LocalName " + localName +" specified did not match with " +
1094                      "current local name");
1095         return;
1096     }
1097 
1098     /** Gets the the text associated with a CHARACTERS, SPACE or CDATA event.
1099      * Text starting a "sourceStart" is copied into "destination" starting at "targetStart".
1100      * Up to "length" characters are copied.  The number of characters actually copied is returned.
1101      *
1102      * The "sourceStart" argument must be greater or equal to 0 and less than or equal to
1103      * the number of characters associated with the event.  Usually, one requests text starting at a "sourceStart" of 0.
1104      * If the number of characters actually copied is less than the "length", then there is no more text.
1105      * Otherwise, subsequent calls need to be made until all text has been retrieved. For example:
1106      *
1107      * <code>
1108      * int length = 1024;
1109      * char[] myBuffer = new char[ length ];
1110      *
1111      * for ( int sourceStart = 0 ; ; sourceStart += length )
1112      * {
1113      *    int nCopied = stream.getTextCharacters( sourceStart, myBuffer, 0, length );
1114      *
1115      *   if (nCopied < length)
1116      *       break;
1117      * }
1118      * </code>
1119      * XMLStreamException may be thrown if there are any XML errors in the underlying source.
1120      * The "targetStart" argument must be greater than or equal to 0 and less than the length of "target",
1121      * Length must be greater than 0 and "targetStart + length" must be less than or equal to length of "target".
1122      *
1123      * @param sourceStart the index of the first character in the source array to copy
1124      * @param target the destination array
1125      * @param targetStart the start offset in the target array
1126      * @param length the number of characters to copy
1127      * @return the number of characters actually copied
1128      * @throws XMLStreamException if the underlying XML source is not well-formed
1129      * @throws IndexOutOfBoundsException if targetStart < 0 or > than the length of target
1130      * @throws IndexOutOfBoundwhile(isCharacters()) ;sException if length < 0 or targetStart + length > length of target
1131      * @throws UnsupportedOperationException if this method is not supported
1132      * @throws NullPointerException is if target is null
1133      */
1134     public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException {
1135 
1136         if(target == null){
1137             throw new NullPointerException("target char array can't be null") ;
1138         }
1139 
1140         if(targetStart < 0 || length < 0 || sourceStart < 0 || targetStart >= target.length ||
1141             (targetStart + length ) > target.length) {
1142             throw new IndexOutOfBoundsException();
1143         }
1144 
1145         //getTextStart() + sourceStart should not be greater than the lenght of number of characters
1146         //present
1147         int copiedLength = 0;
1148         //int presentDataLen = getTextLength() - (getTextStart()+sourceStart);
1149         int available = getTextLength() - sourceStart;
1150         if(available < 0){
1151             throw new IndexOutOfBoundsException("sourceStart is greater than" +
1152                 "number of characters associated with this event");
1153         }
1154         if(available < length){
1155             copiedLength = available;
1156         } else{
1157             copiedLength = length;
1158         }
1159 
1160         System.arraycopy(getTextCharacters(), getTextStart() + sourceStart , target, targetStart, copiedLength);
1161         return copiedLength;
1162     }
1163 
1164     /** Return true if the current event has text, false otherwise
1165      * The following events have text:
1166      * CHARACTERS,DTD ,ENTITY_REFERENCE, COMMENT
1167      */
1168     public boolean hasText() {
1169         if(DEBUG) pr("XMLReaderImpl#EVENT TYPE = " + fEventType ) ;
1170         if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT || fEventType == XMLEvent.CDATA) {
1171             return fScanner.getCharacterData().length > 0;
1172         } else if(fEventType == XMLEvent.ENTITY_REFERENCE) {
1173             String name = fScanner.getEntityName();
1174             if(name != null){
1175                 if(fScanner.foundBuiltInRefs)
1176                     return true;
1177 
1178                 XMLEntityStorage entityStore = fEntityManager.getEntityStore();
1179                 Entity en = entityStore.getEntity(name);
1180                 if(en == null)
1181                     return false;
1182                 if(en.isExternal()){
1183                     return ((Entity.ExternalEntity)en).entityLocation.getExpandedSystemId() != null;
1184                 } else{
1185                     return ((Entity.InternalEntity)en).text != null ;
1186                 }
1187             }else
1188                 return false;
1189         } else {
1190             if(fEventType == XMLEvent.DTD)
1191                 return fScanner.fSeenDoctypeDecl;
1192         }
1193         return false;
1194     }
1195 
1196     /** Returns a boolean which indicates if this
1197      * attribute was created by default
1198      * @param index the position of the attribute
1199      * @return true if this is a default attribute
1200      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
1201      */
1202     public boolean isAttributeSpecified(int index) {
1203         //check that current state should be either START_ELEMENT or ATTRIBUTE
1204         if( (fEventType == XMLEvent.START_ELEMENT) || (fEventType == XMLEvent.ATTRIBUTE)){
1205             return fScanner.getAttributeIterator().isSpecified(index) ;
1206         } else{
1207             throw new IllegalStateException("Current state is not among the states "
1208                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
1209                      + getEventTypeString(XMLEvent.ATTRIBUTE)
1210                      + "valid for isAttributeSpecified()")  ;
1211         }
1212     }
1213 
1214     /** Returns true if the cursor points to a character data event
1215      * @return true if the cursor points to character data, false otherwise
1216      */
1217     public boolean isCharacters() {
1218         return fEventType == XMLEvent.CHARACTERS ;
1219     }
1220 
1221     /** Skips any insignificant events (COMMENT and PROCESSING_INSTRUCTION)
1222      * until a START_ELEMENT or
1223      * END_ELEMENT is reached. If other than space characters are
1224      * encountered, an exception is thrown. This method should
1225      * be used when processing element-only content because
1226      * the parser is not able to recognize ignorable whitespace if
1227      * then DTD is missing or not interpreted.
1228      * @return the event type of the element read
1229      * @throws XMLStreamException if the current event is not white space
1230      */
1231     public int nextTag() throws XMLStreamException {
1232 
1233         int eventType = next();
1234         while((eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace()) // skip whitespace
1235         || (eventType == XMLStreamConstants.CDATA && isWhiteSpace())
1236         // skip whitespace
1237         || eventType == XMLStreamConstants.SPACE
1238         || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
1239         || eventType == XMLStreamConstants.COMMENT
1240         ) {
1241             eventType = next();
1242         }
1243 
1244         if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) {
1245             throw new XMLStreamException(
1246                     "found: " + getEventTypeString(eventType)
1247                     + ", expected " + getEventTypeString(XMLStreamConstants.START_ELEMENT)
1248                     + " or " + getEventTypeString(XMLStreamConstants.END_ELEMENT),
1249                     getLocation());
1250         }
1251 
1252         return eventType;
1253     }
1254 
1255     /** Checks if standalone was set in the document
1256      * @return true if standalone was set in the document, or false otherwise
1257      */
1258     public boolean standaloneSet() {
1259         //xxx: it requires if the standalone was set in the document ? This is different that if the document
1260         // is standalone
1261         return fScanner.standaloneSet() ;
1262     }
1263 
1264     /**
1265      * @param qname
1266      * @return
1267      */
1268     public javax.xml.namespace.QName convertXNIQNametoJavaxQName(com.sun.org.apache.xerces.internal.xni.QName qname){
1269         if (qname == null) return null;
1270         //xxx: prefix definition ?
1271         if(qname.prefix == null){
1272             return new javax.xml.namespace.QName(qname.uri, qname.localpart) ;
1273         } else{
1274             return new javax.xml.namespace.QName(qname.uri, qname.localpart, qname.prefix) ;
1275         }
1276     }
1277 
1278     /** Return the uri for the given prefix.
1279      * The uri returned depends on the current state of the processor.
1280      *
1281      * <p><strong>NOTE:</strong>The 'xml' prefix is bound as defined in
1282      * <a href="http://www.w3.org/TR/REC-xml-names/#ns-using">Namespaces in XML</a>
1283      * specification to "http://www.w3.org/XML/1998/namespace".
1284      *
1285      * <p><strong>NOTE:</strong> The 'xmlns' prefix must be resolved to following namespace
1286      * <a href="http://www.w3.org/2000/xmlns/">http://www.w3.org/2000/xmlns/</a>
1287      * @return the uri bound to the given prefix or null if it is not bound
1288      * @param prefix The prefix to lookup, may not be null
1289      * @throws IllegalStateException - if the prefix is null
1290      */
1291     public String getNamespaceURI(String prefix) {
1292         if(prefix == null) throw new java.lang.IllegalArgumentException("prefix cannot be null.") ;
1293 
1294         //first add the string to symbol table.. since internally identity comparisons are done.
1295         return fScanner.getNamespaceContext().getURI(fSymbolTable.addSymbol(prefix)) ;
1296     }
1297 
1298     //xxx: this function is not being used.
1299     protected void setPropertyManager(PropertyManager propertyManager){
1300         fPropertyManager = propertyManager ;
1301         //REVISIT: we were supplying hashmap ealier
1302         fScanner.setProperty("stax-properties",propertyManager);
1303         fScanner.setPropertyManager(propertyManager) ;
1304     }
1305 
1306     /**
1307      * @return returns the reference to property manager.
1308      */
1309     protected PropertyManager getPropertyManager(){
1310         return fPropertyManager ;
1311     }
1312 
1313     static void pr(String str) {
1314         System.out.println(str) ;
1315     }
1316 
1317     protected List getEntityDecls(){
1318         if(fEventType == XMLStreamConstants.DTD){
1319             XMLEntityStorage entityStore = fEntityManager.getEntityStore();
1320             ArrayList list = null;
1321             if(entityStore.hasEntities()){
1322                 EntityDeclarationImpl decl = null;
1323                 list = new ArrayList(entityStore.getEntitySize());
1324                 Enumeration enu = entityStore.getEntityKeys();
1325                 while(enu.hasMoreElements()){
1326                     String key = (String)enu.nextElement();
1327                     Entity en = (Entity)entityStore.getEntity(key);
1328                     decl = new EntityDeclarationImpl();
1329                     decl.setEntityName(key);
1330                     if(en.isExternal()){
1331                         decl.setXMLResourceIdentifier(((Entity.ExternalEntity)en).entityLocation);
1332                         decl.setNotationName(((Entity.ExternalEntity)en).notation);
1333                     }
1334                     else
1335                         decl.setEntityReplacementText(((Entity.InternalEntity)en).text);
1336                     list.add(decl);
1337                 }
1338             }
1339             return list;
1340         }
1341         return null;
1342     }
1343 
1344     protected List getNotationDecls(){
1345         if(fEventType == XMLStreamConstants.DTD){
1346             if(fScanner.fDTDScanner == null) return null;
1347             DTDGrammar grammar = ((XMLDTDScannerImpl)(fScanner.fDTDScanner)).getGrammar();
1348             if(grammar == null) return null;
1349             List notations = grammar.getNotationDecls();
1350 
1351             Iterator it = notations.iterator();
1352             ArrayList list = new ArrayList();
1353             while(it.hasNext()){
1354                 XMLNotationDecl ni = (XMLNotationDecl)it.next();
1355                 if(ni!= null){
1356                     list.add(new NotationDeclarationImpl(ni));
1357                 }
1358             }
1359             return list;
1360         }
1361         return null;
1362     }
1363 
1364 
1365 
1366 }//XMLReaderImpl