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