1 /*
   2  * Copyright (c) 2005, 2016, 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 = fEntityManager.getEntityScanner();
 611         fEntityScanner.registerListener(fScanner);
 612         fEntityManager.fCurrentEntity.mayReadChunks = true;
 613         fScanner.setScannerState(XMLEvent.START_DOCUMENT);
 614 
 615         fScanner.fEntityDepth = oldEntityDepth;
 616         fScanner.fNamespaceContext = oldNamespaceContext;
 617         fEventType = fScanner.next();
 618     }
 619 
 620 
 621 
 622     final static String getEventTypeString(int eventType) {
 623         switch (eventType){
 624             case XMLEvent.START_ELEMENT:
 625                 return "START_ELEMENT";
 626             case XMLEvent.END_ELEMENT:
 627                 return "END_ELEMENT";
 628             case XMLEvent.PROCESSING_INSTRUCTION:
 629                 return "PROCESSING_INSTRUCTION";
 630             case XMLEvent.CHARACTERS:
 631                 return "CHARACTERS";
 632             case XMLEvent.COMMENT:
 633                 return "COMMENT";
 634             case XMLEvent.START_DOCUMENT:
 635                 return "START_DOCUMENT";
 636             case XMLEvent.END_DOCUMENT:
 637                 return "END_DOCUMENT";
 638             case XMLEvent.ENTITY_REFERENCE:
 639                 return "ENTITY_REFERENCE";
 640             case XMLEvent.ATTRIBUTE:
 641                 return "ATTRIBUTE";
 642             case XMLEvent.DTD:
 643                 return "DTD";
 644             case XMLEvent.CDATA:
 645                 return "CDATA";
 646             case XMLEvent.SPACE:
 647                 return "SPACE";
 648         }
 649         return "UNKNOWN_EVENT_TYPE, " + String.valueOf(eventType);
 650     }
 651 
 652     /** Returns the count of attributes on this START_ELEMENT,
 653      * this method is only valid on a START_ELEMENT or ATTRIBUTE.  This
 654      * count excludes namespace definitions.  Attribute indices are
 655      * zero-based.
 656      * @return returns the number of attributes
 657      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 658      */
 659     public int getAttributeCount() {
 660         //xxx: recognize SAX properties namespace, namespace-prefix to get XML Namespace declarations
 661         //does length includes namespace declarations ?
 662 
 663         //State should be either START_ELEMENT or ATTRIBUTE
 664         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 665             return fScanner.getAttributeIterator().getLength() ;
 666         } else{
 667             throw new java.lang.IllegalStateException( "Current state is not among the states "
 668                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 669                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 670                      + "valid for getAttributeCount()") ;
 671         }
 672     }//getAttributeCount
 673 
 674     /** Returns the localName of the attribute at the provided
 675      * index
 676      * @param index the position of the attribute
 677      * @return the localName of the attribute
 678      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 679      */
 680     public QName getAttributeName(int index) {
 681         //State should be either START_ELEMENT or ATTRIBUTE
 682         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 683             return convertXNIQNametoJavaxQName(fScanner.getAttributeIterator().getQualifiedName(index)) ;
 684         } else{
 685             throw new java.lang.IllegalStateException("Current state is not among the states "
 686                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 687                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 688                      + "valid for getAttributeName()") ;
 689         }
 690     }//getAttributeName
 691 
 692     /**
 693      * @param index
 694      * @return
 695      */
 696     public String getAttributeLocalName(int index) {
 697         //State should be either START_ELEMENT or ATTRIBUTE
 698         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 699             return fScanner.getAttributeIterator().getLocalName(index) ;
 700         } else{
 701             throw new java.lang.IllegalStateException() ;
 702         }
 703     }//getAttributeName
 704 
 705     /** Returns the namespace of the attribute at the provided
 706      * index
 707      * @param index the position of the attribute
 708      * @return the namespace URI (can be null)
 709      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 710      */
 711     public String getAttributeNamespace(int index) {
 712         //State should be either START_ELEMENT or ATTRIBUTE
 713         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 714             return fScanner.getAttributeIterator().getURI(index);
 715         } else{
 716             throw new java.lang.IllegalStateException("Current state is not among the states "
 717                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 718                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 719                      + "valid for getAttributeNamespace()") ;
 720         }
 721 
 722     }//getAttributeNamespace
 723 
 724     /** Returns the prefix of this attribute at the
 725      * provided index
 726      * @param index the position of the attribute
 727      * @return the prefix of the attribute
 728      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 729      */
 730     public String getAttributePrefix(int index) {
 731         //State should be either START_ELEMENT or ATTRIBUTE
 732         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 733             return fScanner.getAttributeIterator().getPrefix(index);
 734         } else{
 735             throw new java.lang.IllegalStateException("Current state is not among the states "
 736                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 737                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 738                      + "valid for getAttributePrefix()") ;
 739         }
 740     }//getAttributePrefix
 741 
 742     /** Returns the qname of the attribute at the provided index
 743      *
 744      * @param index the position of the attribute
 745      * @return the QName of the attribute
 746      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 747      */
 748     public javax.xml.namespace.QName getAttributeQName(int index) {
 749         //State should be either START_ELEMENT or ATTRIBUTE
 750         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 751             // create new object at runtime..
 752             String localName = fScanner.getAttributeIterator().getLocalName(index) ;
 753             String uri = fScanner.getAttributeIterator().getURI(index) ;
 754             return new javax.xml.namespace.QName(uri, localName) ;
 755         } else{
 756             throw new java.lang.IllegalStateException("Current state is not among the states "
 757                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 758                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 759                      + "valid for getAttributeQName()") ;
 760         }
 761     }//getAttributeQName
 762 
 763     /** Returns the XML type of the attribute at the provided
 764      * index
 765      * @param index the position of the attribute
 766      * @return the XML type of the attribute
 767      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 768      */
 769     public String getAttributeType(int index) {
 770         //State should be either START_ELEMENT or ATTRIBUTE
 771         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 772             return fScanner.getAttributeIterator().getType(index) ;
 773         } else{
 774             throw new java.lang.IllegalStateException("Current state is not among the states "
 775                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 776                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 777                      + "valid for getAttributeType()") ;
 778         }
 779 
 780     }//getAttributeType
 781 
 782     /** Returns the value of the attribute at the
 783      * index
 784      * @param index the position of the attribute
 785      * @return the attribute value
 786      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
 787      */
 788     public String getAttributeValue(int index) {
 789         //State should be either START_ELEMENT or ATTRIBUTE
 790         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 791             return fScanner.getAttributeIterator().getValue(index) ;
 792         } else{
 793             throw new java.lang.IllegalStateException("Current state is not among the states "
 794                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 795                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 796                      + "valid for getAttributeValue()") ;
 797         }
 798 
 799     }//getAttributeValue
 800 
 801     /**
 802      * @param namespaceURI
 803      * @param localName
 804      * @return
 805      */
 806     public String getAttributeValue(String namespaceURI, String localName) {
 807         //State should be either START_ELEMENT or ATTRIBUTE
 808         if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
 809             XMLAttributesImpl attributes = fScanner.getAttributeIterator();
 810             if (namespaceURI == null) { //sjsxp issue 70
 811                 return attributes.getValue(attributes.getIndexByLocalName(localName)) ;
 812             } else {
 813                 return fScanner.getAttributeIterator().getValue(
 814                         namespaceURI.length() == 0 ? null : namespaceURI, localName) ;
 815             }
 816 
 817         } else{
 818             throw new java.lang.IllegalStateException("Current state is not among the states "
 819                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
 820                      + getEventTypeString(XMLEvent.ATTRIBUTE)
 821                      + "valid for getAttributeValue()") ;
 822         }
 823 
 824     }
 825 
 826     /** Reads the content of a text-only element. Precondition:
 827      * the current event is START_ELEMENT. Postcondition:
 828      * The current event is the corresponding END_ELEMENT.
 829      * @throws XMLStreamException if the current event is not a START_ELEMENT or if
 830      * a non text element is encountered
 831      */
 832     public String getElementText() throws XMLStreamException {
 833 
 834         if(getEventType() != XMLStreamConstants.START_ELEMENT) {
 835             throw new XMLStreamException(
 836             "parser must be on START_ELEMENT to read next text", getLocation());
 837         }
 838         int eventType = next();
 839         StringBuffer content = new StringBuffer();
 840         while(eventType != XMLStreamConstants.END_ELEMENT ) {
 841             if(eventType == XMLStreamConstants.CHARACTERS
 842             || eventType == XMLStreamConstants.CDATA
 843             || eventType == XMLStreamConstants.SPACE
 844             || eventType == XMLStreamConstants.ENTITY_REFERENCE) {
 845                 content.append(getText());
 846             } else if(eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
 847             || eventType == XMLStreamConstants.COMMENT) {
 848                 // skipping
 849             } else if(eventType == XMLStreamConstants.END_DOCUMENT) {
 850                 throw new XMLStreamException("unexpected end of document when reading element text content");
 851             } else if(eventType == XMLStreamConstants.START_ELEMENT) {
 852                 throw new XMLStreamException(
 853                 "elementGetText() function expects text only elment but START_ELEMENT was encountered.", getLocation());
 854             } else {
 855                 throw new XMLStreamException(
 856                 "Unexpected event type "+ eventType, getLocation());
 857             }
 858             eventType = next();
 859         }
 860         return content.toString();
 861     }
 862 
 863     /** Return the current location of the processor.
 864      * If the Location is unknown the processor should return
 865      * an implementation of Location that returns -1 for the
 866      * location and null for the publicId and systemId.
 867      * The location information is only valid until next() is
 868      * called.
 869      */
 870     public Location getLocation() {
 871         return new Location() {
 872             String _systemId = fEntityScanner.getExpandedSystemId();
 873             String _publicId = fEntityScanner.getPublicId();
 874             int _offset = fEntityScanner.getCharacterOffset();
 875             int _columnNumber = fEntityScanner.getColumnNumber();
 876             int _lineNumber = fEntityScanner.getLineNumber();
 877             public String getLocationURI(){
 878                 return _systemId;
 879             }
 880 
 881             public int getCharacterOffset(){
 882                 return _offset;
 883             }
 884 
 885             public int getColumnNumber() {
 886                 return _columnNumber;
 887             }
 888 
 889             public int getLineNumber(){
 890                 return _lineNumber;
 891             }
 892 
 893             public String getPublicId(){
 894                 return _publicId;
 895             }
 896 
 897             public String getSystemId(){
 898                 return _systemId;
 899             }
 900 
 901             public String toString(){
 902                 StringBuffer sbuffer = new StringBuffer() ;
 903                 sbuffer.append("Line number = " + getLineNumber());
 904                 sbuffer.append("\n") ;
 905                 sbuffer.append("Column number = " + getColumnNumber());
 906                 sbuffer.append("\n") ;
 907                 sbuffer.append("System Id = " + getSystemId());
 908                 sbuffer.append("\n") ;
 909                 sbuffer.append("Public Id = " + getPublicId());
 910                 sbuffer.append("\n") ;
 911                 sbuffer.append("Location Uri= " + getLocationURI());
 912                 sbuffer.append("\n") ;
 913                 sbuffer.append("CharacterOffset = " + getCharacterOffset());
 914                 sbuffer.append("\n") ;
 915                 return sbuffer.toString();
 916             }
 917         } ;
 918 
 919     }
 920 
 921     /** Returns a QName for the current START_ELEMENT or END_ELEMENT event
 922      * @return the QName for the current START_ELEMENT or END_ELEMENT event
 923      */
 924     public javax.xml.namespace.QName getName() {
 925         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT)
 926             return convertXNIQNametoJavaxQName(fScanner.getElementQName());
 927         else
 928             throw new java.lang.IllegalStateException("Illegal to call getName() "+
 929             "when event type is "+ getEventTypeString(fEventType) + "."
 930                      + " Valid states are " + getEventTypeString(XMLEvent.START_ELEMENT) + ", "
 931                      + getEventTypeString(XMLEvent.END_ELEMENT));
 932     }
 933 
 934     /** Returns a read only namespace context for the current
 935      * position.  The context is transient and only valid until
 936      * a call to next() changes the state of the reader.
 937      * @return return a namespace context
 938      */
 939     public NamespaceContext getNamespaceContext() {
 940         return fNamespaceContextWrapper ;
 941     }
 942 
 943     /** Returns the count of namespaces declared on this START_ELEMENT or END_ELEMENT,
 944      * this method is only valid on a START_ELEMENT, END_ELEMENT or NAMESPACE. On
 945      * an END_ELEMENT the count is of the namespaces that are about to go
 946      * out of scope.  This is the equivalent of the information reported
 947      * by SAX callback for an end element event.
 948      * @return returns the number of namespace declarations on this specific element
 949      * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT or NAMESPACE
 950      */
 951     public int getNamespaceCount() {
 952         //namespaceContext is dynamic object.
 953         //REVISIT: check if it specifies all conditions mentioned in the javadoc
 954         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT || fEventType == XMLEvent.NAMESPACE){
 955             return fScanner.getNamespaceContext().getDeclaredPrefixCount() ;
 956         } else{
 957             throw new IllegalStateException("Current event state is " + getEventTypeString(fEventType)
 958              + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
 959              + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
 960                      + getEventTypeString(XMLEvent.NAMESPACE)
 961              + " valid for getNamespaceCount()." );
 962         }
 963     }
 964 
 965     /** Returns the prefix for the namespace declared at the
 966      * index.  Returns null if this is the default namespace
 967      * declaration
 968      *
 969      * @param index the position of the namespace declaration
 970      * @return returns the namespace prefix
 971      * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT or NAMESPACE
 972      */
 973     public String getNamespacePrefix(int index) {
 974         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT || fEventType == XMLEvent.NAMESPACE){
 975             //namespaceContext is dynamic object.
 976             String prefix = fScanner.getNamespaceContext().getDeclaredPrefixAt(index) ;
 977             return prefix.equals("") ? null : prefix ;
 978         }
 979         else{
 980             throw new IllegalStateException("Current state " + getEventTypeString(fEventType)
 981              + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
 982              + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
 983                      + getEventTypeString(XMLEvent.NAMESPACE)
 984              + " valid for getNamespacePrefix()." );
 985         }
 986     }
 987 
 988     /** Returns the uri for the namespace declared at the
 989      * index.
 990      *
 991      * @param index the position of the namespace declaration
 992      * @return returns the namespace uri
 993      * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT or NAMESPACE
 994      */
 995     public String getNamespaceURI(int index) {
 996         if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT || fEventType == XMLEvent.NAMESPACE){
 997             //namespaceContext is dynamic object.
 998             return fScanner.getNamespaceContext().getURI(fScanner.getNamespaceContext().getDeclaredPrefixAt(index));
 999         }
1000         else{
1001             throw new IllegalStateException("Current state " + getEventTypeString(fEventType)
1002              + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
1003              + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
1004                      + getEventTypeString(XMLEvent.NAMESPACE)
1005              + " valid for getNamespaceURI()." );
1006         }
1007 
1008     }
1009 
1010     /** Get the value of a feature/property from the underlying implementation
1011      * @param name The name of the property, may not be null
1012      * @return The value of the property
1013      * @throws IllegalArgumentException if name is null
1014      */
1015     public Object getProperty(java.lang.String name) throws java.lang.IllegalArgumentException {
1016         if(name == null) throw new java.lang.IllegalArgumentException() ;
1017         if (fPropertyManager != null ){
1018             if(name.equals(fPropertyManager.STAX_NOTATIONS)){
1019                 return getNotationDecls();
1020             }else if(name.equals(fPropertyManager.STAX_ENTITIES)){
1021                 return getEntityDecls();
1022             }else
1023                 return fPropertyManager.getProperty(name);
1024         }
1025         return null;
1026     }
1027 
1028     /** Returns the current value of the parse event as a string,
1029      * this returns the string value of a CHARACTERS event,
1030      * returns the value of a COMMENT, the replacement value
1031      * for an ENTITY_REFERENCE,
1032      * or the String value of the DTD
1033      * @return the current text or null
1034      * @throws java.lang.IllegalStateException if this state is not
1035      * a valid text state.
1036      */
1037     public String getText() {
1038         if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
1039                 || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE){
1040             //this requires creation of new string
1041             //fEventType == XMLEvent.ENTITY_REFERENCE
1042             return fScanner.getCharacterData().toString() ;
1043         } else if(fEventType == XMLEvent.ENTITY_REFERENCE){
1044             String name = fScanner.getEntityName();
1045             if(name != null){
1046                 if(fScanner.foundBuiltInRefs)
1047                     return fScanner.getCharacterData().toString();
1048 
1049                 XMLEntityStorage entityStore = fEntityManager.getEntityStore();
1050                 Entity en = entityStore.getEntity(name);
1051                 if(en == null)
1052                     return null;
1053                 if(en.isExternal())
1054                     return ((Entity.ExternalEntity)en).entityLocation.getExpandedSystemId();
1055                 else
1056                     return ((Entity.InternalEntity)en).text;
1057             }else
1058                 return null;
1059         }
1060         else if(fEventType == XMLEvent.DTD){
1061                 if(fDTDDecl != null){
1062                     return fDTDDecl;
1063                 }
1064                 XMLStringBuffer tmpBuffer = fScanner.getDTDDecl();
1065                 fDTDDecl = tmpBuffer.toString();
1066                 return fDTDDecl;
1067         } else{
1068                 throw new IllegalStateException("Current state " + getEventTypeString(fEventType)
1069                      + " is not among the states" + getEventTypeString(XMLEvent.CHARACTERS) + ", "
1070                      + getEventTypeString(XMLEvent.COMMENT) + ", "
1071                      + getEventTypeString(XMLEvent.CDATA) + ", "
1072                      + getEventTypeString(XMLEvent.SPACE) + ", "
1073                      + getEventTypeString(XMLEvent.ENTITY_REFERENCE) + ", "
1074                      + getEventTypeString(XMLEvent.DTD) + " valid for getText() " ) ;
1075         }
1076     }//getText
1077 
1078 
1079     /** 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.
1080      * If the namespaceURI is null it is not checked for equality, if the localName is null it is not checked for equality.
1081      * @param type the event type
1082      * @param namespaceURI the uri of the event, may be null
1083      * @param localName the localName of the event, may be null
1084      * @throws XMLStreamException if the required values are not matched.
1085      */
1086     public void require(int type, String namespaceURI, String localName) throws XMLStreamException {
1087         if( type != fEventType)
1088              throw new XMLStreamException("Event type " + getEventTypeString(type) + " specified did " +
1089                      "not match with current parser event " + getEventTypeString(fEventType));
1090           if( namespaceURI != null && !namespaceURI.equals(getNamespaceURI()) )
1091              throw new XMLStreamException("Namespace URI " + namespaceURI +" specified did not match " +
1092                      "with current namespace URI");
1093           if(localName != null && !localName.equals(getLocalName()))
1094              throw new XMLStreamException("LocalName " + localName +" specified did not match with " +
1095                      "current local name");
1096         return;
1097     }
1098 
1099     /** Gets the the text associated with a CHARACTERS, SPACE or CDATA event.
1100      * Text starting a "sourceStart" is copied into "destination" starting at "targetStart".
1101      * Up to "length" characters are copied.  The number of characters actually copied is returned.
1102      *
1103      * The "sourceStart" argument must be greater or equal to 0 and less than or equal to
1104      * the number of characters associated with the event.  Usually, one requests text starting at a "sourceStart" of 0.
1105      * If the number of characters actually copied is less than the "length", then there is no more text.
1106      * Otherwise, subsequent calls need to be made until all text has been retrieved. For example:
1107      *
1108      * <code>
1109      * int length = 1024;
1110      * char[] myBuffer = new char[ length ];
1111      *
1112      * for ( int sourceStart = 0 ; ; sourceStart += length )
1113      * {
1114      *    int nCopied = stream.getTextCharacters( sourceStart, myBuffer, 0, length );
1115      *
1116      *   if (nCopied < length)
1117      *       break;
1118      * }
1119      * </code>
1120      * XMLStreamException may be thrown if there are any XML errors in the underlying source.
1121      * The "targetStart" argument must be greater than or equal to 0 and less than the length of "target",
1122      * Length must be greater than 0 and "targetStart + length" must be less than or equal to length of "target".
1123      *
1124      * @param sourceStart the index of the first character in the source array to copy
1125      * @param target the destination array
1126      * @param targetStart the start offset in the target array
1127      * @param length the number of characters to copy
1128      * @return the number of characters actually copied
1129      * @throws XMLStreamException if the underlying XML source is not well-formed
1130      * @throws IndexOutOfBoundsException if targetStart < 0 or > than the length of target
1131      * @throws IndexOutOfBoundwhile(isCharacters()) ;sException if length < 0 or targetStart + length > length of target
1132      * @throws UnsupportedOperationException if this method is not supported
1133      * @throws NullPointerException is if target is null
1134      */
1135     public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException {
1136 
1137         if(target == null){
1138             throw new NullPointerException("target char array can't be null") ;
1139         }
1140 
1141         if(targetStart < 0 || length < 0 || sourceStart < 0 || targetStart >= target.length ||
1142             (targetStart + length ) > target.length) {
1143             throw new IndexOutOfBoundsException();
1144         }
1145 
1146         //getTextStart() + sourceStart should not be greater than the lenght of number of characters
1147         //present
1148         int copiedLength = 0;
1149         //int presentDataLen = getTextLength() - (getTextStart()+sourceStart);
1150         int available = getTextLength() - sourceStart;
1151         if(available < 0){
1152             throw new IndexOutOfBoundsException("sourceStart is greater than" +
1153                 "number of characters associated with this event");
1154         }
1155         if(available < length){
1156             copiedLength = available;
1157         } else{
1158             copiedLength = length;
1159         }
1160 
1161         System.arraycopy(getTextCharacters(), getTextStart() + sourceStart , target, targetStart, copiedLength);
1162         return copiedLength;
1163     }
1164 
1165     /** Return true if the current event has text, false otherwise
1166      * The following events have text:
1167      * CHARACTERS,DTD ,ENTITY_REFERENCE, COMMENT
1168      */
1169     public boolean hasText() {
1170         if(DEBUG) pr("XMLReaderImpl#EVENT TYPE = " + fEventType ) ;
1171         if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT || fEventType == XMLEvent.CDATA) {
1172             return fScanner.getCharacterData().length > 0;
1173         } else if(fEventType == XMLEvent.ENTITY_REFERENCE) {
1174             String name = fScanner.getEntityName();
1175             if(name != null){
1176                 if(fScanner.foundBuiltInRefs)
1177                     return true;
1178 
1179                 XMLEntityStorage entityStore = fEntityManager.getEntityStore();
1180                 Entity en = entityStore.getEntity(name);
1181                 if(en == null)
1182                     return false;
1183                 if(en.isExternal()){
1184                     return ((Entity.ExternalEntity)en).entityLocation.getExpandedSystemId() != null;
1185                 } else{
1186                     return ((Entity.InternalEntity)en).text != null ;
1187                 }
1188             }else
1189                 return false;
1190         } else {
1191             if(fEventType == XMLEvent.DTD)
1192                 return fScanner.fSeenDoctypeDecl;
1193         }
1194         return false;
1195     }
1196 
1197     /** Returns a boolean which indicates if this
1198      * attribute was created by default
1199      * @param index the position of the attribute
1200      * @return true if this is a default attribute
1201      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
1202      */
1203     public boolean isAttributeSpecified(int index) {
1204         //check that current state should be either START_ELEMENT or ATTRIBUTE
1205         if( (fEventType == XMLEvent.START_ELEMENT) || (fEventType == XMLEvent.ATTRIBUTE)){
1206             return fScanner.getAttributeIterator().isSpecified(index) ;
1207         } else{
1208             throw new IllegalStateException("Current state is not among the states "
1209                      + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
1210                      + getEventTypeString(XMLEvent.ATTRIBUTE)
1211                      + "valid for isAttributeSpecified()")  ;
1212         }
1213     }
1214 
1215     /** Returns true if the cursor points to a character data event
1216      * @return true if the cursor points to character data, false otherwise
1217      */
1218     public boolean isCharacters() {
1219         return fEventType == XMLEvent.CHARACTERS ;
1220     }
1221 
1222     /** Skips any insignificant events (COMMENT and PROCESSING_INSTRUCTION)
1223      * until a START_ELEMENT or
1224      * END_ELEMENT is reached. If other than space characters are
1225      * encountered, an exception is thrown. This method should
1226      * be used when processing element-only content because
1227      * the parser is not able to recognize ignorable whitespace if
1228      * then DTD is missing or not interpreted.
1229      * @return the event type of the element read
1230      * @throws XMLStreamException if the current event is not white space
1231      */
1232     public int nextTag() throws XMLStreamException {
1233 
1234         int eventType = next();
1235         while((eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace()) // skip whitespace
1236         || (eventType == XMLStreamConstants.CDATA && isWhiteSpace())
1237         // skip whitespace
1238         || eventType == XMLStreamConstants.SPACE
1239         || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
1240         || eventType == XMLStreamConstants.COMMENT
1241         ) {
1242             eventType = next();
1243         }
1244 
1245         if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) {
1246             throw new XMLStreamException(
1247                     "found: " + getEventTypeString(eventType)
1248                     + ", expected " + getEventTypeString(XMLStreamConstants.START_ELEMENT)
1249                     + " or " + getEventTypeString(XMLStreamConstants.END_ELEMENT),
1250                     getLocation());
1251         }
1252 
1253         return eventType;
1254     }
1255 
1256     /** Checks if standalone was set in the document
1257      * @return true if standalone was set in the document, or false otherwise
1258      */
1259     public boolean standaloneSet() {
1260         //xxx: it requires if the standalone was set in the document ? This is different that if the document
1261         // is standalone
1262         return fScanner.standaloneSet() ;
1263     }
1264 
1265     /**
1266      * @param qname
1267      * @return
1268      */
1269     public javax.xml.namespace.QName convertXNIQNametoJavaxQName(com.sun.org.apache.xerces.internal.xni.QName qname){
1270         if (qname == null) return null;
1271         //xxx: prefix definition ?
1272         if(qname.prefix == null){
1273             return new javax.xml.namespace.QName(qname.uri, qname.localpart) ;
1274         } else{
1275             return new javax.xml.namespace.QName(qname.uri, qname.localpart, qname.prefix) ;
1276         }
1277     }
1278 
1279     /** Return the uri for the given prefix.
1280      * The uri returned depends on the current state of the processor.
1281      *
1282      * <p><strong>NOTE:</strong>The 'xml' prefix is bound as defined in
1283      * <a href="http://www.w3.org/TR/REC-xml-names/#ns-using">Namespaces in XML</a>
1284      * specification to "http://www.w3.org/XML/1998/namespace".
1285      *
1286      * <p><strong>NOTE:</strong> The 'xmlns' prefix must be resolved to following namespace
1287      * <a href="http://www.w3.org/2000/xmlns/">http://www.w3.org/2000/xmlns/</a>
1288      * @return the uri bound to the given prefix or null if it is not bound
1289      * @param prefix The prefix to lookup, may not be null
1290      * @throws IllegalStateException - if the prefix is null
1291      */
1292     public String getNamespaceURI(String prefix) {
1293         if(prefix == null) throw new java.lang.IllegalArgumentException("prefix cannot be null.") ;
1294 
1295         //first add the string to symbol table.. since internally identity comparisons are done.
1296         return fScanner.getNamespaceContext().getURI(fSymbolTable.addSymbol(prefix)) ;
1297     }
1298 
1299     //xxx: this function is not being used.
1300     protected void setPropertyManager(PropertyManager propertyManager){
1301         fPropertyManager = propertyManager ;
1302         //REVISIT: we were supplying hashmap ealier
1303         fScanner.setProperty("stax-properties",propertyManager);
1304         fScanner.setPropertyManager(propertyManager) ;
1305     }
1306 
1307     /**
1308      * @return returns the reference to property manager.
1309      */
1310     protected PropertyManager getPropertyManager(){
1311         return fPropertyManager ;
1312     }
1313 
1314     static void pr(String str) {
1315         System.out.println(str) ;
1316     }
1317 
1318     protected List getEntityDecls(){
1319         if(fEventType == XMLStreamConstants.DTD){
1320             XMLEntityStorage entityStore = fEntityManager.getEntityStore();
1321             ArrayList list = null;
1322             if(entityStore.hasEntities()){
1323                 EntityDeclarationImpl decl = null;
1324                 list = new ArrayList(entityStore.getEntitySize());
1325                 Enumeration enu = entityStore.getEntityKeys();
1326                 while(enu.hasMoreElements()){
1327                     String key = (String)enu.nextElement();
1328                     Entity en = (Entity)entityStore.getEntity(key);
1329                     decl = new EntityDeclarationImpl();
1330                     decl.setEntityName(key);
1331                     if(en.isExternal()){
1332                         decl.setXMLResourceIdentifier(((Entity.ExternalEntity)en).entityLocation);
1333                         decl.setNotationName(((Entity.ExternalEntity)en).notation);
1334                     }
1335                     else
1336                         decl.setEntityReplacementText(((Entity.InternalEntity)en).text);
1337                     list.add(decl);
1338                 }
1339             }
1340             return list;
1341         }
1342         return null;
1343     }
1344 
1345     protected List getNotationDecls(){
1346         if(fEventType == XMLStreamConstants.DTD){
1347             if(fScanner.fDTDScanner == null) return null;
1348             DTDGrammar grammar = ((XMLDTDScannerImpl)(fScanner.fDTDScanner)).getGrammar();
1349             if(grammar == null) return null;
1350             List notations = grammar.getNotationDecls();
1351 
1352             Iterator it = notations.iterator();
1353             ArrayList list = new ArrayList();
1354             while(it.hasNext()){
1355                 XMLNotationDecl ni = (XMLNotationDecl)it.next();
1356                 if(ni!= null){
1357                     list.add(new NotationDeclarationImpl(ni));
1358                 }
1359             }
1360             return list;
1361         }
1362         return null;
1363     }
1364 
1365 
1366 
1367 }//XMLReaderImpl