View Javadoc
1   /* -*-             c-basic-offset: 4; indent-tabs-mode: nil; -*-  //------100-columns-wide------>|*/
2   /*
3    * Copyright (c) 2003 Extreme! Lab, Indiana University. All rights reserved.
4    *
5    * This software is open source. See the bottom of this file for the licence.
6    *
7    * $Id$
8    */
9   
10  package org.codehaus.plexus.metadata.merge;
11  
12  import java.io.EOFException;
13  import java.io.IOException;
14  import java.io.Reader;
15  import java.io.UnsupportedEncodingException;
16  
17  import org.codehaus.plexus.util.ReaderFactory;
18  import org.codehaus.plexus.util.xml.pull.XmlPullParser;
19  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
20  
21  //import java.util.Hashtable;
22  
23  //TODO best handling of interning issues
24  //   have isAllNewStringInterned ???
25  
26  //TODO handling surrogate pairs: http://www.unicode.org/unicode/faq/utf_bom.html#6
27  
28  //TODO review code for use of bufAbsoluteStart when keeping pos between next()/fillBuf()
29  
30  /**
31   * Absolutely minimal implementation of XMLPULL V1 API. Encoding handling done with XmlReader
32   *
33   * @see org.codehaus.plexus.util.xml.XmlReader
34   * @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
35   */
36  
37  public class MXParser
38      implements XmlPullParser
39  {
40      //NOTE: no interning of those strings --> by Java leng spec they MUST be already interned
41      protected final static String XML_URI = "http://www.w3.org/XML/1998/namespace";
42      protected final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
43      protected final static String FEATURE_XML_ROUNDTRIP=
44          //"http://xmlpull.org/v1/doc/features.html#xml-roundtrip";
45          "http://xmlpull.org/v1/doc/features.html#xml-roundtrip";
46      protected final static String FEATURE_NAMES_INTERNED =
47          "http://xmlpull.org/v1/doc/features.html#names-interned";
48      protected final static String PROPERTY_XMLDECL_VERSION =
49          "http://xmlpull.org/v1/doc/properties.html#xmldecl-version";
50      protected final static String PROPERTY_XMLDECL_STANDALONE =
51          "http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone";
52      protected final static String PROPERTY_XMLDECL_CONTENT =
53          "http://xmlpull.org/v1/doc/properties.html#xmldecl-content";
54      protected final static String PROPERTY_LOCATION =
55          "http://xmlpull.org/v1/doc/properties.html#location";
56  
57      
58      protected final static String REPORT_NAMESPACE_PREFIXES =
59          "http://xmlpull.org/v1/doc/features.html#report-namespace-prefixes";
60      /**
61       * Implementation notice:
62       * the is instance variable that controls if newString() is interning.
63       * <p><b>NOTE:</b> newStringIntern <b>always</b> returns interned strings
64       * and newString MAY return interned String depending on this variable.
65       * <p><b>NOTE:</b> by default in this minimal implementation it is false!
66       */
67      protected boolean allStringsInterned;
68  
69      protected boolean usePC;
70      protected boolean seenStartTag;
71      protected boolean seenEndTag;
72      protected boolean pastEndTag;
73      protected boolean seenAmpersand;
74      protected boolean seenMarkup;
75      protected boolean seenDocdecl;
76  
77      // transient variable set during each call to next/Token()
78      protected boolean tokenize;
79      protected String text;
80      protected String entityRefName;
81  
82      protected String xmlDeclVersion;
83      protected Boolean xmlDeclStandalone;
84      protected String xmlDeclContent;
85  
86      // NOTE: features are not resetable and typically defaults to false ...
87      protected boolean processNamespaces;
88      protected boolean roundtripSupported;
89  
90      // global parser state
91      protected String location;
92      protected int lineNumber;
93      protected int columnNumber;
94      protected boolean seenRoot;
95      protected boolean reachedEnd;
96      protected int eventType;
97      protected boolean emptyElementTag;
98      // element stack
99      protected int depth;
100     protected char[] elRawName[];
101     protected int elRawNameEnd[];
102     protected int elRawNameLine[];
103 
104     protected String elName[];
105     protected String elPrefix[];
106     protected String elUri[];
107     //protected String elValue[];
108     protected int elNamespaceCount[];
109 
110     // input buffer management
111     protected static final int READ_CHUNK_SIZE = 8*1024; //max data chars in one read() call
112     protected Reader reader;
113     protected String inputEncoding;
114 
115 
116     protected int bufLoadFactor = 95;  // 99%
117     //protected int bufHardLimit;  // only matters when expanding
118 
119     protected char buf[] = new char[READ_CHUNK_SIZE];
120     protected int bufSoftLimit = ( bufLoadFactor * buf.length ) /100; 
121     protected boolean preventBufferCompaction;
122 
123     protected int bufAbsoluteStart; // this is buf
124     protected int bufStart;
125     protected int bufEnd;
126     protected int pos;
127     protected int posStart;
128     protected int posEnd;
129 
130     protected char pc[] = new char[READ_CHUNK_SIZE];
131     protected int pcStart;
132     protected int pcEnd;
133 
134     protected void resetStringCache() {
135         //System.out.println("resetStringCache() minimum called");
136     }
137 
138     protected String newString(char[] cbuf, int off, int len) {
139         return new String(cbuf, off, len);
140     }
141 
142     protected String newStringIntern(char[] cbuf, int off, int len) {
143         return (new String(cbuf, off, len)).intern();
144     }
145 
146     private static final boolean TRACE_SIZING = false;
147 
148  
149     /**
150      * Make sure that we have enough space to keep element stack if passed size.
151      * It will always create one additional slot then current depth
152      */
153     protected void ensureElementsCapacity() {
154         final int elStackSize = elName != null ? elName.length : 0;
155         if( (depth + 1) >= elStackSize) {
156             // we add at least one extra slot ...
157             final int newSize = (depth >= 7 ? 2 * depth : 8) + 2; // = lucky 7 + 1 //25
158             if(TRACE_SIZING) {
159                 System.err.println("TRACE_SIZING elStackSize "+elStackSize+" ==> "+newSize);
160             }
161             final boolean needsCopying = elStackSize > 0;
162             String[] arr = null;
163             // resue arr local variable slot
164             arr = new String[newSize];
165             if(needsCopying) System.arraycopy(elName, 0, arr, 0, elStackSize);
166             elName = arr;
167             arr = new String[newSize];
168             if(needsCopying) System.arraycopy(elPrefix, 0, arr, 0, elStackSize);
169             elPrefix = arr;
170             arr = new String[newSize];
171             if(needsCopying) System.arraycopy(elUri, 0, arr, 0, elStackSize);
172             elUri = arr;
173 
174             int[] iarr = new int[newSize];
175             if(needsCopying) {
176                 System.arraycopy(elNamespaceCount, 0, iarr, 0, elStackSize);
177             } else {
178                 // special initialization
179                 iarr[0] = 0;
180             }
181             elNamespaceCount = iarr;
182 
183             //TODO: avoid using element raw name ...
184             iarr = new int[newSize];
185             if(needsCopying) {
186                 System.arraycopy(elRawNameEnd, 0, iarr, 0, elStackSize);
187             }
188             elRawNameEnd = iarr;
189 
190             iarr = new int[newSize];
191             if(needsCopying) {
192                 System.arraycopy(elRawNameLine, 0, iarr, 0, elStackSize);
193             }
194             elRawNameLine = iarr;
195 
196             final char[][] carr = new char[newSize][];
197             if(needsCopying) {
198                 System.arraycopy(elRawName, 0, carr, 0, elStackSize);
199             }
200             elRawName = carr;
201             //            arr = new String[newSize];
202             //            if(needsCopying) System.arraycopy(elLocalName, 0, arr, 0, elStackSize);
203             //            elLocalName = arr;
204             //            arr = new String[newSize];
205             //            if(needsCopying) System.arraycopy(elDefaultNs, 0, arr, 0, elStackSize);
206             //            elDefaultNs = arr;
207             //            int[] iarr = new int[newSize];
208             //            if(needsCopying) System.arraycopy(elNsStackPos, 0, iarr, 0, elStackSize);
209             //            for (int i = elStackSize; i < iarr.length; i++)
210             //            {
211             //                iarr[i] = (i > 0) ? -1 : 0;
212             //            }
213             //            elNsStackPos = iarr;
214             //assert depth < elName.length;
215         }
216     }
217 
218 
219 
220     // attribute stack
221     protected int attributeCount;
222     protected String attributeName[];
223     protected int attributeNameHash[];
224     //protected int attributeNameStart[];
225     //protected int attributeNameEnd[];
226     protected String attributePrefix[];
227     protected String attributeUri[];
228     protected String attributeValue[];
229     //protected int attributeValueStart[];
230     //protected int attributeValueEnd[];
231 
232 
233     /**
234      * Make sure that in attributes temporary array is enough space.
235      */
236     protected  void ensureAttributesCapacity(int size) {
237         final int attrPosSize = attributeName != null ? attributeName.length : 0;
238         if(size >= attrPosSize) {
239             final int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25
240             if(TRACE_SIZING) {
241                 System.err.println("TRACE_SIZING attrPosSize "+attrPosSize+" ==> "+newSize);
242             }
243             final boolean needsCopying = attrPosSize > 0;
244             String[] arr = null;
245 
246             arr = new String[newSize];
247             if(needsCopying) System.arraycopy(attributeName, 0, arr, 0, attrPosSize);
248             attributeName = arr;
249 
250             arr = new String[newSize];
251             if(needsCopying) System.arraycopy(attributePrefix, 0, arr, 0, attrPosSize);
252             attributePrefix = arr;
253 
254             arr = new String[newSize];
255             if(needsCopying) System.arraycopy(attributeUri, 0, arr, 0, attrPosSize);
256             attributeUri = arr;
257 
258             arr = new String[newSize];
259             if(needsCopying) System.arraycopy(attributeValue, 0, arr, 0, attrPosSize);
260             attributeValue = arr;
261 
262             if( ! allStringsInterned ) {
263                 final int[] iarr = new int[newSize];
264                 if(needsCopying) System.arraycopy(attributeNameHash, 0, iarr, 0, attrPosSize);
265                 attributeNameHash = iarr;
266             }
267 
268             arr = null;
269             // //assert attrUri.length > size
270         }
271     }
272 
273     // namespace stack
274     protected int namespaceEnd;
275     protected String namespacePrefix[];
276     protected int namespacePrefixHash[];
277     protected String namespaceUri[];
278 
279     protected void ensureNamespacesCapacity(int size) {
280         final int namespaceSize = namespacePrefix != null ? namespacePrefix.length : 0;
281         if(size >= namespaceSize) {
282             final int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25
283             if(TRACE_SIZING) {
284                 System.err.println("TRACE_SIZING namespaceSize "+namespaceSize+" ==> "+newSize);
285             }
286             final String[] newNamespacePrefix = new String[newSize];
287             final String[] newNamespaceUri = new String[newSize];
288             if(namespacePrefix != null) {
289                 System.arraycopy(
290                     namespacePrefix, 0, newNamespacePrefix, 0, namespaceEnd);
291                 System.arraycopy(
292                     namespaceUri, 0, newNamespaceUri, 0, namespaceEnd);
293             }
294             namespacePrefix = newNamespacePrefix;
295             namespaceUri = newNamespaceUri;
296 
297 
298             if( ! allStringsInterned ) {
299                 final int[] newNamespacePrefixHash = new int[newSize];
300                 if(namespacePrefixHash != null) {
301                     System.arraycopy(
302                         namespacePrefixHash, 0, newNamespacePrefixHash, 0, namespaceEnd);
303                 }
304                 namespacePrefixHash = newNamespacePrefixHash;
305             }
306             //prefixesSize = newSize;
307             // //assert nsPrefixes.length > size && nsPrefixes.length == newSize
308         }
309     }
310 
311     /**
312      * simplistic implementation of hash function that has <b>constant</b>
313      * time to compute - so it also means diminishing hash quality for long strings
314      * but for XML parsing it should be good enough ...
315      */
316     protected static final int fastHash( char ch[], int off, int len ) {
317         if(len == 0) return 0;
318         //assert len >0
319         int hash = ch[off]; // hash at beginning
320         //try {
321         hash = (hash << 7) + ch[ off +  len - 1 ]; // hash at the end
322         //} catch(ArrayIndexOutOfBoundsException aie) {
323         //    aie.printStackTrace(); //should never happen ...
324         //    throw new RuntimeException("this is violation of pre-condition");
325         //}
326         if(len > 16) hash = (hash << 7) + ch[ off + (len / 4)];  // 1/4 from beginning
327         if(len > 8)  hash = (hash << 7) + ch[ off + (len / 2)];  // 1/2 of string size ...
328         // notice that hash is at most done 3 times <<7 so shifted by 21 bits 8 bit value
329         // so max result == 29 bits so it is quite just below 31 bits for long (2^32) ...
330         //assert hash >= 0;
331         return  hash;
332     }
333 
334     // entity replacement stack
335     protected int entityEnd;
336 
337     protected String entityName[];
338     protected char[] entityNameBuf[];
339     protected String entityReplacement[];
340     protected char[] entityReplacementBuf[];
341 
342     protected int entityNameHash[];
343 
344     protected void ensureEntityCapacity() {
345         final int entitySize = entityReplacementBuf != null ? entityReplacementBuf.length : 0;
346         if(entityEnd >= entitySize) {
347             final int newSize = entityEnd > 7 ? 2 * entityEnd : 8; // = lucky 7 + 1 //25
348             if(TRACE_SIZING) {
349                 System.err.println("TRACE_SIZING entitySize "+entitySize+" ==> "+newSize);
350             }
351             final String[] newEntityName = new String[newSize];
352             final char[] newEntityNameBuf[] = new char[newSize][];
353             final String[] newEntityReplacement = new String[newSize];
354             final char[] newEntityReplacementBuf[] = new char[newSize][];
355             if(entityName != null) {
356                 System.arraycopy(entityName, 0, newEntityName, 0, entityEnd);
357                 System.arraycopy(entityNameBuf, 0, newEntityNameBuf, 0, entityEnd);
358                 System.arraycopy(entityReplacement, 0, newEntityReplacement, 0, entityEnd);
359                 System.arraycopy(entityReplacementBuf, 0, newEntityReplacementBuf, 0, entityEnd);
360             }
361             entityName = newEntityName;
362             entityNameBuf = newEntityNameBuf;
363             entityReplacement = newEntityReplacement;
364             entityReplacementBuf = newEntityReplacementBuf;
365 
366             if( ! allStringsInterned ) {
367                 final int[] newEntityNameHash = new int[newSize];
368                 if(entityNameHash != null) {
369                     System.arraycopy(entityNameHash, 0, newEntityNameHash, 0, entityEnd);
370                 }
371                 entityNameHash = newEntityNameHash;
372             }
373         }
374     }
375         
376     protected void reset() 
377     {
378         location = null;
379         lineNumber = 1;
380         columnNumber = 0;
381         seenRoot = false;
382         reachedEnd = false;
383         eventType = START_DOCUMENT;
384         emptyElementTag = false;
385 
386         depth = 0;
387 
388         attributeCount = 0;
389 
390         namespaceEnd = 0;
391 
392         entityEnd = 0;
393 
394         reader = null;
395         inputEncoding = null;
396 
397         preventBufferCompaction = false;
398         bufAbsoluteStart = 0;
399         bufEnd = bufStart = 0;
400         pos = posStart = posEnd = 0;
401 
402         pcEnd = pcStart = 0;
403 
404         usePC = false;
405 
406         seenStartTag = false;
407         seenEndTag = false;
408         pastEndTag = false;
409         seenAmpersand = false;
410         seenMarkup = false;
411         seenDocdecl = false;
412 
413         xmlDeclVersion = null;
414         xmlDeclStandalone = null;
415         xmlDeclContent = null;
416 
417         resetStringCache();
418     }
419 
420     public MXParser() {
421     }
422 
423 
424     /**
425      * Method setFeature
426      *
427      * @param    name                a  String
428      * @param    state               a  boolean
429      *
430      * @throws   XmlPullParserException
431      *
432      */
433     public void setFeature(String name,
434                            boolean state) throws XmlPullParserException
435     {
436         if(name == null) throw new IllegalArgumentException("feature name should not be null");
437         if(FEATURE_PROCESS_NAMESPACES.equals(name)) {
438             if(eventType != START_DOCUMENT) throw new XmlPullParserException(
439                     "namespace processing feature can only be changed before parsing", this, null);
440             processNamespaces = state;
441             //        } else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
442             //      if(type != START_DOCUMENT) throw new XmlPullParserException(
443             //              "namespace reporting feature can only be changed before parsing", this, null);
444             //            reportNsAttribs = state;
445         } else if(FEATURE_NAMES_INTERNED.equals(name)) {
446             if(state != false) {
447                 throw new XmlPullParserException(
448                     "interning names in this implementation is not supported");
449             }
450         } else if(FEATURE_PROCESS_DOCDECL.equals(name)) {
451             if(state != false) {
452                 throw new XmlPullParserException(
453                     "processing DOCDECL is not supported");
454             }
455             //} else if(REPORT_DOCDECL.equals(name)) {
456             //    paramNotifyDoctype = state;
457         } else if(FEATURE_XML_ROUNDTRIP.equals(name)) {
458             //if(state == false) {
459             //    throw new XmlPullParserException(
460             //        "roundtrip feature can not be switched off");
461             //}
462             roundtripSupported = state;
463         } else if (FEATURE_VALIDATION.equals( name ) && !state) {
464             // noop, is already the default. JDom wants to set it anyway
465         } else {
466             throw new XmlPullParserException("unsupporte feature "+name);
467         }
468     }
469 
470     /** Unknown properties are <string>always</strong> returned as false */
471     public boolean getFeature(String name)
472     {
473         if(name == null) throw new IllegalArgumentException("feature name should not be nulll");
474         if(FEATURE_PROCESS_NAMESPACES.equals(name)) {
475             return processNamespaces;
476             //        } else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
477             //            return reportNsAttribs;
478         } else if(FEATURE_NAMES_INTERNED.equals(name)) {
479             return false;
480         } else if(FEATURE_PROCESS_DOCDECL.equals(name)) {
481             return false;
482             //} else if(REPORT_DOCDECL.equals(name)) {
483             //    return paramNotifyDoctype;
484         } else if(FEATURE_XML_ROUNDTRIP.equals(name)) {
485             //return true;
486             return roundtripSupported;
487         }
488         else if( REPORT_NAMESPACE_PREFIXES.equals(  name ) ) {
489             return processNamespaces;
490         }
491                 
492         return false;
493     }
494 
495     public void setProperty(String name,
496                             Object value)
497         throws XmlPullParserException
498     {
499         if(PROPERTY_LOCATION.equals(name)) {
500             location = (String) value;
501         } else {
502             throw new XmlPullParserException("unsupported property: '"+name+"'");
503         }
504     }
505 
506 
507     public Object getProperty(String name)
508     {
509         if(name == null) throw new IllegalArgumentException("property name should not be nulll");
510         if(PROPERTY_XMLDECL_VERSION.equals(name)) {
511             return xmlDeclVersion;
512         } else if(PROPERTY_XMLDECL_STANDALONE.equals(name)) {
513             return xmlDeclStandalone;
514         } else if(PROPERTY_XMLDECL_CONTENT.equals(name)) {
515             return xmlDeclContent;
516         } else if(PROPERTY_LOCATION.equals(name)) {
517             return location;
518         }
519         return null;
520     }
521 
522 
523     public void setInput(Reader in) throws XmlPullParserException
524     {
525         reset();
526         reader = in;
527     }
528 
529 
530     public void setInput(java.io.InputStream inputStream, String inputEncoding)
531         throws XmlPullParserException
532     {
533         if(inputStream == null) {
534             throw new IllegalArgumentException("input stream can not be null");
535         }
536         Reader reader;
537         try {
538             if(inputEncoding != null) {
539                 reader = ReaderFactory.newReader(inputStream, inputEncoding);
540             } else {
541                 reader = ReaderFactory.newXmlReader(inputStream);
542             }
543         } catch (UnsupportedEncodingException une) {
544             throw new XmlPullParserException(
545                 "could not create reader for encoding "+inputEncoding+" : "+une, this, une);
546         }
547         catch ( IOException e )
548         {
549             throw new XmlPullParserException(
550                 "could not create reader : "+e, this, e);
551         }
552         setInput(reader);
553         //must be  here as reset() was called in setInput() and has set this.inputEncoding to null ...
554         this.inputEncoding = inputEncoding;
555     }
556 
557     public String getInputEncoding() {
558         return inputEncoding;
559     }
560 
561     public void defineEntityReplacementText(String entityName,
562                                             String replacementText)
563         throws XmlPullParserException
564     {
565         //      throw new XmlPullParserException("not allowed");
566 
567         //protected char[] entityReplacement[];
568         ensureEntityCapacity();
569 
570         // this is to make sure that if interning works we will take advantage of it ...
571         this.entityName[entityEnd] = newString(entityName.toCharArray(), 0, entityName.length());
572         entityNameBuf[entityEnd] = entityName.toCharArray();
573 
574         entityReplacement[entityEnd] = replacementText;
575         entityReplacementBuf[entityEnd] = replacementText.toCharArray();
576         if(!allStringsInterned) {
577             entityNameHash[ entityEnd ] =
578                 fastHash(entityNameBuf[entityEnd], 0, entityNameBuf[entityEnd].length);
579         }
580         ++entityEnd;
581         //TODO disallow < or & in entity replacement text (or ]]>???)
582         // TOOD keepEntityNormalizedForAttributeValue cached as well ...
583     }
584 
585     public int getNamespaceCount(int depth)
586         throws XmlPullParserException
587     {
588         if(processNamespaces == false || depth == 0) {
589             return 0;
590         }
591         //int maxDepth = eventType == END_TAG ? this.depth + 1 : this.depth;
592         //if(depth < 0 || depth > maxDepth) throw new IllegalArgumentException(
593         if(depth < 0 || depth > this.depth) throw new IllegalArgumentException(
594                 "napespace count mayt be for depth 0.."+this.depth+" not "+depth);
595         return elNamespaceCount[ depth ];
596     }
597 
598     public String getNamespacePrefix(int pos)
599         throws XmlPullParserException
600     {
601 
602         //int end = eventType == END_TAG ? elNamespaceCount[ depth + 1 ] : namespaceEnd;
603         //if(pos < end) {
604         if(pos < namespaceEnd) {
605             return namespacePrefix[ pos ];
606         } else {
607             throw new XmlPullParserException(
608                 "position "+pos+" exceeded number of available namespaces "+namespaceEnd);
609         }
610     }
611 
612     public String getNamespaceUri(int pos) throws XmlPullParserException
613     {
614         //int end = eventType == END_TAG ? elNamespaceCount[ depth + 1 ] : namespaceEnd;
615         //if(pos < end) {
616         if(pos < namespaceEnd) {
617             return namespaceUri[ pos ];
618         } else {
619             throw new XmlPullParserException(
620                 "position "+pos+" exceedded number of available namespaces "+namespaceEnd);
621         }
622     }
623 
624     public String getNamespace( String prefix )
625         //throws XmlPullParserException
626     {
627         //int count = namespaceCount[ depth ];
628         if(prefix != null) {
629             for( int i = namespaceEnd -1; i >= 0; i--) {
630                 if( prefix.equals( namespacePrefix[ i ] ) ) {
631                     return namespaceUri[ i ];
632                 }
633             }
634             if("xml".equals( prefix )) {
635                 return XML_URI;
636             } else if("xmlns".equals( prefix )) {
637                 return XMLNS_URI;
638             }
639         } else {
640             for( int i = namespaceEnd -1; i >= 0; i--) {
641                 if( namespacePrefix[ i ]  == null) { //"") { //null ) { //TODO check FIXME Alek
642                     return namespaceUri[ i ];
643                 }
644             }
645 
646         }
647         return null;
648     }
649 
650 
651     public int getDepth()
652     {
653         return depth;
654     }
655 
656 
657     private static int findFragment(int bufMinPos, char[] b, int start, int end) {
658         //System.err.println("bufStart="+bufStart+" b="+printable(new String(b, start, end - start))+" start="+start+" end="+end);
659         if(start < bufMinPos) {
660             start = bufMinPos;
661             if(start > end) start = end;
662             return start;
663         }
664         if(end - start > 65) {
665             start = end - 10; // try to find good location
666         }
667         int i = start + 1;
668         while(--i > bufMinPos) {
669             if((end - i) > 65) break;
670             final char c = b[i];
671             if(c == '<' && (start - i) > 10) break;
672         }
673         return i;
674     }
675 
676 
677     /**
678      * Return string describing current position of parsers as
679      * text 'STATE [seen %s...] @line:column'.
680      */
681     public String getPositionDescription ()
682     {
683         String fragment = null;
684         if(posStart <= pos) {
685             final int start = findFragment(0, buf, posStart, pos);
686             //System.err.println("start="+start);
687             if(start < pos) {
688                 fragment = new String(buf, start, pos - start);
689             }
690             if(bufAbsoluteStart > 0 || start > 0) fragment = "..." + fragment;
691         }
692         //        return " at line "+tokenizerPosRow
693         //            +" and column "+(tokenizerPosCol-1)
694         //            +(fragment != null ? " seen "+printable(fragment)+"..." : "");
695         return " "+TYPES[ eventType ] +
696             (fragment != null ? " seen "+printable(fragment)+"..." : "")
697             +" "+(location != null ? location : "")
698             +"@"+getLineNumber()+":"+getColumnNumber();
699     }
700 
701     public int getLineNumber()
702     {
703         return lineNumber;
704     }
705 
706     public int getColumnNumber()
707     {
708         return columnNumber;
709     }
710 
711 
712     public boolean isWhitespace() throws XmlPullParserException
713     {
714         if(eventType == TEXT || eventType == CDSECT) {
715             if(usePC) {
716                 for (int i = pcStart; i <pcEnd; i++)
717                 {
718                     if(!isS(pc[ i ])) return false;
719                 }
720                 return true;
721             } else {
722                 for (int i = posStart; i <posEnd; i++)
723                 {
724                     if(!isS(buf[ i ])) return false;
725                 }
726                 return true;
727             }
728         } else if(eventType == IGNORABLE_WHITESPACE) {
729             return true;
730         }
731         throw new XmlPullParserException("no content available to check for whitespaces");
732     }
733 
734     public String getText()
735     {
736         if(eventType == START_DOCUMENT || eventType == END_DOCUMENT) {
737             //throw new XmlPullParserException("no content available to read");
738             //      if(roundtripSupported) {
739             //          text = new String(buf, posStart, posEnd - posStart);
740             //      } else {
741             return null;
742             //      }
743         } else if(eventType == ENTITY_REF) {
744             return text;
745         }
746         if(text == null) {
747             if(!usePC || eventType == START_TAG || eventType == END_TAG) {
748                 text = new String(buf, posStart, posEnd - posStart);
749             } else {
750                 text = new String(pc, pcStart, pcEnd - pcStart);
751             }
752         }
753         return text;
754     }
755 
756     public char[] getTextCharacters(int [] holderForStartAndLength)
757     {
758         if( eventType == TEXT ) {
759             if(usePC) {
760                 holderForStartAndLength[0] = pcStart;
761                 holderForStartAndLength[1] = pcEnd - pcStart;
762                 return pc;
763             } else {
764                 holderForStartAndLength[0] = posStart;
765                 holderForStartAndLength[1] = posEnd - posStart;
766                 return buf;
767 
768             }
769         } else if( eventType == START_TAG
770                       || eventType == END_TAG
771                       || eventType == CDSECT
772                       || eventType == COMMENT
773                       || eventType == ENTITY_REF
774                       || eventType == PROCESSING_INSTRUCTION
775                       || eventType == IGNORABLE_WHITESPACE
776                       || eventType == DOCDECL)
777         {
778             holderForStartAndLength[0] = posStart;
779             holderForStartAndLength[1] = posEnd - posStart;
780             return buf;
781         } else if(eventType == START_DOCUMENT
782                       || eventType == END_DOCUMENT) {
783             //throw new XmlPullParserException("no content available to read");
784             holderForStartAndLength[0] = holderForStartAndLength[1] = -1;
785             return null;
786         } else {
787             throw new IllegalArgumentException("unknown text eventType: "+eventType);
788         }
789         //      String s = getText();
790         //      char[] cb = null;
791         //      if(s!= null) {
792         //          cb = s.toCharArray();
793         //          holderForStartAndLength[0] = 0;
794         //          holderForStartAndLength[1] = s.length();
795         //      } else {
796         //      }
797         //      return cb;
798     }
799 
800     public String getNamespace()
801     {
802         if(eventType == START_TAG) {
803             //return processNamespaces ? elUri[ depth - 1 ] : NO_NAMESPACE;
804             return processNamespaces ? elUri[ depth  ] : NO_NAMESPACE;
805         } else if(eventType == END_TAG) {
806             return processNamespaces ? elUri[ depth ] : NO_NAMESPACE;
807         }
808         return null;
809         //        String prefix = elPrefix[ maxDepth ];
810         //        if(prefix != null) {
811         //            for( int i = namespaceEnd -1; i >= 0; i--) {
812         //                if( prefix.equals( namespacePrefix[ i ] ) ) {
813         //                    return namespaceUri[ i ];
814         //                }
815         //            }
816         //        } else {
817         //            for( int i = namespaceEnd -1; i >= 0; i--) {
818         //                if( namespacePrefix[ i ]  == null ) {
819         //                    return namespaceUri[ i ];
820         //                }
821         //            }
822         //
823         //        }
824         //        return "";
825     }
826 
827     public String getName()
828     {
829         if(eventType == START_TAG) {
830             //return elName[ depth - 1 ] ;
831             return elName[ depth ] ;
832         } else if(eventType == END_TAG) {
833             return elName[ depth ] ;
834         } else if(eventType == ENTITY_REF) {
835             if(entityRefName == null) {
836                 entityRefName = newString(buf, posStart, posEnd - posStart);
837             }
838             return entityRefName;
839         } else {
840             return null;
841         }
842     }
843 
844     public String getPrefix()
845     {
846         if(eventType == START_TAG) {
847             //return elPrefix[ depth - 1 ] ;
848             return elPrefix[ depth ] ;
849         } else if(eventType == END_TAG) {
850             return elPrefix[ depth ] ;
851         }
852         return null;
853         //        if(eventType != START_TAG && eventType != END_TAG) return null;
854         //        int maxDepth = eventType == END_TAG ? depth : depth - 1;
855         //        return elPrefix[ maxDepth ];
856     }
857 
858 
859     public boolean isEmptyElementTag() throws XmlPullParserException
860     {
861         if(eventType != START_TAG) throw new XmlPullParserException(
862                 "parser must be on START_TAG to check for empty element", this, null);
863         return emptyElementTag;
864     }
865 
866     public int getAttributeCount()
867     {
868         if(eventType != START_TAG) return -1;
869         return attributeCount;
870     }
871 
872     public String getAttributeNamespace(int index)
873     {
874         if(eventType != START_TAG) throw new IndexOutOfBoundsException(
875                 "only START_TAG can have attributes");
876         if(processNamespaces == false) return NO_NAMESPACE;
877         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
878                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
879         return attributeUri[ index ];
880     }
881 
882     public String getAttributeName(int index)
883     {
884         if(eventType != START_TAG) throw new IndexOutOfBoundsException(
885                 "only START_TAG can have attributes");
886         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
887                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
888         return attributeName[ index ];
889     }
890 
891     public String getAttributePrefix(int index)
892     {
893         if(eventType != START_TAG) throw new IndexOutOfBoundsException(
894                 "only START_TAG can have attributes");
895         if(processNamespaces == false) return null;
896         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
897                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
898         return attributePrefix[ index ];
899     }
900 
901     public String getAttributeType(int index) {
902         if(eventType != START_TAG) throw new IndexOutOfBoundsException(
903                 "only START_TAG can have attributes");
904         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
905                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
906         return "CDATA";
907     }
908 
909     public boolean isAttributeDefault(int index) {
910         if(eventType != START_TAG) throw new IndexOutOfBoundsException(
911                 "only START_TAG can have attributes");
912         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
913                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
914         return false;
915     }
916 
917     public String getAttributeValue(int index)
918     {
919         if(eventType != START_TAG) throw new IndexOutOfBoundsException(
920                 "only START_TAG can have attributes");
921         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException(
922                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
923         return attributeValue[ index ];
924     }
925 
926     public String getAttributeValue(String namespace,
927                                     String name)
928     {
929         if(eventType != START_TAG) throw new IndexOutOfBoundsException(
930                 "only START_TAG can have attributes"+getPositionDescription());
931         if(name == null) {
932             throw new IllegalArgumentException("attribute name can not be null");
933         }
934         // TODO make check if namespace is interned!!! etc. for names!!!
935         if(processNamespaces) {
936             if(namespace == null) {
937                 namespace = "";
938             }
939 
940             for(int i = 0; i < attributeCount; ++i) {
941                 if((namespace == attributeUri[ i ] ||
942                         namespace.equals(attributeUri[ i ]) )
943                        //(namespace != null && namespace.equals(attributeUri[ i ]))
944                        // taking advantage of String.intern()
945                        && name.equals(attributeName[ i ]) )
946                 {
947                     return attributeValue[i];
948                 }
949             }
950         } else {
951             if(namespace != null && namespace.length() == 0) {
952                 namespace = null;
953             }
954             if(namespace != null) throw new IllegalArgumentException(
955                     "when namespaces processing is disabled attribute namespace must be null");
956             for(int i = 0; i < attributeCount; ++i) {
957                 if(name.equals(attributeName[i]))
958                 {
959                     return attributeValue[i];
960                 }
961             }
962         }
963         return null;
964     }
965 
966 
967     public int getEventType()
968         throws XmlPullParserException
969     {
970         return eventType;
971     }
972 
973     public void require(int type, String namespace, String name)
974         throws XmlPullParserException, IOException
975     {
976         if(processNamespaces == false && namespace != null) {
977             throw new XmlPullParserException(
978                 "processing namespaces must be enabled on parser (or factory)"+
979                     " to have possible namespaces delcared on elements"
980                     +(" (postion:"+ getPositionDescription())+")");
981         }
982         if (type != getEventType()
983                 || (namespace != null && !namespace.equals (getNamespace()))
984                 || (name != null && !name.equals (getName ())) )
985         {
986             throw new XmlPullParserException (
987                 "expected event "+TYPES[ type ]
988                     +(name != null ? " with name '"+name+"'" : "")
989                     +(namespace != null && name != null ? " and" : "")
990                     +(namespace != null ? " with namespace '"+namespace+"'" : "")
991                     +" but got"
992                     +(type != getEventType() ? " "+TYPES[ getEventType() ] : "")
993                     +(name != null && getName() != null && !name.equals (getName ())
994                           ? " name '"+getName()+"'" : "")
995                     +(namespace != null && name != null
996                           && getName() != null && !name.equals (getName ())
997                           && getNamespace() != null && !namespace.equals (getNamespace())
998                           ? " and" : "")
999                     +(namespace != null && getNamespace() != null && !namespace.equals (getNamespace())
1000                           ? " namespace '"+getNamespace()+"'" : "")
1001                     +(" (postion:"+ getPositionDescription())+")");
1002         }
1003     }
1004 
1005 
1006     /**
1007      * Skip sub tree that is currently porser positioned on.
1008      * <br>NOTE: parser must be on START_TAG and when funtion returns
1009      * parser will be positioned on corresponding END_TAG
1010      */
1011     public void skipSubTree()
1012         throws XmlPullParserException, IOException
1013     {
1014         require(START_TAG, null, null);
1015         int level = 1;
1016         while(level > 0) {
1017             int eventType = next();
1018             if(eventType == END_TAG) {
1019                 --level;
1020             } else if(eventType == START_TAG) {
1021                 ++level;
1022             }
1023         }
1024     }
1025 
1026     //    public String readText() throws XmlPullParserException, IOException
1027     //    {
1028     //        if (getEventType() != TEXT) return "";
1029     //        String result = getText();
1030     //        next();
1031     //        return result;
1032     //    }
1033 
1034     public String nextText() throws XmlPullParserException, IOException
1035     {
1036         //        String result = null;
1037         //        boolean onStartTag = false;
1038         //        if(eventType == START_TAG) {
1039         //            onStartTag = true;
1040         //            next();
1041         //        }
1042         //        if(eventType == TEXT) {
1043         //            result = getText();
1044         //            next();
1045         //        } else if(onStartTag && eventType == END_TAG) {
1046         //            result = "";
1047         //        } else {
1048         //            throw new XmlPullParserException(
1049         //                "parser must be on START_TAG or TEXT to read text", this, null);
1050         //        }
1051         //        if(eventType != END_TAG) {
1052         //            throw new XmlPullParserException(
1053         //                "event TEXT it must be immediately followed by END_TAG", this, null);
1054         //        }
1055         //        return result;
1056         if(getEventType() != START_TAG) {
1057             throw new XmlPullParserException(
1058                 "parser must be on START_TAG to read next text", this, null);
1059         }
1060         int eventType = next();
1061         if(eventType == TEXT) {
1062             final String result = getText();
1063             eventType = next();
1064             if(eventType != END_TAG) {
1065                 throw new XmlPullParserException(
1066                     "TEXT must be immediately followed by END_TAG and not "
1067                         +TYPES[ getEventType() ], this, null);
1068             }
1069             return result;
1070         } else if(eventType == END_TAG) {
1071             return "";
1072         } else {
1073             throw new XmlPullParserException(
1074                 "parser must be on START_TAG or TEXT to read text", this, null);
1075         }
1076     }
1077 
1078     public int nextTag() throws XmlPullParserException, IOException
1079     {
1080         next();
1081         if(eventType == TEXT && isWhitespace()) {  // skip whitespace
1082             next();
1083         }
1084         if (eventType != START_TAG && eventType != END_TAG) {
1085             throw new XmlPullParserException("expected START_TAG or END_TAG not "
1086                                                  +TYPES[ getEventType() ], this, null);
1087         }
1088         return eventType;
1089     }
1090 
1091     public int next()
1092         throws XmlPullParserException, IOException
1093     {
1094         tokenize = false;
1095         return nextImpl();
1096     }
1097 
1098     public int nextToken()
1099         throws XmlPullParserException, IOException
1100     {
1101         tokenize = true;
1102         return nextImpl();
1103     }
1104 
1105 
1106     protected int nextImpl()
1107         throws XmlPullParserException, IOException
1108     {
1109         text = null;
1110         pcEnd = pcStart = 0;
1111         usePC = false;
1112         bufStart = posEnd;
1113         if(pastEndTag) {
1114             pastEndTag = false;
1115             --depth;
1116             namespaceEnd = elNamespaceCount[ depth ]; // less namespaces available
1117         }
1118         if(emptyElementTag) {
1119             emptyElementTag = false;
1120             pastEndTag = true;
1121             return eventType = END_TAG;
1122         }
1123 
1124         // [1] document ::= prolog element Misc*
1125         if(depth > 0) {
1126 
1127             if(seenStartTag) {
1128                 seenStartTag = false;
1129                 return eventType = parseStartTag();
1130             }
1131             if(seenEndTag) {
1132                 seenEndTag = false;
1133                 return eventType = parseEndTag();
1134             }
1135 
1136             // ASSUMPTION: we are _on_ first character of content or markup!!!!
1137             // [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)*
1138             char ch;
1139             if(seenMarkup) {  // we have read ahead ...
1140                 seenMarkup = false;
1141                 ch = '<';
1142             } else if(seenAmpersand) {
1143                 seenAmpersand = false;
1144                 ch = '&';
1145             } else {
1146                 ch = more();
1147             }
1148             posStart = pos - 1; // VERY IMPORTANT: this is correct start of event!!!
1149 
1150             // when true there is some potential event TEXT to return - keep gathering
1151             boolean hadCharData = false;
1152 
1153             // when true TEXT data is not continuous (like <![CDATA[text]]>) and requires PC merging
1154             boolean needsMerging = false;
1155 
1156             MAIN_LOOP:
1157             while(true) {
1158                 // work on MARKUP
1159                 if(ch == '<') {
1160                     if(hadCharData) {
1161                         //posEnd = pos - 1;
1162                         if(tokenize) {
1163                             seenMarkup = true;
1164                             return eventType = TEXT;
1165                         }
1166                     }
1167                     ch = more();
1168                     if(ch == '/') {
1169                         if(!tokenize && hadCharData) {
1170                             seenEndTag = true;
1171                             //posEnd = pos - 2;
1172                             return eventType = TEXT;
1173                         }
1174                         return eventType = parseEndTag();
1175                     } else if(ch == '!') {
1176                         ch = more();
1177                         if(ch == '-') {
1178                             // note: if(tokenize == false) posStart/End is NOT changed!!!!
1179                             parseComment();
1180                             if(tokenize) return eventType = COMMENT;
1181                             if( !usePC && hadCharData ) {
1182                                 needsMerging = true;
1183                             } else {
1184                                 posStart = pos;  //completely ignore comment
1185                             }
1186                         } else if(ch == '[') {
1187                             //posEnd = pos - 3;
1188                             // must remember previous posStart/End as it merges with content of CDATA
1189                             //int oldStart = posStart + bufAbsoluteStart;
1190                             //int oldEnd = posEnd + bufAbsoluteStart;
1191                             parseCDSect(hadCharData);
1192                             if(tokenize) return eventType = CDSECT;
1193                             final int cdStart = posStart;
1194                             final int cdEnd = posEnd;
1195                             final int cdLen = cdEnd - cdStart;
1196 
1197 
1198                             if(cdLen > 0) { // was there anything inside CDATA section?
1199                                 hadCharData = true;
1200                                 if(!usePC) {
1201                                     needsMerging = true;
1202                                 }
1203                             }
1204 
1205                             //                          posStart = oldStart;
1206                             //                          posEnd = oldEnd;
1207                             //                          if(cdLen > 0) { // was there anything inside CDATA section?
1208                             //                              if(hadCharData) {
1209                             //                                  // do merging if there was anything in CDSect!!!!
1210                             //                                  //                                    if(!usePC) {
1211                             //                                  //                                        // posEnd is correct already!!!
1212                             //                                  //                                        if(posEnd > posStart) {
1213                             //                                  //                                            joinPC();
1214                             //                                  //                                        } else {
1215                             //                                  //                                            usePC = true;
1216                             //                                  //                                            pcStart = pcEnd = 0;
1217                             //                                  //                                        }
1218                             //                                  //                                    }
1219                             //                                  //                                    if(pcEnd + cdLen >= pc.length) ensurePC(pcEnd + cdLen);
1220                             //                                  //                                    // copy [cdStart..cdEnd) into PC
1221                             //                                  //                                    System.arraycopy(buf, cdStart, pc, pcEnd, cdLen);
1222                             //                                  //                                    pcEnd += cdLen;
1223                             //                                  if(!usePC) {
1224                             //                                      needsMerging = true;
1225                             //                                      posStart = cdStart;
1226                             //                                      posEnd = cdEnd;
1227                             //                                  }
1228                             //                              } else {
1229                             //                                  if(!usePC) {
1230                             //                                      needsMerging = true;
1231                             //                                      posStart = cdStart;
1232                             //                                      posEnd = cdEnd;
1233                             //                                      hadCharData = true;
1234                             //                                  }
1235                             //                              }
1236                             //                              //hadCharData = true;
1237                             //                          } else {
1238                             //                              if( !usePC && hadCharData ) {
1239                             //                                  needsMerging = true;
1240                             //                              }
1241                             //                          }
1242                         } else {
1243                             throw new XmlPullParserException(
1244                                 "unexpected character in markup "+printable(ch), this, null);
1245                         }
1246                     } else if(ch == '?') {
1247                         parsePI();
1248                         if(tokenize) return eventType = PROCESSING_INSTRUCTION;
1249                         if( !usePC && hadCharData ) {
1250                             needsMerging = true;
1251                         } else {
1252                             posStart = pos;  //completely ignore PI
1253                         }
1254 
1255                     } else if( isNameStartChar(ch) ) {
1256                         if(!tokenize && hadCharData) {
1257                             seenStartTag = true;
1258                             //posEnd = pos - 2;
1259                             return eventType = TEXT;
1260                         }
1261                         return eventType = parseStartTag();
1262                     } else {
1263                         throw new XmlPullParserException(
1264                             "unexpected character in markup "+printable(ch), this, null);
1265                     }
1266                     // do content comapctation if it makes sense!!!!
1267 
1268                 } else if(ch == '&') {
1269                     // work on ENTITTY
1270                     //posEnd = pos - 1;
1271                     if(tokenize && hadCharData) {
1272                         seenAmpersand = true;
1273                         return eventType = TEXT;
1274                     }
1275                     final int oldStart = posStart + bufAbsoluteStart;
1276                     final int oldEnd = posEnd + bufAbsoluteStart;
1277                     final char[] resolvedEntity = parseEntityRef();
1278                     if(tokenize) return eventType = ENTITY_REF;
1279                     // check if replacement text can be resolved !!!
1280                     if(resolvedEntity == null) {
1281                         if(entityRefName == null) {
1282                             entityRefName = newString(buf, posStart, posEnd - posStart);
1283                         }
1284                         throw new XmlPullParserException(
1285                             "could not resolve entity named '"+printable(entityRefName)+"'",
1286                             this, null);
1287                     }
1288                     //int entStart = posStart;
1289                     //int entEnd = posEnd;
1290                     posStart = oldStart - bufAbsoluteStart;
1291                     posEnd = oldEnd - bufAbsoluteStart;
1292                     if(!usePC) {
1293                         if(hadCharData) {
1294                             joinPC(); // posEnd is already set correctly!!!
1295                             needsMerging = false;
1296                         } else {
1297                             usePC = true;
1298                             pcStart = pcEnd = 0;
1299                         }
1300                     }
1301                     //assert usePC == true;
1302                     // write into PC replacement text - do merge for replacement text!!!!
1303                     for (char aResolvedEntity : resolvedEntity) {
1304                         if (pcEnd >= pc.length) ensurePC(pcEnd);
1305                         pc[pcEnd++] = aResolvedEntity;
1306 
1307                     }
1308                     hadCharData = true;
1309                     //assert needsMerging == false;
1310                 } else {
1311 
1312                     if(needsMerging) {
1313                         //assert usePC == false;
1314                         joinPC();  // posEnd is already set correctly!!!
1315                         //posStart = pos  -  1;
1316                         needsMerging = false;
1317                     }
1318 
1319 
1320                     //no MARKUP not ENTITIES so work on character data ...
1321 
1322 
1323 
1324                     // [14] CharData ::=   [^<&]* - ([^<&]* ']]>' [^<&]*)
1325 
1326 
1327                     hadCharData = true;
1328 
1329                     boolean normalizedCR = false;
1330                     final boolean normalizeInput = tokenize == false || roundtripSupported == false;
1331                     // use loop locality here!!!!
1332                     boolean seenBracket = false;
1333                     boolean seenBracketBracket = false;
1334                     do {
1335 
1336                         // check that ]]> does not show in
1337                         if(ch == ']') {
1338                             if(seenBracket) {
1339                                 seenBracketBracket = true;
1340                             } else {
1341                                 seenBracket = true;
1342                             }
1343                         } else if(seenBracketBracket && ch == '>') {
1344                             throw new XmlPullParserException(
1345                                 "characters ]]> are not allowed in content", this, null);
1346                         } else {
1347                             if(seenBracket) {
1348                                 seenBracketBracket = seenBracket = false;
1349                             }
1350                             // assert seenTwoBrackets == seenBracket == false;
1351                         }
1352                         if(normalizeInput) {
1353                             // deal with normalization issues ...
1354                             if(ch == '\r') {
1355                                 normalizedCR = true;
1356                                 posEnd = pos -1;
1357                                 // posEnd is already set
1358                                 if(!usePC) {
1359                                     if(posEnd > posStart) {
1360                                         joinPC();
1361                                     } else {
1362                                         usePC = true;
1363                                         pcStart = pcEnd = 0;
1364                                     }
1365                                 }
1366                                 //assert usePC == true;
1367                                 if(pcEnd >= pc.length) ensurePC(pcEnd);
1368                                 pc[pcEnd++] = '\n';
1369                             } else if(ch == '\n') {
1370                                 //   if(!usePC) {  joinPC(); } else { if(pcEnd >= pc.length) ensurePC(); }
1371                                 if(!normalizedCR && usePC) {
1372                                     if(pcEnd >= pc.length) ensurePC(pcEnd);
1373                                     pc[pcEnd++] = '\n';
1374                                 }
1375                                 normalizedCR = false;
1376                             } else {
1377                                 if(usePC) {
1378                                     if(pcEnd >= pc.length) ensurePC(pcEnd);
1379                                     pc[pcEnd++] = ch;
1380                                 }
1381                                 normalizedCR = false;
1382                             }
1383                         }
1384 
1385                         ch = more();
1386                     } while(ch != '<' && ch != '&');
1387                     posEnd = pos - 1;
1388                     continue MAIN_LOOP;  // skip ch = more() from below - we are already ahead ...
1389                 }
1390                 ch = more();
1391             } // endless while(true)
1392         } else {
1393             if(seenRoot) {
1394                 return parseEpilog();
1395             } else {
1396                 return parseProlog();
1397             }
1398         }
1399     }
1400 
1401 
1402     protected int parseProlog()
1403         throws XmlPullParserException, IOException
1404     {
1405         // [2] prolog: ::= XMLDecl? Misc* (doctypedecl Misc*)? and look for [39] element
1406 
1407         char ch;
1408         if(seenMarkup) {
1409             ch = buf[ pos - 1 ];
1410         } else {
1411             ch = more();
1412         }
1413 
1414         if(eventType == START_DOCUMENT) {
1415             // bootstrap parsing with getting first character input!
1416             // deal with BOM
1417             // detect BOM and crop it (Unicode int Order Mark)
1418             if(ch == '\uFFFE') {
1419                 throw new XmlPullParserException(
1420                     "first character in input was UNICODE noncharacter (0xFFFE)"+
1421                         "- input requires int swapping", this, null);
1422             }
1423             if(ch == '\uFEFF') {
1424                 // skipping UNICODE int Order Mark (so called BOM)
1425                 ch = more();
1426             }
1427         }
1428         seenMarkup = false;
1429         boolean gotS = false;
1430         posStart = pos - 1;
1431         final boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false;
1432         boolean normalizedCR = false;
1433         while(true) {
1434             // deal with Misc
1435             // [27] Misc ::= Comment | PI | S
1436             // deal with docdecl --> mark it!
1437             // else parseStartTag seen <[^/]
1438             if(ch == '<') {
1439                 if(gotS && tokenize) {
1440                     posEnd = pos - 1;
1441                     seenMarkup = true;
1442                     return eventType = IGNORABLE_WHITESPACE;
1443                 }
1444                 ch = more();
1445                 if(ch == '?') {
1446                     // check if it is 'xml'
1447                     // deal with XMLDecl
1448                     boolean isXMLDecl = parsePI();
1449                     if(tokenize) {
1450                         if (isXMLDecl) {
1451                             return eventType = START_DOCUMENT;
1452                         }
1453                         return eventType = PROCESSING_INSTRUCTION;
1454                     }
1455                 } else if(ch == '!') {
1456                     ch = more();
1457                     if(ch == 'D') {
1458                         if(seenDocdecl) {
1459                             throw new XmlPullParserException(
1460                                 "only one docdecl allowed in XML document", this, null);
1461                         }
1462                         seenDocdecl = true;
1463                         parseDocdecl();
1464                         if(tokenize) return eventType = DOCDECL;
1465                     } else if(ch == '-') {
1466                         parseComment();
1467                         if(tokenize) return eventType = COMMENT;
1468                     } else {
1469                         throw new XmlPullParserException(
1470                             "unexpected markup <!"+printable(ch), this, null);
1471                     }
1472                 } else if(ch == '/') {
1473                     throw new XmlPullParserException(
1474                         "expected start tag name and not "+printable(ch), this, null);
1475                 } else if(isNameStartChar(ch)) {
1476                     seenRoot = true;
1477                     return parseStartTag();
1478                 } else {
1479                     throw new XmlPullParserException(
1480                         "expected start tag name and not "+printable(ch), this, null);
1481                 }
1482             } else if(isS(ch)) {
1483                 gotS = true;
1484                 if(normalizeIgnorableWS) {
1485                     if(ch == '\r') {
1486                         normalizedCR = true;
1487                         //posEnd = pos -1;
1488                         //joinPC();
1489                         // posEnd is already set
1490                         if(!usePC) {
1491                             posEnd = pos -1;
1492                             if(posEnd > posStart) {
1493                                 joinPC();
1494                             } else {
1495                                 usePC = true;
1496                                 pcStart = pcEnd = 0;
1497                             }
1498                         }
1499                         //assert usePC == true;
1500                         if(pcEnd >= pc.length) ensurePC(pcEnd);
1501                         pc[pcEnd++] = '\n';
1502                     } else if(ch == '\n') {
1503                         if(!normalizedCR && usePC) {
1504                             if(pcEnd >= pc.length) ensurePC(pcEnd);
1505                             pc[pcEnd++] = '\n';
1506                         }
1507                         normalizedCR = false;
1508                     } else {
1509                         if(usePC) {
1510                             if(pcEnd >= pc.length) ensurePC(pcEnd);
1511                             pc[pcEnd++] = ch;
1512                         }
1513                         normalizedCR = false;
1514                     }
1515                 }
1516             } else {
1517                 throw new XmlPullParserException(
1518                     "only whitespace content allowed before start tag and not "+printable(ch),
1519                     this, null);
1520             }
1521             ch = more();
1522         }
1523     }
1524 
1525     protected int parseEpilog()
1526         throws XmlPullParserException, IOException
1527     {
1528         if(eventType == END_DOCUMENT) {
1529             throw new XmlPullParserException("already reached end of XML input", this, null);
1530         }
1531         if(reachedEnd) {
1532             return eventType = END_DOCUMENT;
1533         }
1534         boolean gotS = false;
1535         final boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false;
1536         boolean normalizedCR = false;
1537         try {
1538             // epilog: Misc*
1539             char ch;
1540             if(seenMarkup) {
1541                 ch = buf[ pos - 1 ];
1542             } else {
1543                 ch = more();
1544             }
1545             seenMarkup = false;
1546             posStart = pos - 1;
1547             if(!reachedEnd) {
1548                 while(true) {
1549                     // deal with Misc
1550                     // [27] Misc ::= Comment | PI | S
1551                     if(ch == '<') {
1552                         if(gotS && tokenize) {
1553                             posEnd = pos - 1;
1554                             seenMarkup = true;
1555                             return eventType = IGNORABLE_WHITESPACE;
1556                         }
1557                         ch = more();
1558                         if(reachedEnd) {
1559                             break;
1560                         }
1561                         if(ch == '?') {
1562                             // check if it is 'xml'
1563                             // deal with XMLDecl
1564                             parsePI();
1565                             if(tokenize) return eventType = PROCESSING_INSTRUCTION;
1566 
1567                         } else if(ch == '!') {
1568                             ch = more();
1569                             if(reachedEnd) {
1570                                 break;
1571                             }
1572                             if(ch == 'D') {
1573                                 parseDocdecl(); //FIXME
1574                                 if(tokenize) return eventType = DOCDECL;
1575                             } else if(ch == '-') {
1576                                 parseComment();
1577                                 if(tokenize) return eventType = COMMENT;
1578                             } else {
1579                                 throw new XmlPullParserException(
1580                                     "unexpected markup <!"+printable(ch), this, null);
1581                             }
1582                         } else if(ch == '/') {
1583                             throw new XmlPullParserException(
1584                                 "end tag not allowed in epilog but got "+printable(ch), this, null);
1585                         } else if(isNameStartChar(ch)) {
1586                             throw new XmlPullParserException(
1587                                 "start tag not allowed in epilog but got "+printable(ch), this, null);
1588                         } else {
1589                             throw new XmlPullParserException(
1590                                 "in epilog expected ignorable content and not "+printable(ch),
1591                                 this, null);
1592                         }
1593                     } else if(isS(ch)) {
1594                         gotS = true;
1595                         if(normalizeIgnorableWS) {
1596                             if(ch == '\r') {
1597                                 normalizedCR = true;
1598                                 //posEnd = pos -1;
1599                                 //joinPC();
1600                                 // posEnd is already set
1601                                 if(!usePC) {
1602                                     posEnd = pos -1;
1603                                     if(posEnd > posStart) {
1604                                         joinPC();
1605                                     } else {
1606                                         usePC = true;
1607                                         pcStart = pcEnd = 0;
1608                                     }
1609                                 }
1610                                 //assert usePC == true;
1611                                 if(pcEnd >= pc.length) ensurePC(pcEnd);
1612                                 pc[pcEnd++] = '\n';
1613                             } else if(ch == '\n') {
1614                                 if(!normalizedCR && usePC) {
1615                                     if(pcEnd >= pc.length) ensurePC(pcEnd);
1616                                     pc[pcEnd++] = '\n';
1617                                 }
1618                                 normalizedCR = false;
1619                             } else {
1620                                 if(usePC) {
1621                                     if(pcEnd >= pc.length) ensurePC(pcEnd);
1622                                     pc[pcEnd++] = ch;
1623                                 }
1624                                 normalizedCR = false;
1625                             }
1626                         }
1627                     } else {
1628                         throw new XmlPullParserException(
1629                             "in epilog non whitespace content is not allowed but got "+printable(ch),
1630                             this, null);
1631                     }
1632                     ch = more();
1633                     if(reachedEnd) {
1634                         break;
1635                     }
1636 
1637                 }
1638             }
1639 
1640             // throw Exception("unexpected content in epilog
1641             // catch EOFException return END_DOCUMENT
1642             //try {
1643         } catch(EOFException ex) {
1644             reachedEnd = true;
1645         }
1646         if(reachedEnd) {
1647             if(tokenize && gotS) {
1648                 posEnd = pos; // well - this is LAST available character pos
1649                 return eventType = IGNORABLE_WHITESPACE;
1650             }
1651             return eventType = END_DOCUMENT;
1652         } else {
1653             throw new XmlPullParserException("internal error in parseEpilog");
1654         }
1655     }
1656 
1657 
1658     public int parseEndTag() throws XmlPullParserException, IOException {
1659         //ASSUMPTION ch is past "</"
1660         // [42] ETag ::=  '</' Name S? '>'
1661         char ch = more();
1662         if(!isNameStartChar(ch)) {
1663             throw new XmlPullParserException(
1664                 "expected name start and not "+printable(ch), this, null);
1665         }
1666         posStart = pos - 3;
1667         final int nameStart = pos - 1 + bufAbsoluteStart;
1668         do {
1669             ch = more();
1670         } while(isNameChar(ch));
1671 
1672         // now we go one level down -- do checks
1673         //--depth;  //FIXME
1674 
1675         // check that end tag name is the same as start tag
1676         //String name = new String(buf, nameStart - bufAbsoluteStart,
1677         //                           (pos - 1) - (nameStart - bufAbsoluteStart));
1678         //int last = pos - 1;
1679         int off = nameStart - bufAbsoluteStart;
1680         //final int len = last - off;
1681         final int len = (pos - 1) - off;
1682         final char[] cbuf = elRawName[depth];
1683         if(elRawNameEnd[depth] != len) {
1684             // construct strings for exception
1685             final String startname = new String(cbuf, 0, elRawNameEnd[depth]);
1686             final String endname = new String(buf, off, len);
1687             throw new XmlPullParserException(
1688                 "end tag name </"+endname+"> must match start tag name <"+startname+">"
1689                     +" from line "+elRawNameLine[depth], this, null);
1690         }
1691         for (int i = 0; i < len; i++)
1692         {
1693             if(buf[off++] != cbuf[i]) {
1694                 // construct strings for exception
1695                 final String startname = new String(cbuf, 0, len);
1696                 final String endname = new String(buf, off - i - 1, len);
1697                 throw new XmlPullParserException(
1698                     "end tag name </"+endname+"> must be the same as start tag <"+startname+">"
1699                         +" from line "+elRawNameLine[depth], this, null);
1700             }
1701         }
1702 
1703         while(isS(ch)) { ch = more(); } // skip additional white spaces
1704         if(ch != '>') {
1705             throw new XmlPullParserException(
1706                 "expected > to finsh end tag not "+printable(ch)
1707                     +" from line "+elRawNameLine[depth], this, null);
1708         }
1709 
1710 
1711         //namespaceEnd = elNamespaceCount[ depth ]; //FIXME
1712 
1713         posEnd = pos;
1714         pastEndTag = true;
1715         return eventType = END_TAG;
1716     }
1717 
1718     public int parseStartTag() throws XmlPullParserException, IOException {
1719         //ASSUMPTION ch is past <T
1720         // [40] STag ::=  '<' Name (S Attribute)* S? '>'
1721         // [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
1722         ++depth; //FIXME
1723 
1724         posStart = pos - 2;
1725 
1726         emptyElementTag = false;
1727         attributeCount = 0;
1728         // retrieve name
1729         final int nameStart = pos - 1 + bufAbsoluteStart;
1730         int colonPos = -1;
1731         char ch = buf[ pos - 1];
1732         if(ch == ':' && processNamespaces) throw new XmlPullParserException(
1733                 "when namespaces processing enabled colon can not be at element name start",
1734                 this, null);
1735         while(true) {
1736             ch = more();
1737             if(!isNameChar(ch)) break;
1738             if(ch == ':' && processNamespaces) {
1739                 if(colonPos != -1) throw new XmlPullParserException(
1740                         "only one colon is allowed in name of element when namespaces are enabled",
1741                         this, null);
1742                 colonPos = pos - 1 + bufAbsoluteStart;
1743             }
1744         }
1745 
1746         // retrieve name
1747         ensureElementsCapacity();
1748 
1749 
1750         //TODO check for efficient interning and then use elRawNameInterned!!!!
1751 
1752         int elLen = (pos - 1) - (nameStart - bufAbsoluteStart);
1753         if(elRawName[ depth ] == null || elRawName[ depth ].length < elLen) {
1754             elRawName[ depth ] = new char[ 2 * elLen ];
1755         }
1756         System.arraycopy(buf, nameStart - bufAbsoluteStart, elRawName[ depth ], 0, elLen);
1757         elRawNameEnd[ depth ] = elLen;
1758         elRawNameLine[ depth ] = lineNumber;
1759 
1760         String name = null;
1761 
1762         // work on prefixes and namespace URI
1763         String prefix = null;
1764         if(processNamespaces) {
1765             if(colonPos != -1) {
1766                 prefix = elPrefix[ depth ] = newString(buf, nameStart - bufAbsoluteStart,
1767                                                        colonPos - nameStart);
1768                 name = elName[ depth ] = newString(buf, colonPos + 1 - bufAbsoluteStart,
1769                                                    //(pos -1) - (colonPos + 1));
1770                                                    pos - 2 - (colonPos - bufAbsoluteStart));
1771             } else {
1772                 prefix = elPrefix[ depth ] = null;
1773                 name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen);
1774             }
1775         } else {
1776 
1777             name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen);
1778 
1779         }
1780 
1781 
1782         while(true) {
1783 
1784             while(isS(ch)) { ch = more(); } // skip additional white spaces
1785 
1786             if(ch == '>') {
1787                 break;
1788             } else if(ch == '/') {
1789                 if(emptyElementTag) throw new XmlPullParserException(
1790                         "repeated / in tag declaration", this, null);
1791                 emptyElementTag = true;
1792                 ch = more();
1793                 if(ch != '>') throw new XmlPullParserException(
1794                         "expected > to end empty tag not "+printable(ch), this, null);
1795                 break;
1796             } else if(isNameStartChar(ch)) {
1797                 ch = parseAttribute();
1798                 ch = more();
1799                 continue;
1800             } else {
1801                 throw new XmlPullParserException(
1802                     "start tag unexpected character "+printable(ch), this, null);
1803             }
1804             //ch = more(); // skip space
1805         }
1806 
1807         // now when namespaces were declared we can resolve them
1808         if(processNamespaces) {
1809             String uri = getNamespace(prefix);
1810             if(uri == null) {
1811                 if(prefix == null) { // no prefix and no uri => use default namespace
1812                     uri = NO_NAMESPACE;
1813                 } else {
1814                     throw new XmlPullParserException(
1815                         "could not determine namespace bound to element prefix "+prefix,
1816                         this, null);
1817                 }
1818 
1819             }
1820             elUri[ depth ] = uri;
1821 
1822 
1823             //String uri = getNamespace(prefix);
1824             //if(uri == null && prefix == null) { // no prefix and no uri => use default namespace
1825             //  uri = "";
1826             //}
1827             // resolve attribute namespaces
1828             for (int i = 0; i < attributeCount; i++)
1829             {
1830                 final String attrPrefix = attributePrefix[ i ];
1831                 if(attrPrefix != null) {
1832                     final String attrUri = getNamespace(attrPrefix);
1833                     if(attrUri == null) {
1834                         throw new XmlPullParserException(
1835                             "could not determine namespace bound to attribute prefix "+attrPrefix,
1836                             this, null);
1837 
1838                     }
1839                     attributeUri[ i ] = attrUri;
1840                 } else {
1841                     attributeUri[ i ] = NO_NAMESPACE;
1842                 }
1843             }
1844 
1845             //TODO
1846             //[ WFC: Unique Att Spec ]
1847             // check namespaced attribute uniqueness contraint!!!
1848 
1849             for (int i = 1; i < attributeCount; i++)
1850             {
1851                 for (int j = 0; j < i; j++)
1852                 {
1853                     if( attributeUri[j] == attributeUri[i]
1854                            && (allStringsInterned && attributeName[j].equals(attributeName[i])
1855                                    || (!allStringsInterned
1856                                            && attributeNameHash[ j ] == attributeNameHash[ i ]
1857                                            && attributeName[j].equals(attributeName[i])) )
1858 
1859                       ) {
1860                         // prepare data for nice error messgae?
1861                         String attr1 = attributeName[j];
1862                         if(attributeUri[j] != null) attr1 = attributeUri[j]+":"+attr1;
1863                         String attr2 = attributeName[i];
1864                         if(attributeUri[i] != null) attr2 = attributeUri[i]+":"+attr2;
1865                         throw new XmlPullParserException(
1866                             "duplicated attributes "+attr1+" and "+attr2, this, null);
1867                     }
1868                 }
1869             }
1870 
1871 
1872         } else { // ! processNamespaces
1873 
1874             //[ WFC: Unique Att Spec ]
1875             // check raw attribute uniqueness contraint!!!
1876             for (int i = 1; i < attributeCount; i++)
1877             {
1878                 for (int j = 0; j < i; j++)
1879                 {
1880                     if((allStringsInterned && attributeName[j].equals(attributeName[i])
1881                             || (!allStringsInterned
1882                                     && attributeNameHash[ j ] == attributeNameHash[ i ]
1883                                     && attributeName[j].equals(attributeName[i])) )
1884 
1885                       ) {
1886                         // prepare data for nice error messgae?
1887                         final String attr1 = attributeName[j];
1888                         final String attr2 = attributeName[i];
1889                         throw new XmlPullParserException(
1890                             "duplicated attributes "+attr1+" and "+attr2, this, null);
1891                     }
1892                 }
1893             }
1894         }
1895 
1896         elNamespaceCount[ depth ] = namespaceEnd;
1897         posEnd = pos;
1898         return eventType = START_TAG;
1899     }
1900 
1901     protected char parseAttribute() throws XmlPullParserException, IOException
1902     {
1903         // parse attribute
1904         // [41] Attribute ::= Name Eq AttValue
1905         // [WFC: No External Entity References]
1906         // [WFC: No < in Attribute Values]
1907         final int prevPosStart = posStart + bufAbsoluteStart;
1908         final int nameStart = pos - 1 + bufAbsoluteStart;
1909         int colonPos = -1;
1910         char ch = buf[ pos - 1 ];
1911         if(ch == ':' && processNamespaces) throw new XmlPullParserException(
1912                 "when namespaces processing enabled colon can not be at attribute name start",
1913                 this, null);
1914 
1915 
1916         boolean startsWithXmlns = processNamespaces && ch == 'x';
1917         int xmlnsPos = 0;
1918 
1919         ch = more();
1920         while(isNameChar(ch)) {
1921             if(processNamespaces) {
1922                 if(startsWithXmlns && xmlnsPos < 5) {
1923                     ++xmlnsPos;
1924                     if(xmlnsPos == 1) { if(ch != 'm') startsWithXmlns = false; }
1925                     else if(xmlnsPos == 2) { if(ch != 'l') startsWithXmlns = false; }
1926                     else if(xmlnsPos == 3) { if(ch != 'n') startsWithXmlns = false; }
1927                     else if(xmlnsPos == 4) { if(ch != 's') startsWithXmlns = false; }
1928                     else if(xmlnsPos == 5) {
1929                         if(ch != ':') throw new XmlPullParserException(
1930                                 "after xmlns in attribute name must be colon"
1931                                     +"when namespaces are enabled", this, null);
1932                         //colonPos = pos - 1 + bufAbsoluteStart;
1933                     }
1934                 }
1935                 if(ch == ':') {
1936                     if(colonPos != -1) throw new XmlPullParserException(
1937                             "only one colon is allowed in attribute name"
1938                                 +" when namespaces are enabled", this, null);
1939                     colonPos = pos - 1 + bufAbsoluteStart;
1940                 }
1941             }
1942             ch = more();
1943         }
1944 
1945         ensureAttributesCapacity(attributeCount);
1946 
1947         // --- start processing attributes
1948         String name = null;
1949         String prefix = null;
1950         // work on prefixes and namespace URI
1951         if(processNamespaces) {
1952             if(xmlnsPos < 4) startsWithXmlns = false;
1953             if(startsWithXmlns) {
1954                 if(colonPos != -1) {
1955                     //prefix = attributePrefix[ attributeCount ] = null;
1956                     final int nameLen = pos - 2 - (colonPos - bufAbsoluteStart);
1957                     if(nameLen == 0) {
1958                         throw new XmlPullParserException(
1959                             "namespace prefix is required after xmlns: "
1960                                 +" when namespaces are enabled", this, null);
1961                     }
1962                     name = //attributeName[ attributeCount ] =
1963                         newString(buf, colonPos - bufAbsoluteStart + 1, nameLen);
1964                     //pos - 1 - (colonPos + 1 - bufAbsoluteStart)
1965                 }
1966             } else {
1967                 if(colonPos != -1) {
1968                     int prefixLen = colonPos - nameStart;
1969                     prefix = attributePrefix[ attributeCount ] =
1970                         newString(buf, nameStart - bufAbsoluteStart,prefixLen);
1971                     //colonPos - (nameStart - bufAbsoluteStart));
1972                     int nameLen = pos - 2 - (colonPos - bufAbsoluteStart);
1973                     name = attributeName[ attributeCount ] =
1974                         newString(buf, colonPos - bufAbsoluteStart + 1, nameLen);
1975                     //pos - 1 - (colonPos + 1 - bufAbsoluteStart));
1976 
1977                     //name.substring(0, colonPos-nameStart);
1978                 } else {
1979                     prefix = attributePrefix[ attributeCount ]  = null;
1980                     name = attributeName[ attributeCount ] =
1981                         newString(buf, nameStart - bufAbsoluteStart,
1982                                   pos - 1 - (nameStart - bufAbsoluteStart));
1983                 }
1984                 if(!allStringsInterned) {
1985                     attributeNameHash[ attributeCount ] = name.hashCode();
1986                 }
1987             }
1988 
1989         } else {
1990             // retrieve name
1991             name = attributeName[ attributeCount ] =
1992                 newString(buf, nameStart - bufAbsoluteStart,
1993                           pos - 1 - (nameStart - bufAbsoluteStart));
1994             ////assert name != null;
1995             if(!allStringsInterned) {
1996                 attributeNameHash[ attributeCount ] = name.hashCode();
1997             }
1998         }
1999 
2000         // [25] Eq ::=  S? '=' S?
2001         while(isS(ch)) { ch = more(); } // skip additional spaces
2002         if(ch != '=') throw new XmlPullParserException(
2003                 "expected = after attribute name", this, null);
2004         ch = more();
2005         while(isS(ch)) { ch = more(); } // skip additional spaces
2006 
2007         // [10] AttValue ::=   '"' ([^<&"] | Reference)* '"'
2008         //                  |  "'" ([^<&'] | Reference)* "'"
2009         final char delimit = ch;
2010         if(delimit != '"' && delimit != '\'') throw new XmlPullParserException(
2011                 "attribute value must start with quotation or apostrophe not "
2012                     +printable(delimit), this, null);
2013         // parse until delimit or < and resolve Reference
2014         //[67] Reference ::= EntityRef | CharRef
2015         //int valueStart = pos + bufAbsoluteStart;
2016 
2017 
2018         boolean normalizedCR = false;
2019         usePC = false;
2020         pcStart = pcEnd;
2021         posStart = pos;
2022 
2023         while(true) {
2024             ch = more();
2025             if(ch == delimit) {
2026                 break;
2027             } if(ch == '<') {
2028                 throw new XmlPullParserException(
2029                     "markup not allowed inside attribute value - illegal < ", this, null);
2030             } if(ch == '&') {
2031                 // extractEntityRef
2032                 posEnd = pos - 1;
2033                 if(!usePC) {
2034                     final boolean hadCharData = posEnd > posStart;
2035                     if(hadCharData) {
2036                         // posEnd is already set correctly!!!
2037                         joinPC();
2038                     } else {
2039                         usePC = true;
2040                         pcStart = pcEnd = 0;
2041                     }
2042                 }
2043                 //assert usePC == true;
2044 
2045                 final char[] resolvedEntity = parseEntityRef();
2046                 // check if replacement text can be resolved !!!
2047                 if(resolvedEntity == null) {
2048                     if(entityRefName == null) {
2049                         entityRefName = newString(buf, posStart, posEnd - posStart);
2050                     }
2051                     throw new XmlPullParserException(
2052                         "could not resolve entity named '"+printable(entityRefName)+"'",
2053                         this, null);
2054                 }
2055                 // write into PC replacement text - do merge for replacement text!!!!
2056                 for (char aResolvedEntity : resolvedEntity) {
2057                     if (pcEnd >= pc.length) ensurePC(pcEnd);
2058                     pc[pcEnd++] = aResolvedEntity;
2059                 }
2060             } else if(ch == '\t' || ch == '\n' || ch == '\r') {
2061                 // do attribute value normalization
2062                 // as described in http://www.w3.org/TR/REC-xml#AVNormalize
2063                 // TODO add test for it form spec ...
2064                 // handle EOL normalization ...
2065                 if(!usePC) {
2066                     posEnd = pos - 1;
2067                     if(posEnd > posStart) {
2068                         joinPC();
2069                     } else {
2070                         usePC = true;
2071                         pcEnd = pcStart = 0;
2072                     }
2073                 }
2074                 //assert usePC == true;
2075                 if(pcEnd >= pc.length) ensurePC(pcEnd);
2076                 if(ch != '\n' || !normalizedCR) {
2077                     pc[pcEnd++] = ' '; //'\n';
2078                 }
2079 
2080             } else {
2081                 if(usePC) {
2082                     if(pcEnd >= pc.length) ensurePC(pcEnd);
2083                     pc[pcEnd++] = ch;
2084                 }
2085             }
2086             normalizedCR = ch == '\r';
2087         }
2088 
2089 
2090         if(processNamespaces && startsWithXmlns) {
2091             String ns = null;
2092             if(!usePC) {
2093                 ns = newStringIntern(buf, posStart, pos - 1 - posStart);
2094             } else {
2095                 ns = newStringIntern(pc, pcStart, pcEnd - pcStart);
2096             }
2097             ensureNamespacesCapacity(namespaceEnd);
2098             int prefixHash = -1;
2099             if(colonPos != -1) {
2100                 if(ns.length() == 0) {
2101                     throw new XmlPullParserException(
2102                         "non-default namespace can not be declared to be empty string", this, null);
2103                 }
2104                 // declare new namespace
2105                 namespacePrefix[ namespaceEnd ] = name;
2106                 if(!allStringsInterned) {
2107                     prefixHash = namespacePrefixHash[ namespaceEnd ] = name.hashCode();
2108                 }
2109             } else {
2110                 // declare new default namespace...
2111                 namespacePrefix[ namespaceEnd ] = null; //""; //null; //TODO check FIXME Alek
2112                 if(!allStringsInterned) {
2113                     prefixHash = namespacePrefixHash[ namespaceEnd ] = -1;
2114                 }
2115             }
2116             namespaceUri[ namespaceEnd ] = ns;
2117 
2118             // detect duplicate namespace declarations!!!
2119             final int startNs = elNamespaceCount[ depth - 1 ];
2120             for (int i = namespaceEnd - 1; i >= startNs; --i)
2121             {
2122                 if(((allStringsInterned || name == null) && namespacePrefix[ i ] == name)
2123                        || (!allStringsInterned && name != null &&
2124                                namespacePrefixHash[ i ] == prefixHash
2125                                && name.equals(namespacePrefix[ i ])
2126                           ))
2127                 {
2128                     final String s = name == null ? "default" : "'"+name+"'";
2129                     throw new XmlPullParserException(
2130                         "duplicated namespace declaration for "+s+" prefix", this, null);
2131                 }
2132             }
2133 
2134             ++namespaceEnd;
2135 
2136         } else {
2137             if(!usePC) {
2138                 attributeValue[ attributeCount ] =
2139                     new String(buf, posStart, pos - 1 - posStart);
2140             } else {
2141                 attributeValue[ attributeCount ] =
2142                     new String(pc, pcStart, pcEnd - pcStart);
2143             }
2144             ++attributeCount;
2145         }
2146         posStart = prevPosStart - bufAbsoluteStart;
2147         return ch;
2148     }
2149 
2150     protected char[] charRefOneCharBuf = new char[1];
2151 
2152     protected char[] parseEntityRef()
2153         throws XmlPullParserException, IOException
2154     {
2155         // entity reference http://www.w3.org/TR/2000/REC-xml-20001006#NT-Reference
2156         // [67] Reference          ::=          EntityRef | CharRef
2157 
2158         // ASSUMPTION just after &
2159         entityRefName = null;
2160         posStart = pos;
2161         char ch = more();
2162         if(ch == '#') {
2163             // parse character reference
2164             char charRef = 0;
2165             ch = more();
2166             if(ch == 'x') {
2167                 //encoded in hex
2168                 while(true) {
2169                     ch = more();
2170                     if(ch >= '0' && ch <= '9') {
2171                         charRef = (char)(charRef * 16 + (ch - '0'));
2172                     } else if(ch >= 'a' && ch <= 'f') {
2173                         charRef = (char)(charRef * 16 + (ch - ('a' - 10)));
2174                     } else if(ch >= 'A' && ch <= 'F') {
2175                         charRef = (char)(charRef * 16 + (ch - ('A' - 10)));
2176                     } else if(ch == ';') {
2177                         break;
2178                     } else {
2179                         throw new XmlPullParserException(
2180                             "character reference (with hex value) may not contain "
2181                                 +printable(ch), this, null);
2182                     }
2183                 }
2184             } else {
2185                 // encoded in decimal
2186                 while(true) {
2187                     if(ch >= '0' && ch <= '9') {
2188                         charRef = (char)(charRef * 10 + (ch - '0'));
2189                     } else if(ch == ';') {
2190                         break;
2191                     } else {
2192                         throw new XmlPullParserException(
2193                             "character reference (with decimal value) may not contain "
2194                                 +printable(ch), this, null);
2195                     }
2196                     ch = more();
2197                 }
2198             }
2199             posEnd = pos - 1;
2200             charRefOneCharBuf[0] = charRef;
2201             if(tokenize) {
2202                 text = newString(charRefOneCharBuf, 0, 1);
2203             }
2204             return charRefOneCharBuf;
2205         } else {
2206             // [68]     EntityRef          ::=          '&' Name ';'
2207             // scan anem until ;
2208             if(!isNameStartChar(ch)) {
2209                 throw new XmlPullParserException(
2210                     "entity reference names can not start with character '"
2211                         +printable(ch)+"'", this, null);
2212             }
2213             while(true) {
2214                 ch = more();
2215                 if(ch == ';') {
2216                     break;
2217                 }
2218                 if(!isNameChar(ch)) {
2219                     throw new XmlPullParserException(
2220                         "entity reference name can not contain character "
2221                             +printable(ch)+"'", this, null);
2222                 }
2223             }
2224             posEnd = pos - 1;
2225             // determine what name maps to
2226             final int len = posEnd - posStart;
2227             if(len == 2 && buf[posStart] == 'l' && buf[posStart+1] == 't') {
2228                 if(tokenize) {
2229                     text = "<";
2230                 }
2231                 charRefOneCharBuf[0] = '<';
2232                 return charRefOneCharBuf;
2233                 //if(paramPC || isParserTokenizing) {
2234                 //    if(pcEnd >= pc.length) ensurePC();
2235                 //   pc[pcEnd++] = '<';
2236                 //}
2237             } else if(len == 3 && buf[posStart] == 'a'
2238                           && buf[posStart+1] == 'm' && buf[posStart+2] == 'p') {
2239                 if(tokenize) {
2240                     text = "&";
2241                 }
2242                 charRefOneCharBuf[0] = '&';
2243                 return charRefOneCharBuf;
2244             } else if(len == 2 && buf[posStart] == 'g' && buf[posStart+1] == 't') {
2245                 if(tokenize) {
2246                     text = ">";
2247                 }
2248                 charRefOneCharBuf[0] = '>';
2249                 return charRefOneCharBuf;
2250             } else if(len == 4 && buf[posStart] == 'a' && buf[posStart+1] == 'p'
2251                           && buf[posStart+2] == 'o' && buf[posStart+3] == 's')
2252             {
2253                 if(tokenize) {
2254                     text = "'";
2255                 }
2256                 charRefOneCharBuf[0] = '\'';
2257                 return charRefOneCharBuf;
2258             } else if(len == 4 && buf[posStart] == 'q' && buf[posStart+1] == 'u'
2259                           && buf[posStart+2] == 'o' && buf[posStart+3] == 't')
2260             {
2261                 if(tokenize) {
2262                     text = "\"";
2263                 }
2264                 charRefOneCharBuf[0] = '"';
2265                 return charRefOneCharBuf;
2266             } else {
2267                 final char[] result = lookuEntityReplacement(len);
2268                 if(result != null) {
2269                     return result;
2270                 }
2271             }
2272             if(tokenize) text = null;
2273             return null;
2274         }
2275     }
2276 
2277     protected char[] lookuEntityReplacement(int entitNameLen)
2278         throws XmlPullParserException, IOException
2279 
2280     {
2281         if(!allStringsInterned) {
2282             final int hash = fastHash(buf, posStart, posEnd - posStart);
2283             LOOP:
2284             for (int i = entityEnd - 1; i >= 0; --i)
2285             {
2286                 if(hash == entityNameHash[ i ] && entitNameLen == entityNameBuf[ i ].length) {
2287                     final char[] entityBuf = entityNameBuf[ i ];
2288                     for (int j = 0; j < entitNameLen; j++)
2289                     {
2290                         if(buf[posStart + j] != entityBuf[j]) continue LOOP;
2291                     }
2292                     if(tokenize) text = entityReplacement[ i ];
2293                     return entityReplacementBuf[ i ];
2294                 }
2295             }
2296         } else {
2297             entityRefName = newString(buf, posStart, posEnd - posStart);
2298             for (int i = entityEnd - 1; i >= 0; --i)
2299             {
2300                 // take advantage that interning for newStirng is enforced
2301                 if(entityRefName == entityName[ i ]) {
2302                     if(tokenize) text = entityReplacement[ i ];
2303                     return entityReplacementBuf[ i ];
2304                 }
2305             }
2306         }
2307         return null;
2308     }
2309 
2310 
2311     protected void parseComment()
2312         throws XmlPullParserException, IOException
2313     {
2314         // implements XML 1.0 Section 2.5 Comments
2315 
2316         //ASSUMPTION: seen <!-
2317         char ch = more();
2318         if(ch != '-') throw new XmlPullParserException(
2319                 "expected <!-- for comment start", this, null);
2320         if(tokenize) posStart = pos;
2321 
2322         final int curLine = lineNumber;
2323         final int curColumn = columnNumber;
2324         try {
2325             final boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false;
2326             boolean normalizedCR = false;
2327 
2328             boolean seenDash = false;
2329             boolean seenDashDash = false;
2330             while(true) {
2331                 // scan until it hits -->
2332                 ch = more();
2333                 if(seenDashDash && ch != '>') {
2334                     throw new XmlPullParserException(
2335                         "in comment after two dashes (--) next character must be >"
2336                             +" not "+printable(ch), this, null);
2337                 }
2338                 if(ch == '-') {
2339                     if(!seenDash) {
2340                         seenDash = true;
2341                     } else {
2342                         seenDashDash = true;
2343                         seenDash = false;
2344                     }
2345                 } else if(ch == '>') {
2346                     if(seenDashDash) {
2347                         break;  // found end sequence!!!!
2348                     } else {
2349                         seenDashDash = false;
2350                     }
2351                     seenDash = false;
2352                 } else {
2353                     seenDash = false;
2354                 }
2355                 if(normalizeIgnorableWS) {
2356                     if(ch == '\r') {
2357                         normalizedCR = true;
2358                         //posEnd = pos -1;
2359                         //joinPC();
2360                         // posEnd is alreadys set
2361                         if(!usePC) {
2362                             posEnd = pos -1;
2363                             if(posEnd > posStart) {
2364                                 joinPC();
2365                             } else {
2366                                 usePC = true;
2367                                 pcStart = pcEnd = 0;
2368                             }
2369                         }
2370                         //assert usePC == true;
2371                         if(pcEnd >= pc.length) ensurePC(pcEnd);
2372                         pc[pcEnd++] = '\n';
2373                     } else if(ch == '\n') {
2374                         if(!normalizedCR && usePC) {
2375                             if(pcEnd >= pc.length) ensurePC(pcEnd);
2376                             pc[pcEnd++] = '\n';
2377                         }
2378                         normalizedCR = false;
2379                     } else {
2380                         if(usePC) {
2381                             if(pcEnd >= pc.length) ensurePC(pcEnd);
2382                             pc[pcEnd++] = ch;
2383                         }
2384                         normalizedCR = false;
2385                     }
2386                 }
2387             }
2388 
2389         } catch(EOFException ex) {
2390             // detect EOF and create meaningful error ...
2391             throw new XmlPullParserException(
2392                 "comment started on line "+curLine+" and column "+curColumn+" was not closed",
2393                 this, ex);
2394         }
2395         if(tokenize) {
2396             posEnd = pos - 3;
2397             if(usePC) {
2398                 pcEnd -= 2;
2399             }
2400         }
2401     }
2402 
2403     protected boolean parsePI()
2404         throws XmlPullParserException, IOException
2405     {
2406         // implements XML 1.0 Section 2.6 Processing Instructions
2407 
2408         // [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
2409         // [17] PITarget         ::=    Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
2410         //ASSUMPTION: seen <?
2411         if(tokenize) posStart = pos;
2412         final int curLine = lineNumber;
2413         final int curColumn = columnNumber;
2414         int piTargetStart = pos + bufAbsoluteStart;
2415         int piTargetEnd = -1;
2416         final boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false;
2417         boolean normalizedCR = false;
2418 
2419         try {
2420             boolean seenQ = false;
2421             char ch = more();
2422             if(isS(ch)) {
2423                 throw new XmlPullParserException(
2424                     "processing instruction PITarget must be exactly after <? and not white space character",
2425                     this, null);
2426             }
2427             while(true) {
2428                 // scan until it hits ?>
2429                 //ch = more();
2430 
2431                 if(ch == '?') {
2432                     seenQ = true;
2433                 } else if(ch == '>') {
2434                     if(seenQ) {
2435                         break;  // found end sequence!!!!
2436                     }
2437                     seenQ = false;
2438                 } else {
2439                     if(piTargetEnd == -1 && isS(ch)) {
2440                         piTargetEnd = pos - 1 + bufAbsoluteStart;
2441 
2442                         // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
2443                         if((piTargetEnd - piTargetStart) == 3) {
2444                             if((buf[piTargetStart] == 'x' || buf[piTargetStart] == 'X')
2445                                    && (buf[piTargetStart+1] == 'm' || buf[piTargetStart+1] == 'M')
2446                                    && (buf[piTargetStart+2] == 'l' || buf[piTargetStart+2] == 'L')
2447                               )
2448                             {
2449                                 if(piTargetStart > 3) {  //<?xml is allowed as first characters in input ...
2450                                     throw new XmlPullParserException(
2451                                         "processing instruction can not have PITarget with reserveld xml name",
2452                                         this, null);
2453                                 } else {
2454                                     if(buf[piTargetStart] != 'x'
2455                                            && buf[piTargetStart+1] != 'm'
2456                                            && buf[piTargetStart+2] != 'l')
2457                                     {
2458                                         throw new XmlPullParserException(
2459                                             "XMLDecl must have xml name in lowercase",
2460                                             this, null);
2461                                     }
2462                                 }
2463                                 parseXmlDecl(ch);
2464                                 if(tokenize) posEnd = pos - 2;
2465                                 final int off = piTargetStart - bufAbsoluteStart + 3;
2466                                 final int len = pos - 2 - off;
2467                                 xmlDeclContent = newString(buf, off, len);
2468                                 return false;
2469                             }
2470                         }
2471                     }
2472                     seenQ = false;
2473                 }
2474                 if(normalizeIgnorableWS) {
2475                     if(ch == '\r') {
2476                         normalizedCR = true;
2477                         //posEnd = pos -1;
2478                         //joinPC();
2479                         // posEnd is alreadys set
2480                         if(!usePC) {
2481                             posEnd = pos -1;
2482                             if(posEnd > posStart) {
2483                                 joinPC();
2484                             } else {
2485                                 usePC = true;
2486                                 pcStart = pcEnd = 0;
2487                             }
2488                         }
2489                         //assert usePC == true;
2490                         if(pcEnd >= pc.length) ensurePC(pcEnd);
2491                         pc[pcEnd++] = '\n';
2492                     } else if(ch == '\n') {
2493                         if(!normalizedCR && usePC) {
2494                             if(pcEnd >= pc.length) ensurePC(pcEnd);
2495                             pc[pcEnd++] = '\n';
2496                         }
2497                         normalizedCR = false;
2498                     } else {
2499                         if(usePC) {
2500                             if(pcEnd >= pc.length) ensurePC(pcEnd);
2501                             pc[pcEnd++] = ch;
2502                         }
2503                         normalizedCR = false;
2504                     }
2505                 }
2506                 ch = more();
2507             }
2508         } catch(EOFException ex) {
2509             // detect EOF and create meaningful error ...
2510             throw new XmlPullParserException(
2511                 "processing instruction started on line "+curLine+" and column "+curColumn
2512                     +" was not closed",
2513                 this, ex);
2514         }
2515         if(piTargetEnd == -1) {
2516             piTargetEnd = pos - 2 + bufAbsoluteStart;
2517             //throw new XmlPullParserException(
2518             //    "processing instruction must have PITarget name", this, null);
2519         }
2520         piTargetStart -= bufAbsoluteStart;
2521         piTargetEnd -= bufAbsoluteStart;
2522         if(tokenize) {
2523             posEnd = pos - 2;
2524             if(normalizeIgnorableWS) {
2525                 --pcEnd;
2526             }
2527         }
2528         return true;
2529     }
2530 
2531     //    protected final static char[] VERSION = {'v','e','r','s','i','o','n'};
2532     //    protected final static char[] NCODING = {'n','c','o','d','i','n','g'};
2533     //    protected final static char[] TANDALONE = {'t','a','n','d','a','l','o','n','e'};
2534     //    protected final static char[] YES = {'y','e','s'};
2535     //    protected final static char[] NO = {'n','o'};
2536 
2537     protected final static char[] VERSION = "version".toCharArray();
2538     protected final static char[] NCODING = "ncoding".toCharArray();
2539     protected final static char[] TANDALONE = "tandalone".toCharArray();
2540     protected final static char[] YES = "yes".toCharArray();
2541     protected final static char[] NO = "no".toCharArray();
2542 
2543 
2544 
2545     protected void parseXmlDecl(char ch)
2546         throws XmlPullParserException, IOException
2547     {
2548         // [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
2549 
2550         // first make sure that relative positions will stay OK
2551         preventBufferCompaction = true;
2552         bufStart = 0; // necessary to keep pos unchanged during expansion!
2553 
2554         // --- parse VersionInfo
2555 
2556         // [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
2557         // parse is positioned just on first S past <?xml
2558         ch = skipS(ch);
2559         ch = requireInput(ch, VERSION);
2560         // [25] Eq ::= S? '=' S?
2561         ch = skipS(ch);
2562         if(ch != '=') {
2563             throw new XmlPullParserException(
2564                 "expected equals sign (=) after version and not "+printable(ch), this, null);
2565         }
2566         ch = more();
2567         ch = skipS(ch);
2568         if(ch != '\'' && ch != '"') {
2569             throw new XmlPullParserException(
2570                 "expected apostrophe (') or quotation mark (\") after version and not "
2571                     +printable(ch), this, null);
2572         }
2573         final char quotChar = ch;
2574         //int versionStart = pos + bufAbsoluteStart;  // required if preventBufferCompaction==false
2575         final int versionStart = pos;
2576         ch = more();
2577         // [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
2578         while(ch != quotChar) {
2579             if((ch  < 'a' || ch > 'z') && (ch  < 'A' || ch > 'Z') && (ch  < '0' || ch > '9')
2580                    && ch != '_' && ch != '.' && ch != ':' && ch != '-')
2581             {
2582                 throw new XmlPullParserException(
2583                     "<?xml version value expected to be in ([a-zA-Z0-9_.:] | '-')"
2584                         +" not "+printable(ch), this, null);
2585             }
2586             ch = more();
2587         }
2588         final int versionEnd = pos - 1;
2589         parseXmlDeclWithVersion(versionStart, versionEnd);
2590         preventBufferCompaction = false; // allow again buffer commpaction - pos MAY chnage
2591     }
2592     //protected String xmlDeclVersion;
2593 
2594     protected void parseXmlDeclWithVersion(int versionStart, int versionEnd)
2595         throws XmlPullParserException, IOException
2596     {
2597         // check version is "1.0"
2598         if((versionEnd - versionStart != 3)
2599                || buf[versionStart] != '1'
2600                || buf[versionStart+1] != '.'
2601                || buf[versionStart+2] != '0')
2602         {
2603             throw new XmlPullParserException(
2604                 "only 1.0 is supported as <?xml version not '"
2605                     +printable(new String(buf, versionStart, versionEnd - versionStart))+"'", this, null);
2606         }
2607         xmlDeclVersion = newString(buf, versionStart, versionEnd - versionStart);
2608 
2609         // [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" )
2610         char ch = more();
2611         ch = skipS(ch);
2612         if(ch == 'e') {
2613             ch = more();
2614             ch = requireInput(ch, NCODING);
2615             ch = skipS(ch);
2616             if(ch != '=') {
2617                 throw new XmlPullParserException(
2618                     "expected equals sign (=) after encoding and not "+printable(ch), this, null);
2619             }
2620             ch = more();
2621             ch = skipS(ch);
2622             if(ch != '\'' && ch != '"') {
2623                 throw new XmlPullParserException(
2624                     "expected apostrophe (') or quotation mark (\") after encoding and not "
2625                         +printable(ch), this, null);
2626             }
2627             final char quotChar = ch;
2628             final int encodingStart = pos;
2629             ch = more();
2630             // [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
2631             if((ch  < 'a' || ch > 'z') && (ch  < 'A' || ch > 'Z'))
2632             {
2633                 throw new XmlPullParserException(
2634                     "<?xml encoding name expected to start with [A-Za-z]"
2635                         +" not "+printable(ch), this, null);
2636             }
2637             ch = more();
2638             while(ch != quotChar) {
2639                 if((ch  < 'a' || ch > 'z') && (ch  < 'A' || ch > 'Z') && (ch  < '0' || ch > '9')
2640                        && ch != '.' && ch != '_' && ch != '-')
2641                 {
2642                     throw new XmlPullParserException(
2643                         "<?xml encoding value expected to be in ([A-Za-z0-9._] | '-')"
2644                             +" not "+printable(ch), this, null);
2645                 }
2646                 ch = more();
2647             }
2648             final int encodingEnd = pos - 1;
2649 
2650 
2651             // TODO reconcile with setInput encodingName
2652             inputEncoding = newString(buf, encodingStart, encodingEnd - encodingStart);
2653             ch = more();
2654         }
2655 
2656         ch = skipS(ch);
2657         // [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
2658         if(ch == 's') {
2659             ch = more();
2660             ch = requireInput(ch, TANDALONE);
2661             ch = skipS(ch);
2662             if(ch != '=') {
2663                 throw new XmlPullParserException(
2664                     "expected equals sign (=) after standalone and not "+printable(ch),
2665                     this, null);
2666             }
2667             ch = more();
2668             ch = skipS(ch);
2669             if(ch != '\'' && ch != '"') {
2670                 throw new XmlPullParserException(
2671                     "expected apostrophe (') or quotation mark (\") after encoding and not "
2672                         +printable(ch), this, null);
2673             }
2674             char quotChar = ch;
2675             int standaloneStart = pos;
2676             ch = more();
2677             if(ch == 'y') {
2678                 ch = requireInput(ch, YES);
2679                 //Boolean standalone = new Boolean(true);
2680                 xmlDeclStandalone = true;
2681             } else if(ch == 'n') {
2682                 ch = requireInput(ch, NO);
2683                 //Boolean standalone = new Boolean(false);
2684                 xmlDeclStandalone = false;
2685             } else {
2686                 throw new XmlPullParserException(
2687                     "expected 'yes' or 'no' after standalone and not "
2688                         +printable(ch), this, null);
2689             }
2690             if(ch != quotChar) {
2691                 throw new XmlPullParserException(
2692                     "expected "+quotChar+" after standalone value not "
2693                         +printable(ch), this, null);
2694             }
2695             ch = more();
2696         }
2697 
2698 
2699         ch = skipS(ch);
2700         if(ch != '?') {
2701             throw new XmlPullParserException(
2702                 "expected ?> as last part of <?xml not "
2703                     +printable(ch), this, null);
2704         }
2705         ch = more();
2706         if(ch != '>') {
2707             throw new XmlPullParserException(
2708                 "expected ?> as last part of <?xml not "
2709                     +printable(ch), this, null);
2710         }
2711 
2712     }
2713     protected void parseDocdecl()
2714         throws XmlPullParserException, IOException
2715     {
2716         //ASSUMPTION: seen <!D
2717         char ch = more();
2718         if(ch != 'O') throw new XmlPullParserException(
2719                 "expected <!DOCTYPE", this, null);
2720         ch = more();
2721         if(ch != 'C') throw new XmlPullParserException(
2722                 "expected <!DOCTYPE", this, null);
2723         ch = more();
2724         if(ch != 'T') throw new XmlPullParserException(
2725                 "expected <!DOCTYPE", this, null);
2726         ch = more();
2727         if(ch != 'Y') throw new XmlPullParserException(
2728                 "expected <!DOCTYPE", this, null);
2729         ch = more();
2730         if(ch != 'P') throw new XmlPullParserException(
2731                 "expected <!DOCTYPE", this, null);
2732         ch = more();
2733         if(ch != 'E') throw new XmlPullParserException(
2734                 "expected <!DOCTYPE", this, null);
2735         posStart = pos;
2736         // do simple and crude scanning for end of doctype
2737 
2738         // [28]  doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('['
2739         //                      (markupdecl | DeclSep)* ']' S?)? '>'
2740         int bracketLevel = 0;
2741         final boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false;
2742         boolean normalizedCR = false;
2743         while(true) {
2744             ch = more();
2745             if(ch == '[') ++bracketLevel;
2746             if(ch == ']') --bracketLevel;
2747             if(ch == '>' && bracketLevel == 0) break;
2748             if(normalizeIgnorableWS) {
2749                 if(ch == '\r') {
2750                     normalizedCR = true;
2751                     //posEnd = pos -1;
2752                     //joinPC();
2753                     // posEnd is alreadys set
2754                     if(!usePC) {
2755                         posEnd = pos -1;
2756                         if(posEnd > posStart) {
2757                             joinPC();
2758                         } else {
2759                             usePC = true;
2760                             pcStart = pcEnd = 0;
2761                         }
2762                     }
2763                     //assert usePC == true;
2764                     if(pcEnd >= pc.length) ensurePC(pcEnd);
2765                     pc[pcEnd++] = '\n';
2766                 } else if(ch == '\n') {
2767                     if(!normalizedCR && usePC) {
2768                         if(pcEnd >= pc.length) ensurePC(pcEnd);
2769                         pc[pcEnd++] = '\n';
2770                     }
2771                     normalizedCR = false;
2772                 } else {
2773                     if(usePC) {
2774                         if(pcEnd >= pc.length) ensurePC(pcEnd);
2775                         pc[pcEnd++] = ch;
2776                     }
2777                     normalizedCR = false;
2778                 }
2779             }
2780 
2781         }
2782         posEnd = pos - 1;
2783     }
2784 
2785     protected void parseCDSect(boolean hadCharData)
2786         throws XmlPullParserException, IOException
2787     {
2788         // implements XML 1.0 Section 2.7 CDATA Sections
2789 
2790         // [18] CDSect ::= CDStart CData CDEnd
2791         // [19] CDStart ::=  '<![CDATA['
2792         // [20] CData ::= (Char* - (Char* ']]>' Char*))
2793         // [21] CDEnd ::= ']]>'
2794 
2795         //ASSUMPTION: seen <![
2796         char ch = more();
2797         if(ch != 'C') throw new XmlPullParserException(
2798                 "expected <[CDATA[ for comment start", this, null);
2799         ch = more();
2800         if(ch != 'D') throw new XmlPullParserException(
2801                 "expected <[CDATA[ for comment start", this, null);
2802         ch = more();
2803         if(ch != 'A') throw new XmlPullParserException(
2804                 "expected <[CDATA[ for comment start", this, null);
2805         ch = more();
2806         if(ch != 'T') throw new XmlPullParserException(
2807                 "expected <[CDATA[ for comment start", this, null);
2808         ch = more();
2809         if(ch != 'A') throw new XmlPullParserException(
2810                 "expected <[CDATA[ for comment start", this, null);
2811         ch = more();
2812         if(ch != '[') throw new XmlPullParserException(
2813                 "expected <![CDATA[ for comment start", this, null);
2814 
2815         //if(tokenize) {
2816         final int cdStart = pos + bufAbsoluteStart;
2817         final int curLine = lineNumber;
2818         final int curColumn = columnNumber;
2819         final boolean normalizeInput = tokenize == false || roundtripSupported == false;
2820         try {
2821             if(normalizeInput) {
2822                 if(hadCharData) {
2823                     if(!usePC) {
2824                         // posEnd is correct already!!!
2825                         if(posEnd > posStart) {
2826                             joinPC();
2827                         } else {
2828                             usePC = true;
2829                             pcStart = pcEnd = 0;
2830                         }
2831                     }
2832                 }
2833             }
2834             boolean seenBracket = false;
2835             boolean seenBracketBracket = false;
2836             boolean normalizedCR = false;
2837             while(true) {
2838                 // scan until it hits "]]>"
2839                 ch = more();
2840                 if(ch == ']') {
2841                     if(!seenBracket) {
2842                         seenBracket = true;
2843                     } else {
2844                         seenBracketBracket = true;
2845                         //seenBracket = false;
2846                     }
2847                 } else if(ch == '>') {
2848                     if(seenBracket && seenBracketBracket) {
2849                         break;  // found end sequence!!!!
2850                     } else {
2851                         seenBracketBracket = false;
2852                     }
2853                     seenBracket = false;
2854                 } else {
2855                     if(seenBracket) {
2856                         seenBracket = false;
2857                     }
2858                 }
2859                 if(normalizeInput) {
2860                     // deal with normalization issues ...
2861                     if(ch == '\r') {
2862                         normalizedCR = true;
2863                         posStart = cdStart - bufAbsoluteStart;
2864                         posEnd = pos - 1; // posEnd is alreadys set
2865                         if(!usePC) {
2866                             if(posEnd > posStart) {
2867                                 joinPC();
2868                             } else {
2869                                 usePC = true;
2870                                 pcStart = pcEnd = 0;
2871                             }
2872                         }
2873                         //assert usePC == true;
2874                         if(pcEnd >= pc.length) ensurePC(pcEnd);
2875                         pc[pcEnd++] = '\n';
2876                     } else if(ch == '\n') {
2877                         if(!normalizedCR && usePC) {
2878                             if(pcEnd >= pc.length) ensurePC(pcEnd);
2879                             pc[pcEnd++] = '\n';
2880                         }
2881                         normalizedCR = false;
2882                     } else {
2883                         if(usePC) {
2884                             if(pcEnd >= pc.length) ensurePC(pcEnd);
2885                             pc[pcEnd++] = ch;
2886                         }
2887                         normalizedCR = false;
2888                     }
2889                 }
2890             }
2891         } catch(EOFException ex) {
2892             // detect EOF and create meaningful error ...
2893             throw new XmlPullParserException(
2894                 "CDATA section started on line "+curLine+" and column "+curColumn+" was not closed",
2895                 this, ex);
2896         }
2897         if(normalizeInput) {
2898             if(usePC) {
2899                 pcEnd = pcEnd - 2;
2900             }
2901         }
2902         posStart = cdStart - bufAbsoluteStart;
2903         posEnd = pos - 3;
2904     }
2905 
2906     protected void fillBuf() throws IOException, XmlPullParserException {
2907         if(reader == null) throw new XmlPullParserException(
2908                 "reader must be set before parsing is started");
2909 
2910         // see if we are in compaction area
2911         if(bufEnd > bufSoftLimit) {
2912 
2913             // expand buffer it makes sense!!!!
2914             boolean compact = bufStart > bufSoftLimit;
2915             boolean expand = false;
2916             if(preventBufferCompaction) {
2917                 compact = false;
2918                 expand = true;
2919             } else if(!compact) {
2920                 //freeSpace
2921                 if(bufStart < buf.length / 2) {
2922                     // less then half buffer available forcompactin --> expand instead!!!
2923                     expand = true;
2924                 } else {
2925                     // at least half of buffer can be reclaimed --> worthwhile effort!!!
2926                     compact = true;
2927                 }
2928             }
2929 
2930             // if buffer almost full then compact it
2931             if(compact) {
2932                 //TODO: look on trashing
2933                 // //assert bufStart > 0
2934                 System.arraycopy(buf, bufStart, buf, 0, bufEnd - bufStart);
2935                 if(TRACE_SIZING) System.out.println(
2936                         "TRACE_SIZING fillBuf() compacting "+bufStart
2937                             +" bufEnd="+bufEnd
2938                             +" pos="+pos+" posStart="+posStart+" posEnd="+posEnd
2939                             +" buf first 100 chars:"+new String(buf, bufStart,
2940                                                                 bufEnd - bufStart < 100 ? bufEnd - bufStart : 100 ));
2941 
2942             } else if(expand) {
2943                 final int newSize = 2 * buf.length;
2944                 final char newBuf[] = new char[ newSize ];
2945                 if(TRACE_SIZING) System.out.println("TRACE_SIZING fillBuf() "+buf.length+" => "+newSize);
2946                 System.arraycopy(buf, bufStart, newBuf, 0, bufEnd - bufStart);
2947                 buf = newBuf;
2948                 if(bufLoadFactor > 0) {
2949                     bufSoftLimit = ( bufLoadFactor * buf.length ) /100;
2950                 }
2951 
2952             } else {
2953                 throw new XmlPullParserException("internal error in fillBuffer()");
2954             }
2955             bufEnd -= bufStart;
2956             pos -= bufStart;
2957             posStart -= bufStart;
2958             posEnd -= bufStart;
2959             bufAbsoluteStart += bufStart;
2960             bufStart = 0;
2961             if(TRACE_SIZING) System.out.println(
2962                     "TRACE_SIZING fillBuf() after bufEnd="+bufEnd
2963                         +" pos="+pos+" posStart="+posStart+" posEnd="+posEnd
2964                         +" buf first 100 chars:"+new String(buf, 0, bufEnd < 100 ? bufEnd : 100));
2965         }
2966         // at least one charcter must be read or error
2967         final int len = buf.length - bufEnd > READ_CHUNK_SIZE ? READ_CHUNK_SIZE : buf.length - bufEnd;
2968         final int ret = reader.read(buf, bufEnd, len);
2969         if(ret > 0) {
2970             bufEnd += ret;
2971             if(TRACE_SIZING) System.out.println(
2972                     "TRACE_SIZING fillBuf() after filling in buffer"
2973                         +" buf first 100 chars:"+new String(buf, 0, bufEnd < 100 ? bufEnd : 100));
2974 
2975             return;
2976         }
2977         if(ret == -1) {
2978             if(bufAbsoluteStart == 0 && pos == 0) {
2979                 throw new EOFException("input contained no data");
2980             } else {
2981                 if(seenRoot && depth == 0) { // inside parsing epilog!!!
2982                     reachedEnd = true;
2983                     return;
2984                 } else {
2985                     StringBuilder expectedTagStack = new StringBuilder();
2986                     if(depth > 0) {
2987                         //final char[] cbuf = elRawName[depth];
2988                         //final String startname = new String(cbuf, 0, elRawNameEnd[depth]);
2989                         expectedTagStack.append(" - expected end tag");
2990                         if(depth > 1) {
2991                             expectedTagStack.append("s"); //more than one end tag
2992                         }
2993                         expectedTagStack.append(" ");
2994                         for (int i = depth; i > 0; i--)
2995                         {
2996                             String tagName = new String(elRawName[i], 0, elRawNameEnd[i]);
2997                             expectedTagStack.append("</").append(tagName).append('>');
2998                         }
2999                         expectedTagStack.append(" to close");
3000                         for (int i = depth; i > 0; i--)
3001                         {
3002                             if(i != depth) {
3003                                 expectedTagStack.append(" and"); //more than one end tag
3004                             }
3005                             String tagName = new String(elRawName[i], 0, elRawNameEnd[i]);
3006                             expectedTagStack.append(" start tag <").append(tagName).append(">");
3007                             expectedTagStack.append(" from line ").append(elRawNameLine[i]);
3008                         }
3009                         expectedTagStack.append(", parser stopped on");
3010                     }
3011                     throw new EOFException("no more data available"
3012                                                +expectedTagStack.toString()+getPositionDescription());
3013                 }
3014             }
3015         } else {
3016             throw new IOException("error reading input, returned "+ret);
3017         }
3018     }
3019 
3020     protected char more() throws IOException, XmlPullParserException {
3021         if(pos >= bufEnd) {
3022             fillBuf();
3023             // this return value should be ignonored as it is used in epilog parsing ...
3024             if(reachedEnd) return (char)-1;
3025         }
3026         final char ch = buf[pos++];
3027         //line/columnNumber
3028         if(ch == '\n') { ++lineNumber; columnNumber = 1; }
3029         else { ++columnNumber; }
3030         //System.out.print(ch);
3031         return ch;
3032     }
3033 
3034     //    /**
3035     //     * This function returns position of parser in XML input stream
3036     //     * (how many <b>characters</b> were processed.
3037     //     * <p><b>NOTE:</b> this logical position and not byte offset as encodings
3038     //     * such as UTF8 may use more than one byte to encode one character.
3039     //     */
3040     //    public int getCurrentInputPosition() {
3041     //        return pos + bufAbsoluteStart;
3042     //    }
3043 
3044     protected void ensurePC(int end) {
3045         //assert end >= pc.length;
3046         final int newSize = end > READ_CHUNK_SIZE ? 2 * end : 2 * READ_CHUNK_SIZE;
3047         final char[] newPC = new char[ newSize ];
3048         if(TRACE_SIZING) System.out.println("TRACE_SIZING ensurePC() "+pc.length+" ==> "+newSize+" end="+end);
3049         System.arraycopy(pc, 0, newPC, 0, pcEnd);
3050         pc = newPC;
3051         //assert end < pc.length;
3052     }
3053 
3054     protected void joinPC() {
3055         //assert usePC == false;
3056         //assert posEnd > posStart;
3057         final int len = posEnd - posStart;
3058         final int newEnd = pcEnd + len + 1;
3059         if(newEnd >= pc.length) ensurePC(newEnd); // add 1 for extra space for one char
3060         //assert newEnd < pc.length;
3061         System.arraycopy(buf, posStart, pc, pcEnd, len);
3062         pcEnd += len;
3063         usePC = true;
3064 
3065     }
3066 
3067     protected char requireInput(char ch, char[] input)
3068         throws XmlPullParserException, IOException
3069     {
3070         for (char anInput : input) {
3071             if (ch != anInput) {
3072                 throw new XmlPullParserException(
3073                         "expected " + printable(anInput) + " in " + new String(input)
3074                                 + " and not " + printable(ch), this, null);
3075             }
3076             ch = more();
3077         }
3078         return ch;
3079     }
3080 
3081     protected char requireNextS()
3082         throws XmlPullParserException, IOException
3083     {
3084         final char ch = more();
3085         if(!isS(ch)) {
3086             throw new XmlPullParserException(
3087                 "white space is required and not "+printable(ch), this, null);
3088         }
3089         return skipS(ch);
3090     }
3091 
3092     protected char skipS(char ch)
3093         throws XmlPullParserException, IOException
3094     {
3095         while(isS(ch)) { ch = more(); } // skip additional spaces
3096         return ch;
3097     }
3098 
3099     // nameStart / name lookup tables based on XML 1.1 http://www.w3.org/TR/2001/WD-xml11-20011213/
3100     protected static final int LOOKUP_MAX = 0x400;
3101     protected static final char LOOKUP_MAX_CHAR = (char)LOOKUP_MAX;
3102     //    protected static int lookupNameStartChar[] = new int[ LOOKUP_MAX_CHAR / 32 ];
3103     //    protected static int lookupNameChar[] = new int[ LOOKUP_MAX_CHAR / 32 ];
3104     protected static boolean lookupNameStartChar[] = new boolean[ LOOKUP_MAX ];
3105     protected static boolean lookupNameChar[] = new boolean[ LOOKUP_MAX ];
3106 
3107     private static final void setName(char ch)
3108         //{ lookupNameChar[ (int)ch / 32 ] |= (1 << (ch % 32)); }
3109     { lookupNameChar[ ch ] = true; }
3110     private static final void setNameStart(char ch)
3111         //{ lookupNameStartChar[ (int)ch / 32 ] |= (1 << (ch % 32)); setName(ch); }
3112     { lookupNameStartChar[ ch ] = true; setName(ch); }
3113 
3114     static {
3115         setNameStart(':');
3116         for (char ch = 'A'; ch <= 'Z'; ++ch) setNameStart(ch);
3117         setNameStart('_');
3118         for (char ch = 'a'; ch <= 'z'; ++ch) setNameStart(ch);
3119         for (char ch = '\u00c0'; ch <= '\u02FF'; ++ch) setNameStart(ch);
3120         for (char ch = '\u0370'; ch <= '\u037d'; ++ch) setNameStart(ch);
3121         for (char ch = '\u037f'; ch < '\u0400'; ++ch) setNameStart(ch);
3122 
3123         setName('-');
3124         setName('.');
3125         for (char ch = '0'; ch <= '9'; ++ch) setName(ch);
3126         setName('\u00b7');
3127         for (char ch = '\u0300'; ch <= '\u036f'; ++ch) setName(ch);
3128     }
3129 
3130     //private final static boolean isNameStartChar(char ch) {
3131     protected boolean isNameStartChar(char ch) {
3132         return (ch < LOOKUP_MAX_CHAR && lookupNameStartChar[ ch ])
3133             || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027')
3134             || (ch >= '\u202A' &&  ch <= '\u218F')
3135             || (ch >= '\u2800' &&  ch <= '\uFFEF')
3136             ;
3137 
3138         //      if(ch < LOOKUP_MAX_CHAR) return lookupNameStartChar[ ch ];
3139         //      else return ch <= '\u2027'
3140         //              || (ch >= '\u202A' &&  ch <= '\u218F')
3141         //              || (ch >= '\u2800' &&  ch <= '\uFFEF')
3142         //              ;
3143         //return false;
3144         //        return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == ':'
3145         //          || (ch >= '0' && ch <= '9');
3146         //        if(ch < LOOKUP_MAX_CHAR) return (lookupNameStartChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0;
3147         //        if(ch <= '\u2027') return true;
3148         //        //[#x202A-#x218F]
3149         //        if(ch < '\u202A') return false;
3150         //        if(ch <= '\u218F') return true;
3151         //        // added pairts [#x2800-#xD7FF] | [#xE000-#xFDCF] | [#xFDE0-#xFFEF] | [#x10000-#x10FFFF]
3152         //        if(ch < '\u2800') return false;
3153         //        if(ch <= '\uFFEF') return true;
3154         //        return false;
3155 
3156 
3157         // else return (supportXml11 && ( (ch < '\u2027') || (ch > '\u2029' && ch < '\u2200') ...
3158     }
3159 
3160     //private final static boolean isNameChar(char ch) {
3161     protected boolean isNameChar(char ch) {
3162         //return isNameStartChar(ch);
3163 
3164         //        if(ch < LOOKUP_MAX_CHAR) return (lookupNameChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0;
3165 
3166         return (ch < LOOKUP_MAX_CHAR && lookupNameChar[ ch ])
3167             || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027')
3168             || (ch >= '\u202A' &&  ch <= '\u218F')
3169             || (ch >= '\u2800' &&  ch <= '\uFFEF')
3170             ;
3171         //return false;
3172         //        return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == ':'
3173         //          || (ch >= '0' && ch <= '9');
3174         //        if(ch < LOOKUP_MAX_CHAR) return (lookupNameStartChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0;
3175 
3176         //else return
3177         //  else if(ch <= '\u2027') return true;
3178         //        //[#x202A-#x218F]
3179         //        else if(ch < '\u202A') return false;
3180         //        else if(ch <= '\u218F') return true;
3181         //        // added pairts [#x2800-#xD7FF] | [#xE000-#xFDCF] | [#xFDE0-#xFFEF] | [#x10000-#x10FFFF]
3182         //        else if(ch < '\u2800') return false;
3183         //        else if(ch <= '\uFFEF') return true;
3184         //else return false;
3185     }
3186 
3187     protected boolean isS(char ch) {
3188         return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t');
3189         // || (supportXml11 && (ch == '\u0085' || ch == '\u2028');
3190     }
3191 
3192     //protected boolean isChar(char ch) { return (ch < '\uD800' || ch > '\uDFFF')
3193     //  ch != '\u0000' ch < '\uFFFE'
3194 
3195 
3196     //protected char printable(char ch) { return ch; }
3197     protected String printable(char ch) {
3198         if(ch == '\n') {
3199             return "\\n";
3200         } else if(ch == '\r') {
3201             return "\\r";
3202         } else if(ch == '\t') {
3203             return "\\t";
3204         } else if(ch == '\'') {
3205             return "\\'";
3206         } if(ch > 127 || ch < 32) {
3207             return "\\u"+Integer.toHexString((int)ch);
3208         }
3209         return ""+ch;
3210     }
3211 
3212     protected String printable(String s) {
3213         if(s == null) return null;
3214         final int sLen = s.length();
3215         StringBuilder buf = new StringBuilder(sLen + 10);
3216         for(int i = 0; i < sLen; ++i) {
3217             buf.append(printable(s.charAt(i)));
3218         }
3219         s = buf.toString();
3220         return s;
3221     }
3222 }
3223 
3224 
3225 /*
3226  * Indiana University Extreme! Lab Software License, Version 1.2
3227  *
3228  * Copyright (C) 2003 The Trustees of Indiana University.
3229  * All rights reserved.
3230  *
3231  * Redistribution and use in source and binary forms, with or without
3232  * modification, are permitted provided that the following conditions are
3233  * met:
3234  *
3235  * 1) All redistributions of source code must retain the above
3236  *    copyright notice, the list of authors in the original source
3237  *    code, this list of conditions and the disclaimer listed in this
3238  *    license;
3239  *
3240  * 2) All redistributions in binary form must reproduce the above
3241  *    copyright notice, this list of conditions and the disclaimer
3242  *    listed in this license in the documentation and/or other
3243  *    materials provided with the distribution;
3244  *
3245  * 3) Any documentation included with all redistributions must include
3246  *    the following acknowledgement:
3247  *
3248  *      "This product includes software developed by the Indiana
3249  *      University Extreme! Lab.  For further information please visit
3250  *      http://www.extreme.indiana.edu/"
3251  *
3252  *    Alternatively, this acknowledgment may appear in the software
3253  *    itself, and wherever such third-party acknowledgments normally
3254  *    appear.
3255  *
3256  * 4) The name "Indiana University" or "Indiana University
3257  *    Extreme! Lab" shall not be used to endorse or promote
3258  *    products derived from this software without prior written
3259  *    permission from Indiana University.  For written permission,
3260  *    please contact http://www.extreme.indiana.edu/.
3261  *
3262  * 5) Products derived from this software may not use "Indiana
3263  *    University" name nor may "Indiana University" appear in their name,
3264  *    without prior written permission of the Indiana University.
3265  *
3266  * Indiana University provides no reassurances that the source code
3267  * provided does not infringe the patent or any other intellectual
3268  * property rights of any other entity.  Indiana University disclaims any
3269  * liability to any recipient for claims brought by any other entity
3270  * based on infringement of intellectual property rights or otherwise.
3271  *
3272  * LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH
3273  * NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA
3274  * UNIVERSITY GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT
3275  * SOFTWARE IS FREE OF INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR
3276  * OTHER PROPRIETARY RIGHTS.  INDIANA UNIVERSITY MAKES NO WARRANTIES THAT
3277  * SOFTWARE IS FREE FROM "BUGS", "VIRUSES", "TROJAN HORSES", "TRAP
3278  * DOORS", "WORMS", OR OTHER HARMFUL CODE.  LICENSEE ASSUMES THE ENTIRE
3279  * RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR ASSOCIATED MATERIALS,
3280  * AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION GENERATED USING
3281  * SOFTWARE.
3282  */
3283 
3284 
3285 
3286 
3287 
3288