View Javadoc

1   /*
2    * Copyright (c) 2002 Extreme! Lab, Indiana University. All rights reserved.
3    *
4    * This software is open source. See the bottom of this file for the licence.
5    *
6    */
7   
8   package com.bea.xml.stream;
9   
10  import java.io.EOFException;
11  import java.io.IOException;
12  import java.io.Reader;
13  import java.io.BufferedReader;
14  import java.io.InputStreamReader;
15  import java.io.UnsupportedEncodingException;
16  import java.util.ArrayList;
17  import java.util.HashMap;
18  import java.util.Vector;
19  import java.util.Enumeration;
20  import java.util.Iterator;
21  
22  import javax.xml.namespace.NamespaceContext;
23  
24  import com.bea.xml.stream.util.EmptyIterator;
25  import com.bea.xml.stream.util.ElementTypeNames;
26  import javax.xml.stream.events.XMLEvent;
27  import javax.xml.stream.Location;
28  import javax.xml.namespace.QName;
29  import javax.xml.stream.XMLStreamReader;
30  import javax.xml.stream.XMLStreamException;
31  import com.wutka.dtd.DTDParser;
32  import com.wutka.dtd.DTD;
33  import com.wutka.dtd.DTDEntity;
34  import com.wutka.dtd.DTDAttlist;
35  import com.wutka.dtd.DTDAttribute;
36  
37  
38  
39  public class MXParser
40    implements XMLStreamReader, Location
41  {
42      protected final static String XML_URI = "http://www.w3.org/XML/1998/namespace";
43      protected final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
44      protected static final String FEATURE_XML_ROUNDTRIP=
45          "http://xmlpull.org/v1/doc/features.html#xml-roundtrip";
46      protected static final String FEATURE_NAMES_INTERNED =
47          "http://xmlpull.org/v1/doc/features.html#names-interned";
48  
49      public static final String FEATURE_PROCESS_DOCDECL =
50          "http://xmlpull.org/v1/doc/features.html#process-docdecl";
51  
52      public static final String [] TYPES = {
53          "START_DOCUMENT",
54          "END_DOCUMENT",
55          "START_ELEMENT",
56          "END_ELEMENT",
57          "CHARACTERS", // "TEXT",
58          "CDATA",
59          "ENTITY_REFERENCE",
60          "SPACE", // "IGNORABLE_WHITESPACE",
61          "PROCESSING_INSTRUCTION",
62          "XML_DECLARATION",
63          "COMMENT",
64          "DOCDECL"
65      };
66      
67      // TODO - cwitt : split TEXT into CHARACTERS and WHITESPACE
68      private static final int TEXT=0x00004000;
69      // TODO - cwitt : remove DOCDECL ?
70      private static final int DOCDECL=0x00008000;
71      // TODO - cwitt : move to XMLEvent ?
72      // will not be available in event interface (info under start_document
73      // in that case), just in cursor
74    //private static final int XML_DECLARATION=0x00010000;
75      // NOTE - cwitt : from XmlPullParser interface
76      public static final String NO_NAMESPACE = "";
77      
78      /***
79       * Implementation notice:
80       * the is instance variable that controls if newString() is interning.
81       * <p><b>NOTE:</b> newStringIntern <b>always</b> returns interned strings
82       * and newString MAY return interned String depending on this variable.
83       * <p><b>NOTE:</b> by default in this minimal implementation it is false!
84       */
85      protected boolean allStringsInterned;
86  
87      protected void resetStringCache() {
88          //System.out.println("resetStringCache() minimum called");
89      }
90  
91      protected String newString(char[] cbuf, int off, int len) {
92          return new String(cbuf, off, len);
93      }
94  
95      protected String newStringIntern(char[] cbuf, int off, int len) {
96          return (new String(cbuf, off, len)).intern();
97      }
98  
99  
100     private static final boolean TRACE_SIZING = false;
101 
102     // NOTE: features are not resetable and typicaly defaults to false ...
103     // TODO - cwitt : we always want to set these to true, so the featues
104     // don't need to be defined in the factory, will remove them later here
105     public static final String FEATURE_PROCESS_NAMESPACES =
106         "http://xmlpull.org/v1/doc/features.html#process-namespaces";
107     protected boolean processNamespaces = true;
108     protected boolean roundtripSupported = true;
109 
110     // global parser state
111     protected int lineNumber;
112     protected int columnNumber;
113     protected boolean seenRoot;
114     protected boolean reachedEnd;
115     protected int eventType;
116     protected boolean emptyElementTag;
117     // element stack
118     protected int depth;
119     protected char[] elRawName[];
120     protected int elRawNameEnd[];
121     //pnrotected int elRawNameEnd[];
122     protected String elName[];
123     protected String elPrefix[];
124     protected String elUri[];
125     //protected String elValue[];
126     protected int elNamespaceCount[];
127 
128     protected String xmlVersion;
129     protected boolean standalone=true;
130     protected boolean standaloneSet=false;
131     protected String charEncodingScheme;
132 
133   protected String piTarget;
134   protected String piData;
135 
136   protected HashMap defaultAttributes;
137     /***
138      * Make sure that we have enough space to keep element stack if passed size.
139      * It will always create one additional slot then current depth
140      */
141     protected void ensureElementsCapacity() {
142         int elStackSize = elName != null ? elName.length : 0;
143         if( (depth + 1) >= elStackSize) {
144             // we add at least one extra slot ...
145             int newSize = (depth >= 7 ? 2 * depth : 8) + 2; // = lucky 7 + 1 //25
146             if(TRACE_SIZING) {
147                 System.err.println("elStackSize "+elStackSize+" ==> "+newSize);
148             }
149             boolean needsCopying = elStackSize > 0;
150             String[] arr = null;
151             arr = new String[newSize];
152             if(needsCopying) System.arraycopy(elName, 0, arr, 0, elStackSize);
153             elName = arr;
154             arr = new String[newSize];
155             if(needsCopying) System.arraycopy(elPrefix, 0, arr, 0, elStackSize);
156             elPrefix = arr;
157             arr = new String[newSize];
158             if(needsCopying) System.arraycopy(elUri, 0, arr, 0, elStackSize);
159             elUri = arr;
160 
161             int[] iarr = new int[newSize];
162             if(needsCopying) {
163                 System.arraycopy(elNamespaceCount, 0, iarr, 0, elStackSize);
164             } else {
165                 // special initialization
166                 iarr[0] = 0;
167             }
168             elNamespaceCount = iarr;
169 
170             //TODO: avoid using element raw name ...
171             iarr = new int[newSize];
172             if(needsCopying) {
173                 System.arraycopy(elRawNameEnd, 0, iarr, 0, elStackSize);
174             }
175             elRawNameEnd = iarr;
176 
177             char[][] carr = new char[newSize][];
178             if(needsCopying) {
179                 System.arraycopy(elRawName, 0, carr, 0, elStackSize);
180             }
181             elRawName = carr;
182             //            arr = new String[newSize];
183             //            if(needsCopying) System.arraycopy(elLocalName, 0, arr, 0, elStackSize);
184             //            elLocalName = arr;
185             //            arr = new String[newSize];
186             //            if(needsCopying) System.arraycopy(elDefaultNs, 0, arr, 0, elStackSize);
187             //            elDefaultNs = arr;
188             //            int[] iarr = new int[newSize];
189             //            if(needsCopying) System.arraycopy(elNsStackPos, 0, iarr, 0, elStackSize);
190             //            for (int i = elStackSize; i < iarr.length; i++)
191             //            {
192             //                iarr[i] = (i > 0) ? -1 : 0;
193             //            }
194             //            elNsStackPos = iarr;
195             //assert depth < elName.length;
196         }
197     }
198 
199 
200     // nameStart / name lookup tables based on XML 1.1 http://www.w3.org/TR/2001/WD-xml11-20011213/
201     protected static final int LOOKUP_MAX = 0x400;
202     protected static final char LOOKUP_MAX_CHAR = (char)LOOKUP_MAX;
203     //    protected static int lookupNameStartChar[] = new int[ LOOKUP_MAX_CHAR / 32 ];
204     //    protected static int lookupNameChar[] = new int[ LOOKUP_MAX_CHAR / 32 ];
205     protected static boolean lookupNameStartChar[] = new boolean[ LOOKUP_MAX ];
206     protected static boolean lookupNameChar[] = new boolean[ LOOKUP_MAX ];
207 
208     private static final void setName(char ch)
209         //{ lookupNameChar[ (int)ch / 32 ] |= (1 << (ch % 32)); }
210     { lookupNameChar[ ch ] = true; }
211     private static final void setNameStart(char ch)
212         //{ lookupNameStartChar[ (int)ch / 32 ] |= (1 << (ch % 32)); setName(ch); }
213     { lookupNameStartChar[ ch ] = true; setName(ch); }
214 
215     static {
216         setNameStart(':');
217         for (char ch = 'A'; ch <= 'Z'; ++ch) setNameStart(ch);
218         setNameStart('_');
219         for (char ch = 'a'; ch <= 'z'; ++ch) setNameStart(ch);
220         for (char ch = '\u00c0'; ch <= '\u02FF'; ++ch) setNameStart(ch);
221         for (char ch = '\u0370'; ch <= '\u037d'; ++ch) setNameStart(ch);
222         for (char ch = '\u037f'; ch < '\u0400'; ++ch) setNameStart(ch);
223 
224         setName('-');
225         setName('.');
226         for (char ch = '0'; ch <= '9'; ++ch) setName(ch);
227         setName('\u00b7');
228         for (char ch = '\u0300'; ch <= '\u036f'; ++ch) setName(ch);
229     }
230 
231     //private final static boolean isNameStartChar(char ch) {
232     protected boolean isNameStartChar(char ch) {
233         return (ch < LOOKUP_MAX_CHAR && lookupNameStartChar[ ch ])
234             || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027')
235             || (ch >= '\u202A' &&  ch <= '\u218F')
236             || (ch >= '\u2800' &&  ch <= '\uFFEF')
237             ;
238 
239         //      if(ch < LOOKUP_MAX_CHAR) return lookupNameStartChar[ ch ];
240         //      else return ch <= '\u2027'
241         //              || (ch >= '\u202A' &&  ch <= '\u218F')
242         //              || (ch >= '\u2800' &&  ch <= '\uFFEF')
243         //              ;
244         //return false;
245         //        return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == ':'
246         //          || (ch >= '0' && ch <= '9');
247         //        if(ch < LOOKUP_MAX_CHAR) return (lookupNameStartChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0;
248         //        if(ch <= '\u2027') return true;
249         //        //[#x202A-#x218F]
250         //        if(ch < '\u202A') return false;
251         //        if(ch <= '\u218F') return true;
252         //        // added pairts [#x2800-#xD7FF] | [#xE000-#xFDCF] | [#xFDE0-#xFFEF] | [#x10000-#x10FFFF]
253         //        if(ch < '\u2800') return false;
254         //        if(ch <= '\uFFEF') return true;
255         //        return false;
256 
257 
258         // else return (supportXml11 && ( (ch < '\u2027') || (ch > '\u2029' && ch < '\u2200') ...
259     }
260 
261     //private final static boolean isNameChar(char ch) {
262     protected boolean isNameChar(char ch) {
263         //return isNameStartChar(ch);
264 
265         //        if(ch < LOOKUP_MAX_CHAR) return (lookupNameChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0;
266 
267         return (ch < LOOKUP_MAX_CHAR && lookupNameChar[ ch ])
268             || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027')
269             || (ch >= '\u202A' &&  ch <= '\u218F')
270             || (ch >= '\u2800' &&  ch <= '\uFFEF')
271             ;
272         //return false;
273         //        return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == ':'
274         //          || (ch >= '0' && ch <= '9');
275         //        if(ch < LOOKUP_MAX_CHAR) return (lookupNameStartChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0;
276 
277         //else return
278         //  else if(ch <= '\u2027') return true;
279         //        //[#x202A-#x218F]
280         //        else if(ch < '\u202A') return false;
281         //        else if(ch <= '\u218F') return true;
282         //        // added pairts [#x2800-#xD7FF] | [#xE000-#xFDCF] | [#xFDE0-#xFFEF] | [#x10000-#x10FFFF]
283         //        else if(ch < '\u2800') return false;
284         //        else if(ch <= '\uFFEF') return true;
285         //else return false;
286     }
287 
288     protected boolean isS(char ch) {
289         return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t');
290         // || (supportXml11 && (ch == '\u0085' || ch == '\u2028');
291     }
292 
293     //protected boolean isChar(char ch) { return (ch < '\uD800' || ch > '\uDFFF')
294     //  ch != '\u0000' ch < '\uFFFE'
295 
296 
297     // attribute stack
298     protected int attributeCount;
299     protected String attributeName[];
300     protected int attributeNameHash[];
301     //protected int attributeNameStart[];
302     //protected int attributeNameEnd[];
303     protected String attributePrefix[];
304     protected String attributeUri[];
305     protected String attributeValue[];
306     //protected int attributeValueStart[];
307     //protected int attributeValueEnd[];
308 
309 
310     /***
311      * Make sure that in attributes temporary array is enough space.
312      */
313     protected  void ensureAttributesCapacity(int size) {
314         int attrPosSize = attributeName != null ? attributeName.length : 0;
315         if(size >= attrPosSize) {
316             int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25
317             if(TRACE_SIZING) {
318                 System.err.println("attrPosSize "+attrPosSize+" ==> "+newSize);
319             }
320             boolean needsCopying = attrPosSize > 0;
321             String[] arr = null;
322 
323             arr = new String[newSize];
324             if(needsCopying) System.arraycopy(attributeName, 0, arr, 0, attrPosSize);
325             attributeName = arr;
326 
327             arr = new String[newSize];
328             if(needsCopying) System.arraycopy(attributePrefix, 0, arr, 0, attrPosSize);
329             attributePrefix = arr;
330 
331             arr = new String[newSize];
332             if(needsCopying) System.arraycopy(attributeUri, 0, arr, 0, attrPosSize);
333             attributeUri = arr;
334 
335             arr = new String[newSize];
336             if(needsCopying) System.arraycopy(attributeValue, 0, arr, 0, attrPosSize);
337             attributeValue = arr;
338 
339             if( ! allStringsInterned ) {
340                 int[] iarr = new int[newSize];
341                 if(needsCopying) System.arraycopy(attributeNameHash, 0, iarr, 0, attrPosSize);
342                 attributeNameHash = iarr;
343             }
344 
345             arr = null;
346             // //assert attrUri.length > size
347         }
348     }
349 
350     // namespace stack
351     protected int namespaceEnd;
352     protected String namespacePrefix[];
353     protected int namespacePrefixHash[];
354     protected String namespaceUri[];
355 
356     protected void ensureNamespacesCapacity(int size) {
357         int namespaceSize = namespacePrefix != null ? namespacePrefix.length : 0;
358         if(size >= namespaceSize) {
359             int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25
360             if(TRACE_SIZING) {
361                 System.err.println("namespaceSize "+namespaceSize+" ==> "+newSize);
362             }
363             String[] newNamespacePrefix = new String[newSize];
364             String[] newNamespaceUri = new String[newSize];
365             if(namespacePrefix != null) {
366                 System.arraycopy(
367                     namespacePrefix, 0, newNamespacePrefix, 0, namespaceEnd);
368                 System.arraycopy(
369                     namespaceUri, 0, newNamespaceUri, 0, namespaceEnd);
370             }
371             namespacePrefix = newNamespacePrefix;
372             namespaceUri = newNamespaceUri;
373 
374 
375             if( ! allStringsInterned ) {
376                 int[] newNamespacePrefixHash = new int[newSize];
377                 if(namespacePrefixHash != null) {
378                     System.arraycopy(
379                         namespacePrefixHash, 0, newNamespacePrefixHash, 0, namespaceEnd);
380                 }
381                 namespacePrefixHash = newNamespacePrefixHash;
382             }
383             //prefixesSize = newSize;
384             // //assert nsPrefixes.length > size && nsPrefixes.length == newSize
385         }
386     }
387 
388   // local namespace stack
389   protected int localNamespaceEnd;
390   protected String localNamespacePrefix[];
391   protected int localNamespacePrefixHash[];
392   protected String localNamespaceUri[];
393   
394   protected void ensureLocalNamespacesCapacity(int size) {
395     int localNamespaceSize = localNamespacePrefix != null ? localNamespacePrefix.length : 0;
396     if(size >= localNamespaceSize) {
397       int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25
398       if(TRACE_SIZING) {
399         System.err.println("localNamespaceSize "+localNamespaceSize+" ==> "+newSize);
400       }
401       String[] newLocalNamespacePrefix = new String[newSize];
402       String[] newLocalNamespaceUri = new String[newSize];
403       if(localNamespacePrefix != null) {
404         System.arraycopy(
405                          localNamespacePrefix, 0, newLocalNamespacePrefix, 0, localNamespaceEnd);
406         System.arraycopy(
407                          localNamespaceUri, 0, newLocalNamespaceUri, 0, localNamespaceEnd);
408       }
409       localNamespacePrefix = newLocalNamespacePrefix;
410       localNamespaceUri = newLocalNamespaceUri;
411       
412       
413       if( ! allStringsInterned ) {
414         int[] newLocalNamespacePrefixHash = new int[newSize];
415         if(localNamespacePrefixHash != null) {
416           System.arraycopy(
417                            localNamespacePrefixHash, 0, newLocalNamespacePrefixHash, 0, localNamespaceEnd);
418         }
419         localNamespacePrefixHash = newLocalNamespacePrefixHash;
420       }
421       //prefixesSize = newSize;
422       // //assert nsPrefixes.length > size && nsPrefixes.length == newSize
423     }
424   }
425   
426   public int getLocalNamespaceCount() {
427     int startNs = elNamespaceCount[ depth - 1 ];
428     return namespaceEnd-startNs;
429   }
430   
431   // This returns an array of all the namespaces uris defined
432   // in the scope of this element
433   // To index into it you need to add the namespaceCount from
434   // the previous depth
435   private String getLocalNamespaceURI(int pos) {
436     return namespaceUri[pos];
437   }
438   
439 
440   // This returns an array of all the namespaces prefixes defined
441   // in the scope of this element
442   // the prefix for the default ns is bound to null
443   // To index into it you need to add the namespaceCount from
444   // the previous depth
445   private String getLocalNamespacePrefix(int pos){
446     return namespacePrefix[pos];
447   }
448   
449     /***
450      * simplistic implementation of hash function that has <b>constant</b>
451      * time to compute - so it also means diminishing hash quality for long strings
452      * but for XML parsing it should be good enough ...
453      */
454     protected static final int fastHash( char ch[], int off, int len ) {
455         if(len == 0) return 0;
456         //assert len >0
457         int hash = ch[off]; // hash at beginnig
458         //try {
459         hash = (hash << 7) + ch[ off +  len - 1 ]; // hash at the end
460         //} catch(ArrayIndexOutOfBoundsException aie) {
461         //    aie.printStackTrace(); //should never happen ...
462         //    throw new RuntimeException("this is violation of pre-condition");
463         //}
464         if(len > 16) hash = (hash << 7) + ch[ off + (len / 4)];  // 1/4 from beginning
465         if(len > 8)  hash = (hash << 7) + ch[ off + (len / 2)];  // 1/2 of string size ...
466         // notice that hash is at most done 3 times <<7 so shifted by 21 bits 8 bit value
467         // so max result == 29 bits so it is quite just below 31 bits for long (2^32) ...
468         //assert hash >= 0;
469         return  hash;
470     }
471 
472     // entity replacement stack
473     protected int entityEnd;
474     protected String entityName[];
475     protected char[] entityNameBuf[];
476     protected int entityNameHash[];
477     protected char[] entityReplacementBuf[];
478     protected String entityReplacement[];
479 
480 
481     protected void ensureEntityCapacity() {
482         int entitySize = entityReplacementBuf != null ? entityReplacementBuf.length : 0;
483         if(entityEnd >= entitySize) {
484             int newSize = entityEnd > 7 ? 2 * entityEnd : 8; // = lucky 7 + 1 //25
485             if(TRACE_SIZING) {
486                 System.err.println("entitySize "+entitySize+" ==> "+newSize);
487             }
488             String[] newEntityName = new String[newSize];
489             char[] newEntityNameBuf[] = new char[newSize][];
490             String[] newEntityReplacement = new String[newSize];
491             char[] newEntityReplacementBuf[] = new char[newSize][];
492             if(entityName != null) {
493                 System.arraycopy(entityName, 0, newEntityName, 0, entityEnd);
494                 System.arraycopy(entityReplacementBuf, 0, newEntityReplacement, 0, entityEnd);
495                 System.arraycopy(entityReplacement, 0, newEntityReplacement, 0, entityEnd);
496                 System.arraycopy(entityReplacementBuf, 0, newEntityReplacementBuf, 0, entityEnd);
497             }
498             entityName = newEntityName;
499             entityNameBuf = newEntityNameBuf;
500             entityReplacement = newEntityReplacement;
501             entityReplacementBuf = newEntityReplacementBuf;
502 
503             if( ! allStringsInterned ) {
504                 int[] newEntityNameHash = new int[newSize];
505                 if(entityNameHash != null) {
506                     System.arraycopy(entityNameHash, 0, newEntityNameHash, 0, entityEnd);
507                 }
508                 entityNameHash = newEntityNameHash;
509             }
510         }
511     }
512 
513     // input buffer management
514     protected static final int READ_CHUNK_SIZE = 8*1024; //max data chars in one read() call
515     protected Reader reader;
516     protected String inputEncoding;
517 
518 
519     protected int bufLoadFactor = 95;  // 99%
520     //protected int bufHardLimit;  // only matters when expanding
521 
522     protected char buf[] = new char[
523         Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 256 ];
524     protected int bufSoftLimit = ( bufLoadFactor * buf.length ) /100; // desirable size of buffer
525 
526 
527     protected int bufAbsoluteStart; // this is buf
528     protected int bufStart;
529     protected int bufEnd;
530     protected int pos;
531     protected int posStart;
532     protected int posEnd;
533 
534     protected char pc[] = new char[
535         Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 64 ];
536     protected int pcStart;
537     protected int pcEnd;
538 
539 
540     // parsing state
541     //protected boolean needsMore;
542     //protected boolean seenMarkup;
543     protected boolean usePC;
544 
545 
546     protected boolean seenStartTag;
547     protected boolean seenEndTag;
548     protected boolean pastEndTag;
549     protected boolean seenAmpersand;
550     protected boolean seenMarkup;
551     protected boolean seenDocdecl;
552 
553     // transient variable set during each call to next/Token()
554     protected boolean tokenize;
555     protected String text;
556     protected String entityRefName;
557 
558 
559     private void reset() {
560         //System.out.println("reset() called");
561         lineNumber = 1;
562         columnNumber = 0;
563         seenRoot = false;
564         reachedEnd = false;
565         eventType = XMLEvent.START_DOCUMENT;
566         emptyElementTag = false;
567 
568         depth = 0;
569 
570         attributeCount = 0;
571 
572         namespaceEnd = 0;
573         localNamespaceEnd = 0;
574 
575         entityEnd = 0;
576 
577         reader = null;
578         inputEncoding = null;
579 
580         bufAbsoluteStart = 0;
581         bufEnd = bufStart = 0;
582         pos = posStart = posEnd = 0;
583 
584         pcEnd = pcStart = 0;
585 
586         usePC = false;
587 
588         seenStartTag = false;
589         seenEndTag = false;
590         pastEndTag = false;
591         seenAmpersand = false;
592         seenMarkup = false;
593         seenDocdecl = false;
594         resetStringCache();
595 
596     }
597 
598 
599     public MXParser() {
600     }
601 
602     /***
603      * Method setFeature
604      *
605      * @param    name                a  String
606      * @param    state               a  boolean
607      *
608      * @throws   XMLStreamException
609      *
610      */
611     public void setFeature(String name,
612                            boolean state) throws XMLStreamException
613     {
614         if(name == null) throw new IllegalArgumentException("feature name should not be nulll");
615         if(FEATURE_PROCESS_NAMESPACES.equals(name)) {
616             if(eventType != XMLEvent.START_DOCUMENT) throw new XMLStreamException(
617                     "namespace processing feature can only be changed before parsing",
618                     getLocation());
619             processNamespaces = state;
620             //        } else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
621             //      if(type != XMLEvent.START_DOCUMENT) throw new XMLStreamException(
622             //              "namespace reporting feature can only be changed before parsing",
623             // getLineNumber(), getColumnNumber(), getPositionDescription(), null);
624             //            reportNsAttribs = state;
625         } else if(FEATURE_NAMES_INTERNED.equals(name)) {
626             if(state != false) {
627                 throw new XMLStreamException(
628                     "interning names in this implementation is not supported");
629             }
630         } else if(FEATURE_PROCESS_DOCDECL.equals(name)) {
631             if(state != false) {
632                 throw new XMLStreamException(
633                     "processing DOCDECL is not supported");
634             }
635             //} else if(REPORT_DOCDECL.equals(name)) {
636             //    paramNotifyDoctype = state;
637         } else if(FEATURE_XML_ROUNDTRIP.equals(name)) {
638             if(state == false) {
639                 throw new XMLStreamException(
640                     "roundtrip feature can not be switched off");
641             }
642         } else {
643             throw new XMLStreamException("unknown feature "+name);
644         }
645     }
646 
647     /*** Unknown properties are <string>always</strong> returned as false */
648     public boolean getFeature(String name)
649     {
650         if(name == null) throw new IllegalArgumentException("feature name should not be nulll");
651         if(FEATURE_PROCESS_NAMESPACES.equals(name)) {
652             return processNamespaces;
653             //        } else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
654             //            return reportNsAttribs;
655         } else if(FEATURE_NAMES_INTERNED.equals(name)) {
656             return false;
657         } else if(FEATURE_PROCESS_DOCDECL.equals(name)) {
658             return false;
659             //} else if(REPORT_DOCDECL.equals(name)) {
660             //    return paramNotifyDoctype;
661         } else if(FEATURE_XML_ROUNDTRIP.equals(name)) {
662             return true; //roundtripSupported;
663         }
664         return false;
665     }
666 
667     public void setProperty(String name,
668                             Object value)
669         throws XMLStreamException
670     {
671         throw new XMLStreamException("unsupported property: '"+name+"'");
672     }
673 
674 
675   public boolean checkForXMLDecl()
676     throws XMLStreamException
677   {
678     try {
679       BufferedReader breader = new BufferedReader(reader,7);
680       reader = breader;
681       breader.mark(7);
682       if (breader.read() == '<' &&
683           breader.read() == '?' &&
684           breader.read() == 'x' &&
685           breader.read() == 'm' &&
686           breader.read() == 'l') {
687         breader.reset();
688         return true;
689       }
690       breader.reset();
691       return false;
692     } catch (IOException e) {
693       throw new XMLStreamException(e);
694     }
695   }
696 
697     public void setInput(Reader in)
698       throws XMLStreamException
699     {
700         reset();
701         reader = in;
702         if(checkForXMLDecl()) {
703           next();
704         }
705     }
706   public void setInput(java.io.InputStream in)
707     throws XMLStreamException
708     {
709       try {
710       setInput(com.bea.xml.stream.reader.XmlReader.createReader(in));
711       } catch (Exception e) {
712         throw new XMLStreamException(e);
713       }
714     }
715 
716     public void setInput(java.io.InputStream inputStream, String inputEncoding)
717         throws XMLStreamException
718     {
719         if(inputStream == null) {
720             throw new IllegalArgumentException("input stream can not be null");
721         }
722         Reader reader;
723         if(inputEncoding != null) {
724             try {
725                 if(inputEncoding != null) {
726                     reader = new InputStreamReader(inputStream, inputEncoding);
727                 } else {
728                     reader = new InputStreamReader(inputStream);
729                 }
730             } catch (UnsupportedEncodingException une) {
731                 throw new XMLStreamException(
732                     "could not create reader for encoding "+inputEncoding+" : "+une,
733                     getLocation(), une);
734             }
735         } else {
736             reader = new InputStreamReader(inputStream);
737         }
738         setInput(reader);
739         //must be  here as reest() was called in setInput() and has set this.inputEncoding to null ...
740         this.inputEncoding = inputEncoding;
741     }
742 
743     public String getInputEncoding() {
744         return inputEncoding;
745     }
746 
747     public void defineEntityReplacementText(String entityName,
748                                             String replacementText)
749         throws XMLStreamException
750     {
751         //      throw new XMLStreamException("not allowed");
752 
753         //protected char[] entityReplacement[];
754         ensureEntityCapacity();
755 
756         // this is to make sure that if interning works we wil take advatage of it ...
757         this.entityName[entityEnd] = newString(entityName.toCharArray(), 0, entityName.length());
758         entityNameBuf[entityEnd] = entityName.toCharArray();
759 
760         entityReplacement[entityEnd] = replacementText;
761         entityReplacementBuf[entityEnd] = replacementText.toCharArray();
762         if(!allStringsInterned) {
763             entityNameHash[ entityEnd ] =
764                 fastHash(entityNameBuf[entityEnd], 0, entityNameBuf[entityEnd].length);
765         }
766         ++entityEnd;
767         //TODO disallow < or & in entity replacement text (or ]]>???)
768         // TOOD keepEntityNormalizedForAttributeValue cached as well ...
769     }
770 
771 
772   public int getNamespaceCount()
773   {
774     return getNamespaceCount(depth);
775   }
776 
777   public int getNamespaceCount(int depth)
778   {
779     if(processNamespaces == false || depth == 0) {
780       return 0;
781     }
782     //int maxDepth = eventType == XMLEvent.END_ELEMENT ? this.depth + 1 : this.depth;
783     //if(depth < 0 || depth > maxDepth) throw new IllegalArgumentException(
784     if(depth < 0) throw new IllegalArgumentException("namespace count may be 0.."+this.depth+" not "+depth);
785     return elNamespaceCount[ depth ]-elNamespaceCount[depth-1];
786   }
787   
788   public String getNamespacePrefix(int pos)
789   {
790     int currentDepth = depth;
791     int end = getNamespaceCount(currentDepth);//eventType == XMLEvent.END_ELEMENT ? elNamespaceCount[ depth + 1 ] : namespaceEnd;
792     int newpos = pos + elNamespaceCount[currentDepth-1];
793     if(pos < end) {
794       return namespacePrefix[ newpos ];
795     } else {
796       throw new ArrayIndexOutOfBoundsException(
797                                                "position "+pos+" exceeded number of available namespaces "+end);
798     }
799   }
800 
801     public String getNamespaceURI(int pos)
802     {
803       int currentDepth = depth;
804       int end = getNamespaceCount(currentDepth); //eventType == XMLEvent.END_ELEMENT ? elNamespaceCount[ depth + 1 ] : namespaceEnd;
805       int newpos = pos + elNamespaceCount[currentDepth-1];
806       if(pos < end) {
807         return namespaceUri[ newpos ];
808        } else {
809          throw new ArrayIndexOutOfBoundsException(
810                                               "position "+pos+" exceedded number of available namespaces "+end);
811        }
812     }
813 
814     public String getNamespaceURI( String prefix )
815         //throws XMLStreamException
816     {
817         //int count = namespaceCount[ depth ];
818         if(prefix != null && !"".equals(prefix)) {
819             for( int i = namespaceEnd -1; i >= 0; i--) {
820                 if( prefix.equals( namespacePrefix[ i ] ) ) {
821                     return namespaceUri[ i ];
822                 }
823             }
824             if("xml".equals( prefix )) {
825                 return XML_URI;
826             } else if("xmlns".equals( prefix )) {
827                 return XMLNS_URI;
828             }
829         } else {
830             for( int i = namespaceEnd -1; i >= 0; i--) {
831                 if( namespacePrefix[ i ]  == null ) {
832                     return namespaceUri[ i ];
833                 }
834             }
835 
836         }
837         return null;
838     }
839  
840     public int getDepth()
841     {
842         return depth;
843     }
844 
845 
846     private static int findFragment(int bufMinPos, char[] b, int start, int end) {
847         //System.err.println("bufStart="+bufStart+" b="+printable(new String(b, start, end - start))+" start="+start+" end="+end);
848         if(start < bufMinPos) {
849             start = bufMinPos;
850             if(start > end) start = end;
851             return start;
852         }
853         if(end - start > 65) {
854             start = end - 10; // try to find good location
855         }
856         int i = start + 1;
857         while(--i > bufMinPos) {
858             if((end - i) > 65) break;
859             char c = b[i];
860             if(c == '<' && (start - i) > 10) break;
861         }
862         return i;
863     }
864 
865 
866     /***
867      * Return string describing current position of parsers as
868      * text 'STATE [seen %s...] @line:column'.
869      */
870     public String getPositionDescription ()
871     {
872         String fragment = null;
873         if(posStart <= pos) {
874             int start = findFragment(0, buf, posStart, pos);
875             //System.err.println("start="+start);
876             if(start < pos) {
877                 fragment = new String(buf, start, pos - start);
878             }
879             if(bufAbsoluteStart > 0 || start > 0) fragment = "..." + fragment;
880         }
881         //        return " at line "+tokenizerPosRow
882         //            +" and column "+(tokenizerPosCol-1)
883         //            +(fragment != null ? " seen "+printable(fragment)+"..." : "");
884         return " "+//TYPES[ eventType ] +
885             (fragment != null ? " seen "+printable(fragment)+"..." : "")+
886             " @"+getLineNumber()+":"+getColumnNumber();
887     }
888 
889     public int getLineNumber()
890     {
891         return lineNumber;
892     }
893 
894     public int getColumnNumber()
895     {
896         return columnNumber;
897     }
898 
899   public String getLocationURI() { return null; }
900 
901     public boolean isWhiteSpace()
902     // throws XMLStreamException
903     {
904         if(eventType == XMLEvent.CHARACTERS || eventType == XMLEvent.CDATA) {
905             if(usePC) {
906                 for (int i = pcStart; i <pcEnd; i++)
907                 {
908                     if(!isS(pc[ i ])) return false;
909                 }
910                 return true;
911             } else {
912                 for (int i = posStart; i <posEnd; i++)
913                 {
914                     if(!isS(buf[ i ])) return false;
915                 }
916                 return true;
917             }
918         } else if(eventType == /* XMLEvent.IGNORABLE_WHITESPACE */ XMLEvent.SPACE) {
919             return true;
920 
921         // COMMENT - cwitt : our interface doesn't define this
922         // (and is 'meant to be slightly different anyway' - quote cfry)
923         // throw new XMLStreamException("no content available to check for whitespaces");
924 
925         } else {
926             return false;
927         }
928     }
929   
930     public String getText()
931     {
932         if(eventType == XMLEvent.START_DOCUMENT || eventType == XMLEvent.END_DOCUMENT) {
933             //throw new XMLStreamException("no content available to read");
934             //      if(roundtripSupported) {
935             //          text = new String(buf, posStart, posEnd - posStart);
936             //      } else {
937             return null;
938             //      }
939         } else if(eventType == XMLEvent.ENTITY_REFERENCE) {
940             return text;
941         }
942 
943         if(usePC) {
944           text = new String(pc, pcStart, pcEnd - pcStart);
945         } else {
946           text = new String(buf, posStart, posEnd - posStart);
947         }
948         return text;
949     }
950 
951     public String getNamespaceURI()
952     {
953         if(eventType == XMLEvent.START_ELEMENT ||
954            eventType == XMLEvent.END_ELEMENT) {
955             return processNamespaces ? elUri[ depth  ] : NO_NAMESPACE;
956         }
957         return null;
958     }
959 
960     public String getLocalName()
961     {
962         if(eventType == XMLEvent.START_ELEMENT) {
963             //return elName[ depth - 1 ] ;
964             return elName[ depth ] ;
965         } else if(eventType == XMLEvent.END_ELEMENT) {
966             return elName[ depth ] ;
967         } else if(eventType == XMLEvent.ENTITY_REFERENCE) {
968             if(entityRefName == null) {
969                 entityRefName = newString(buf, posStart, posEnd - posStart);
970             }
971             return entityRefName;
972         } else {
973             return null;
974         }
975     }
976 
977     public String getPrefix()
978     {
979         if(eventType == XMLEvent.START_ELEMENT ||
980            eventType == XMLEvent.END_ELEMENT) {
981             return elPrefix[ depth ] ;
982         }
983         return null;
984      }
985 
986 
987     public boolean isEmptyElementTag() throws XMLStreamException
988     {
989         if(eventType != XMLEvent.START_ELEMENT) throw new XMLStreamException(
990                 "parser must be on XMLEvent.START_ELEMENT to check for empty element",
991                 getLocation());
992         return emptyElementTag;
993     }
994 
995     public int getAttributeCount()
996     {
997         if(eventType != XMLEvent.START_ELEMENT) return -1;
998         return attributeCount;
999     }
1000 
1001     public String getAttributeNamespace(int index)
1002     {
1003         if(eventType != XMLEvent.START_ELEMENT) throw new IndexOutOfBoundsException(
1004                 "only XMLEvent.START_ELEMENT can have attributes");
1005         if(processNamespaces == false) return NO_NAMESPACE;
1006         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
1007                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
1008         return attributeUri[ index ];
1009     }
1010 
1011     public String getAttributeLocalName(int index)
1012     {
1013         if(eventType != XMLEvent.START_ELEMENT) throw new IndexOutOfBoundsException(
1014                 "only XMLEvent.START_ELEMENT can have attributes");
1015         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
1016                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
1017         return attributeName[ index ];
1018     }
1019 
1020     public String getAttributePrefix(int index)
1021     {
1022         if(eventType != XMLEvent.START_ELEMENT) throw new IndexOutOfBoundsException(
1023                 "only XMLEvent.START_ELEMENT can have attributes");
1024         if(processNamespaces == false) return null;
1025         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
1026                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
1027         return attributePrefix[ index ];
1028     }
1029 
1030     public String getAttributeType(int index) {
1031         if(eventType != XMLEvent.START_ELEMENT) throw new IndexOutOfBoundsException(
1032                 "only XMLEvent.START_ELEMENT can have attributes");
1033         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
1034                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
1035         return "CDATA";
1036     }
1037 
1038     public boolean isAttributeSpecified(int index) {
1039         if(eventType != XMLEvent.START_ELEMENT) throw new IndexOutOfBoundsException(
1040                 "only XMLEvent.START_ELEMENT can have attributes");
1041         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
1042                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
1043         return false;
1044     }
1045 
1046     public String getAttributeValue(int index)
1047     {
1048         if(eventType != XMLEvent.START_ELEMENT) throw new IndexOutOfBoundsException(
1049                 "only XMLEvent.START_ELEMENT can have attributes");
1050         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
1051                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
1052         return attributeValue[ index ];
1053     }
1054 
1055     public String getAttributeValue(String namespace,
1056                                     String name)
1057     {
1058         if(eventType != XMLEvent.START_ELEMENT) throw new IndexOutOfBoundsException(
1059                 "only XMLEvent.START_ELEMENT can have attributes");
1060         if(name == null) {
1061             throw new IllegalArgumentException("attribute name can not be null");
1062         }
1063         // TODO make check if namespace is interned!!! etc. for names!!!
1064         if(namespace != null) {
1065             for(int i = 0; i < attributeCount; ++i) {
1066                 if(namespace.equals(attributeUri[i])
1067                    && name.equals(attributeName[i]))
1068                 {
1069                     return attributeValue[i];
1070                 }
1071             }
1072         } else {
1073             for(int i = 0; i < attributeCount; ++i) {
1074                 if(name.equals(attributeName[i]))
1075                 {
1076                     return attributeValue[i];
1077                 }
1078             }
1079         }
1080         return null;
1081     }
1082   
1083  
1084 
1085     public int getEventType() {
1086         return eventType;
1087     }
1088 
1089     public void require(int type, String namespace, String name)
1090         throws XMLStreamException
1091     {
1092         if (type != getEventType()
1093             || (namespace != null && !namespace.equals (getNamespaceURI()))
1094             || (name != null && !name.equals (getLocalName ())) )
1095         {
1096             throw new XMLStreamException (
1097                 "expected event "+ElementTypeNames.getEventTypeString(type)
1098                     +(name != null ? " with name '"+name+"'" : "")
1099                     +(namespace != null && name != null ? " and" : "")
1100                     +(namespace != null ? " with namespace '"+namespace+"'" : "")
1101                     +" but got"
1102                     +(type != getEventType() ? " "+ElementTypeNames.getEventTypeString(getEventType()) : "")
1103                     +(name != null && getLocalName() != null && !name.equals (getName ())
1104                           ? " name '"+getLocalName()+"'" : "")
1105                     +(namespace != null && name != null
1106                           && getLocalName() != null && !name.equals (getName ())
1107                           && getNamespaceURI() != null && !namespace.equals (getNamespaceURI())
1108                           ? " and" : "")
1109                     +(namespace != null && getNamespaceURI() != null && !namespace.equals (getNamespaceURI())
1110                           ? " namespace '"+getNamespaceURI()+"'" : "")
1111                     +(" (postion:"+ getPositionDescription())+")");
1112         }
1113     }
1114 
1115     public String nextText() throws XMLStreamException
1116     {
1117         if(getEventType() != XMLEvent.START_ELEMENT) {
1118             throw new XMLStreamException(
1119                 "parser must be on XMLEvent.START_ELEMENT to read next text",
1120                 getLocation());
1121         }
1122         int eventType = next();
1123         if(eventType == XMLEvent.CHARACTERS) {
1124             String result = getText();
1125             eventType = next();
1126             if(eventType != XMLEvent.END_ELEMENT) {
1127                 throw new XMLStreamException(
1128                     "TEXT must be immediately followed by XMLEvent.END_ELEMENT and not "
1129                     +ElementTypeNames.getEventTypeString(getEventType()),
1130                     getLocation());
1131             }
1132             return result;
1133         } else if(eventType == XMLEvent.END_ELEMENT) {
1134             return "";
1135         } else {
1136             throw new XMLStreamException(
1137                 "parser must be on XMLEvent.START_ELEMENT or TEXT to read text",
1138                 getLocation());
1139         }
1140     }
1141 
1142   public int nextTag()
1143     throws XMLStreamException
1144   {
1145     next();
1146     if((eventType == XMLEvent.CHARACTERS && isWhiteSpace())||
1147        eventType == XMLEvent.COMMENT) {  // skip whitespace
1148       next();
1149     }
1150     if (eventType != XMLEvent.START_ELEMENT && eventType != XMLEvent.END_ELEMENT) {
1151       throw new XMLStreamException("expected XMLEvent.START_ELEMENT or XMLEvent.END_ELEMENT not "
1152                                    +ElementTypeNames.getEventTypeString(getEventType()),
1153                                    getLocation());
1154     }
1155     return eventType;
1156   }
1157 
1158   public String getElementText()
1159     throws XMLStreamException
1160   {
1161     StringBuffer buf = new StringBuffer();
1162     if(getEventType() != START_ELEMENT)
1163       throw new XMLStreamException(
1164         "Precondition for readText is getEventType() == START_ELEMENT");
1165     do {
1166       if(next() == END_DOCUMENT)
1167         throw new XMLStreamException("Unexpected end of Document");
1168       if(isStartElement())
1169         throw new XMLStreamException("Unexpected Element start");
1170       if(isCharacters() || getEventType() == XMLEvent.ENTITY_REFERENCE)
1171         buf.append(getText());
1172     } while(!isEndElement());
1173     return buf.toString();
1174   }
1175 
1176   public int next() throws XMLStreamException {
1177     tokenize = true;
1178     pcEnd = pcStart = 0;
1179     usePC = false;
1180     return nextImpl();
1181   }
1182   
1183   public int nextToken() throws XMLStreamException {
1184     tokenize = true;
1185     return nextImpl();
1186   }
1187   
1188   public int nextElement() throws XMLStreamException {
1189     return nextTag();
1190   }
1191   
1192   public boolean hasNext() throws XMLStreamException {
1193     return !(eventType == XMLEvent.END_DOCUMENT);
1194   }
1195 
1196   public void skip() throws XMLStreamException {
1197     nextToken();
1198   }
1199 
1200   public void close() throws XMLStreamException {
1201 
1202   }
1203   
1204   public boolean isStartElement() {
1205     return (eventType == XMLEvent.START_ELEMENT);
1206   }
1207   
1208   public boolean isEndElement() {
1209     return (eventType == XMLEvent.END_ELEMENT);
1210   }
1211   
1212   public boolean isCharacters() {
1213     return (eventType == XMLEvent.CHARACTERS);
1214   }
1215   
1216   public boolean isEOF() {
1217     return (eventType == XMLEvent.END_DOCUMENT);
1218   }
1219   
1220   public boolean moveToStartElement() throws XMLStreamException {
1221     if (isStartElement()) return true;
1222     while(hasNext()) {
1223       if (isStartElement()) return true;
1224       else
1225         next();
1226     }
1227     return false;
1228   }
1229   
1230   public boolean moveToStartElement(String localName)
1231     throws XMLStreamException
1232   {
1233     if (localName == null) return false;
1234     while( moveToStartElement() ) {
1235       if (localName.equals(getLocalName())) return true;
1236       if (!hasNext()) return false;
1237       next();
1238     }
1239     return false;
1240   }
1241   
1242   public boolean moveToStartElement(String localName, String namespaceUri)
1243     throws XMLStreamException
1244   {
1245     if (localName == null || namespaceUri == null) return false;
1246     while(moveToStartElement(localName)) {
1247       if(namespaceUri.equals(getNamespaceURI())) return true;
1248       if (!hasNext()) return false;
1249       next();
1250     }
1251     return false;
1252   }
1253   
1254   public boolean moveToEndElement() throws XMLStreamException {
1255     if (isEndElement()) return true;
1256     while (hasNext()) {
1257       if (isEndElement()) return true;
1258       else
1259         next();
1260     }
1261     return false;
1262   }
1263   
1264   public boolean moveToEndElement(String localName)
1265     throws XMLStreamException
1266   {
1267     if (localName == null) return false;
1268     while( moveToEndElement() ) {
1269       if (localName.equals(getLocalName())) return true;
1270       if (!hasNext()) return false;
1271       next();
1272     }
1273     return false;
1274   }
1275   
1276   public boolean moveToEndElement(String localName, String namespaceUri)
1277     throws XMLStreamException
1278   {
1279     if (localName == null || namespaceUri == null) return false;
1280     while(moveToEndElement(localName)) {
1281       if(namespaceUri.equals(getNamespaceURI())) return true;
1282       if (!hasNext()) return false;
1283       next();
1284     }
1285     return false;
1286   }
1287   
1288   public boolean hasAttributes() {
1289     if (getAttributeCount() > 0)
1290       return true;
1291     return false;
1292   }
1293   
1294   public boolean hasNamespaces() {
1295     if(getNamespaceCount() > 0)
1296       return true;
1297     return false;
1298   }
1299 
1300   public Iterator getAttributes() {
1301     if (!hasAttributes()) return EmptyIterator.emptyIterator;
1302     int attributeCount = getAttributeCount();
1303     ArrayList atts = new ArrayList();
1304     for (int i = 0; i < attributeCount; i++){
1305       atts.add(new AttributeBase(getAttributePrefix(i),
1306                                  getAttributeNamespace(i),
1307                                  getAttributeLocalName(i),
1308                                  getAttributeValue(i),
1309                                  getAttributeType(i)));
1310     }
1311     return atts.iterator();
1312   }
1313 
1314   public Iterator internalGetNamespaces(int depth,
1315                                                  int namespaceCount) {
1316     ArrayList ns = new ArrayList();
1317     int startNs = elNamespaceCount[ depth - 1 ];
1318     for (int i = 0; i < namespaceCount; i++){
1319       String prefix = getLocalNamespacePrefix(i+startNs);
1320       if(prefix == null){
1321         ns.add(new NamespaceBase(getLocalNamespaceURI(i+startNs)));
1322       } else {
1323         ns.add(new NamespaceBase(prefix,
1324                                  getLocalNamespaceURI(i+startNs)));
1325       }
1326     }
1327     return ns.iterator();
1328   }
1329 
1330 
1331   public Iterator getNamespaces() {
1332     if (!hasNamespaces()) return EmptyIterator.emptyIterator;
1333     int namespaceCount = getLocalNamespaceCount();
1334     return internalGetNamespaces(depth,namespaceCount);
1335   }
1336 
1337   public Iterator getOutOfScopeNamespaces() {
1338     int startNs = elNamespaceCount[ depth-1  ];
1339     int endNs = elNamespaceCount[depth];
1340     int namespaceCount = endNs-startNs;
1341     return internalGetNamespaces(depth,
1342                                  namespaceCount);
1343   }
1344   
1345   public XMLStreamReader subReader() throws XMLStreamException {
1346     return new SubReader(this);
1347   }
1348   
1349   public void recycle() throws XMLStreamException {
1350     reset();
1351   }
1352   
1353   public Reader getTextStream() {
1354     throw new UnsupportedOperationException();
1355   }
1356 
1357   public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length)
1358     throws XMLStreamException {
1359     if (getTextStart()+sourceStart >= getTextLength())
1360       throw new ArrayIndexOutOfBoundsException();
1361     int numCopy;
1362     if (getTextStart()+sourceStart+length < getTextLength())
1363       numCopy = length;
1364     else
1365       numCopy = getTextLength() - (getTextStart()+sourceStart);
1366     System.arraycopy(getTextCharacters(), getTextStart() + sourceStart, target, targetStart, numCopy);
1367     return numCopy;
1368   }
1369                                
1370   public char[] getTextCharacters() {
1371     if( eventType == XMLEvent.CHARACTERS ) {
1372       if(usePC) {
1373         return pc;
1374       } else {
1375         return buf;
1376       }
1377     } else if( eventType == XMLEvent.START_ELEMENT
1378                || eventType == XMLEvent.END_ELEMENT
1379                || eventType == XMLEvent.CDATA
1380                || eventType == XMLEvent.COMMENT
1381                || eventType == XMLEvent.ENTITY_REFERENCE
1382                || eventType == XMLEvent.PROCESSING_INSTRUCTION
1383                || eventType == /* XMLEvent.IGNORABLE_WHITESPACE */ XMLEvent.SPACE
1384                || eventType == XMLEvent.DTD)
1385       {
1386         return buf;
1387       } else if(eventType == XMLEvent.START_DOCUMENT
1388                 || eventType == XMLEvent.END_DOCUMENT) {
1389         return null;
1390       } else {
1391         throw new IllegalArgumentException("unknown text eventType: "+eventType);
1392       }
1393   }
1394 
1395   
1396   public int getTextStart() {
1397     if(usePC) {
1398       return pcStart;
1399     } else {
1400       return posStart;
1401     }
1402   }
1403 
1404   public int getTextLength() {
1405     if(usePC) {
1406       return pcEnd - pcStart;
1407     } else {
1408       return  posEnd - posStart;
1409     }
1410   }
1411 
1412   public boolean hasText() {
1413     return (0 != (eventType & (XMLEvent.CHARACTERS |
1414                                XMLEvent.DTD |
1415                                XMLEvent.COMMENT |
1416                                XMLEvent.ENTITY_REFERENCE)));
1417   }
1418   
1419   public String getValue() {
1420     return getText();
1421   }
1422   
1423   public String getEncoding() {
1424     return getInputEncoding();
1425   }
1426   
1427   public int getCharacterOffset() {
1428     // TODO - cwitt : which buffer are we using?
1429     return posEnd;
1430   }
1431 
1432   private static final String checkNull(String s) {
1433     if (s != null) return s;
1434     else return "";
1435   }
1436 
1437   public QName getAttributeName(int index) {
1438     return new QName(checkNull(getAttributeNamespace(index)),
1439                      getAttributeLocalName(index),
1440                      checkNull(getAttributePrefix(index)));
1441   }
1442 
1443 
1444 
1445   public QName getName() {
1446     return new QName(checkNull(getNamespaceURI()),
1447                      getLocalName(),
1448                      checkNull(getPrefix()));
1449   }
1450   
1451   public boolean hasName() {
1452     return (0 != (eventType  & (XMLEvent.START_ELEMENT
1453                             | XMLEvent.END_ELEMENT
1454                             | XMLEvent.ENTITY_REFERENCE)));
1455   }
1456   
1457   public String getVersion() {
1458     return xmlVersion;
1459   }
1460   
1461   public boolean isStandalone() {
1462     return standalone;
1463   }
1464      public boolean standaloneSet() {
1465     return standaloneSet;
1466   }
1467 
1468   public String getCharacterEncodingScheme() {
1469     return charEncodingScheme;
1470   }
1471   
1472   // COMMENT - cwitt : end of added XMLStreamReader impl
1473   
1474   protected int nextImpl() throws XMLStreamException
1475   {