KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xmlpull > mxp1 > MXParser


1 /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/
2 /*
3  * Copyright (c) 2002 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: MXParser.java,v 1.20 2002/10/10 06:49:21 aslom Exp $
8  */

9
10 package org.xmlpull.mxp1;
11
12 import java.io.EOFException JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.Reader JavaDoc;
15 import java.io.InputStreamReader JavaDoc;
16 import java.io.UnsupportedEncodingException JavaDoc;
17
18 //import java.util.Hashtable;
19

20 import org.xmlpull.v1.XmlPullParser;
21 import org.xmlpull.v1.XmlPullParserException;
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 implementaion of XMLPULL V1 API
32  *
33  * @author <a HREF="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
34  */

35
36 public class MXParser
37     implements XmlPullParser
38 {
39     //NOTE: no interning of those strings --> by Java leng spec they MUST be already interned
40
protected final static String JavaDoc XML_URI = "http://www.w3.org/XML/1998/namespace";
41     protected final static String JavaDoc XMLNS_URI = "http://www.w3.org/2000/xmlns/";
42     protected final static String JavaDoc FEATURE_XML_ROUNDTRIP=
43         //"http://xmlpull.org/v1/doc/features.html#xml-roundtrip";
44
"http://xmlpull.org/v1/doc/features.html#xml-roundtrip";
45     protected final static String JavaDoc FEATURE_NAMES_INTERNED =
46         "http://xmlpull.org/v1/doc/features.html#names-interned";
47     protected final static String JavaDoc PROPERTY_XMLDECL_VERSION =
48         "http://xmlpull.org/v1/doc/properties.html#xmldecl-version";
49     protected final static String JavaDoc PROPERTY_XMLDECL_STANDALONE =
50         "http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone";
51     protected final static String JavaDoc PROPERTY_XMLDECL_CONTENT =
52         "http://xmlpull.org/v1/doc/properties.html#xmldecl-content";
53
54
55     /**
56      * Implementation notice:
57      * the is instance variable that controls if newString() is interning.
58      * <p><b>NOTE:</b> newStringIntern <b>always</b> returns interned strings
59      * and newString MAY return interned String depending on this variable.
60      * <p><b>NOTE:</b> by default in this minimal implementation it is false!
61      */

62     protected boolean allStringsInterned;
63
64     protected void resetStringCache() {
65         //System.out.println("resetStringCache() minimum called");
66
}
67
68     protected String JavaDoc newString(char[] cbuf, int off, int len) {
69         return new String JavaDoc(cbuf, off, len);
70     }
71
72     protected String JavaDoc newStringIntern(char[] cbuf, int off, int len) {
73         return (new String JavaDoc(cbuf, off, len)).intern();
74     }
75
76
77     private static final boolean TRACE_SIZING = false;
78
79     // NOTE: features are not resetable and typicaly defaults to false ...
80
protected boolean processNamespaces;
81     protected boolean roundtripSupported;
82
83     // global parser state
84
protected int lineNumber;
85     protected int columnNumber;
86     protected boolean seenRoot;
87     protected boolean reachedEnd;
88     protected int eventType;
89     protected boolean emptyElementTag;
90     // element stack
91
protected int depth;
92     protected char[] elRawName[];
93     protected int elRawNameEnd[];
94     //pnrotected int elRawNameEnd[];
95
protected String JavaDoc elName[];
96     protected String JavaDoc elPrefix[];
97     protected String JavaDoc elUri[];
98     //protected String elValue[];
99
protected int elNamespaceCount[];
100
101
102
103     /**
104      * Make sure that we have enough space to keep element stack if passed size.
105      * It will always create one additional slot then current depth
106      */

107     protected void ensureElementsCapacity() {
108         int elStackSize = elName != null ? elName.length : 0;
109         if( (depth + 1) >= elStackSize) {
110             // we add at least one extra slot ...
111
int newSize = (depth >= 7 ? 2 * depth : 8) + 2; // = lucky 7 + 1 //25
112
if(TRACE_SIZING) {
113                 System.err.println("TRACE_SIZING elStackSize "+elStackSize+" ==> "+newSize);
114             }
115             boolean needsCopying = elStackSize > 0;
116             String JavaDoc[] arr = null;
117             arr = new String JavaDoc[newSize];
118             if(needsCopying) System.arraycopy(elName, 0, arr, 0, elStackSize);
119             elName = arr;
120             arr = new String JavaDoc[newSize];
121             if(needsCopying) System.arraycopy(elPrefix, 0, arr, 0, elStackSize);
122             elPrefix = arr;
123             arr = new String JavaDoc[newSize];
124             if(needsCopying) System.arraycopy(elUri, 0, arr, 0, elStackSize);
125             elUri = arr;
126
127             int[] iarr = new int[newSize];
128             if(needsCopying) {
129                 System.arraycopy(elNamespaceCount, 0, iarr, 0, elStackSize);
130             } else {
131                 // special initialization
132
iarr[0] = 0;
133             }
134             elNamespaceCount = iarr;
135
136             //TODO: avoid using element raw name ...
137
iarr = new int[newSize];
138             if(needsCopying) {
139                 System.arraycopy(elRawNameEnd, 0, iarr, 0, elStackSize);
140             }
141             elRawNameEnd = iarr;
142
143             char[][] carr = new char[newSize][];
144             if(needsCopying) {
145                 System.arraycopy(elRawName, 0, carr, 0, elStackSize);
146             }
147             elRawName = carr;
148             // arr = new String[newSize];
149
// if(needsCopying) System.arraycopy(elLocalName, 0, arr, 0, elStackSize);
150
// elLocalName = arr;
151
// arr = new String[newSize];
152
// if(needsCopying) System.arraycopy(elDefaultNs, 0, arr, 0, elStackSize);
153
// elDefaultNs = arr;
154
// int[] iarr = new int[newSize];
155
// if(needsCopying) System.arraycopy(elNsStackPos, 0, iarr, 0, elStackSize);
156
// for (int i = elStackSize; i < iarr.length; i++)
157
// {
158
// iarr[i] = (i > 0) ? -1 : 0;
159
// }
160
// elNsStackPos = iarr;
161
//assert depth < elName.length;
162
}
163     }
164
165
166     // nameStart / name lookup tables based on XML 1.1 http://www.w3.org/TR/2001/WD-xml11-20011213/
167
protected static final int LOOKUP_MAX = 0x400;
168     protected static final char LOOKUP_MAX_CHAR = (char)LOOKUP_MAX;
169     // protected static int lookupNameStartChar[] = new int[ LOOKUP_MAX_CHAR / 32 ];
170
// protected static int lookupNameChar[] = new int[ LOOKUP_MAX_CHAR / 32 ];
171
protected static boolean lookupNameStartChar[] = new boolean[ LOOKUP_MAX ];
172     protected static boolean lookupNameChar[] = new boolean[ LOOKUP_MAX ];
173
174     private static final void setName(char ch)
175         //{ lookupNameChar[ (int)ch / 32 ] |= (1 << (ch % 32)); }
176
{ lookupNameChar[ ch ] = true; }
177     private static final void setNameStart(char ch)
178         //{ lookupNameStartChar[ (int)ch / 32 ] |= (1 << (ch % 32)); setName(ch); }
179
{ lookupNameStartChar[ ch ] = true; setName(ch); }
180
181     static {
182         setNameStart(':');
183         for (char ch = 'A'; ch <= 'Z'; ++ch) setNameStart(ch);
184         setNameStart('_');
185         for (char ch = 'a'; ch <= 'z'; ++ch) setNameStart(ch);
186         for (char ch = '\u00c0'; ch <= '\u02FF'; ++ch) setNameStart(ch);
187         for (char ch = '\u0370'; ch <= '\u037d'; ++ch) setNameStart(ch);
188         for (char ch = '\u037f'; ch < '\u0400'; ++ch) setNameStart(ch);
189
190         setName('-');
191         setName('.');
192         for (char ch = '0'; ch <= '9'; ++ch) setName(ch);
193         setName('\u00b7');
194         for (char ch = '\u0300'; ch <= '\u036f'; ++ch) setName(ch);
195     }
196
197     //private final static boolean isNameStartChar(char ch) {
198
protected boolean isNameStartChar(char ch) {
199         return (ch < LOOKUP_MAX_CHAR && lookupNameStartChar[ ch ])
200             || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027')
201             || (ch >= '\u202A' && ch <= '\u218F')
202             || (ch >= '\u2800' && ch <= '\uFFEF')
203             ;
204
205         // if(ch < LOOKUP_MAX_CHAR) return lookupNameStartChar[ ch ];
206
// else return ch <= '\u2027'
207
// || (ch >= '\u202A' && ch <= '\u218F')
208
// || (ch >= '\u2800' && ch <= '\uFFEF')
209
// ;
210
//return false;
211
// return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == ':'
212
// || (ch >= '0' && ch <= '9');
213
// if(ch < LOOKUP_MAX_CHAR) return (lookupNameStartChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0;
214
// if(ch <= '\u2027') return true;
215
// //[#x202A-#x218F]
216
// if(ch < '\u202A') return false;
217
// if(ch <= '\u218F') return true;
218
// // added pairts [#x2800-#xD7FF] | [#xE000-#xFDCF] | [#xFDE0-#xFFEF] | [#x10000-#x10FFFF]
219
// if(ch < '\u2800') return false;
220
// if(ch <= '\uFFEF') return true;
221
// return false;
222

223
224         // else return (supportXml11 && ( (ch < '\u2027') || (ch > '\u2029' && ch < '\u2200') ...
225
}
226
227     //private final static boolean isNameChar(char ch) {
228
protected boolean isNameChar(char ch) {
229         //return isNameStartChar(ch);
230

231         // if(ch < LOOKUP_MAX_CHAR) return (lookupNameChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0;
232

233         return (ch < LOOKUP_MAX_CHAR && lookupNameChar[ ch ])
234             || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027')
235             || (ch >= '\u202A' && ch <= '\u218F')
236             || (ch >= '\u2800' && ch <= '\uFFEF')
237             ;
238         //return false;
239
// return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == ':'
240
// || (ch >= '0' && ch <= '9');
241
// if(ch < LOOKUP_MAX_CHAR) return (lookupNameStartChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0;
242

243         //else return
244
// else if(ch <= '\u2027') return true;
245
// //[#x202A-#x218F]
246
// else if(ch < '\u202A') return false;
247
// else if(ch <= '\u218F') return true;
248
// // added pairts [#x2800-#xD7FF] | [#xE000-#xFDCF] | [#xFDE0-#xFFEF] | [#x10000-#x10FFFF]
249
// else if(ch < '\u2800') return false;
250
// else if(ch <= '\uFFEF') return true;
251
//else return false;
252
}
253
254     protected boolean isS(char ch) {
255         return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t');
256         // || (supportXml11 && (ch == '\u0085' || ch == '\u2028');
257
}
258
259     //protected boolean isChar(char ch) { return (ch < '\uD800' || ch > '\uDFFF')
260
// ch != '\u0000' ch < '\uFFFE'
261

262
263     // attribute stack
264
protected int attributeCount;
265     protected String JavaDoc attributeName[];
266     protected int attributeNameHash[];
267     //protected int attributeNameStart[];
268
//protected int attributeNameEnd[];
269
protected String JavaDoc attributePrefix[];
270     protected String JavaDoc attributeUri[];
271     protected String JavaDoc attributeValue[];
272     //protected int attributeValueStart[];
273
//protected int attributeValueEnd[];
274

275
276     /**
277      * Make sure that in attributes temporary array is enough space.
278      */

279     protected void ensureAttributesCapacity(int size) {
280         int attrPosSize = attributeName != null ? attributeName.length : 0;
281         if(size >= attrPosSize) {
282             int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25
283
if(TRACE_SIZING) {
284                 System.err.println("TRACE_SIZING attrPosSize "+attrPosSize+" ==> "+newSize);
285             }
286             boolean needsCopying = attrPosSize > 0;
287             String JavaDoc[] arr = null;
288
289             arr = new String JavaDoc[newSize];
290             if(needsCopying) System.arraycopy(attributeName, 0, arr, 0, attrPosSize);
291             attributeName = arr;
292
293             arr = new String JavaDoc[newSize];
294             if(needsCopying) System.arraycopy(attributePrefix, 0, arr, 0, attrPosSize);
295             attributePrefix = arr;
296
297             arr = new String JavaDoc[newSize];
298             if(needsCopying) System.arraycopy(attributeUri, 0, arr, 0, attrPosSize);
299             attributeUri = arr;
300
301             arr = new String JavaDoc[newSize];
302             if(needsCopying) System.arraycopy(attributeValue, 0, arr, 0, attrPosSize);
303             attributeValue = arr;
304
305             if( ! allStringsInterned ) {
306                 int[] iarr = new int[newSize];
307                 if(needsCopying) System.arraycopy(attributeNameHash, 0, iarr, 0, attrPosSize);
308                 attributeNameHash = iarr;
309             }
310
311             arr = null;
312             // //assert attrUri.length > size
313
}
314     }
315
316     // namespace stack
317
protected int namespaceEnd;
318     protected String JavaDoc namespacePrefix[];
319     protected int namespacePrefixHash[];
320     protected String JavaDoc namespaceUri[];
321
322     protected void ensureNamespacesCapacity(int size) {
323         int namespaceSize = namespacePrefix != null ? namespacePrefix.length : 0;
324         if(size >= namespaceSize) {
325             int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25
326
if(TRACE_SIZING) {
327                 System.err.println("TRACE_SIZING namespaceSize "+namespaceSize+" ==> "+newSize);
328             }
329             String JavaDoc[] newNamespacePrefix = new String JavaDoc[newSize];
330             String JavaDoc[] newNamespaceUri = new String JavaDoc[newSize];
331             if(namespacePrefix != null) {
332                 System.arraycopy(
333                     namespacePrefix, 0, newNamespacePrefix, 0, namespaceEnd);
334                 System.arraycopy(
335                     namespaceUri, 0, newNamespaceUri, 0, namespaceEnd);
336             }
337             namespacePrefix = newNamespacePrefix;
338             namespaceUri = newNamespaceUri;
339
340
341             if( ! allStringsInterned ) {
342                 int[] newNamespacePrefixHash = new int[newSize];
343                 if(namespacePrefixHash != null) {
344                     System.arraycopy(
345                         namespacePrefixHash, 0, newNamespacePrefixHash, 0, namespaceEnd);
346                 }
347                 namespacePrefixHash = newNamespacePrefixHash;
348             }
349             //prefixesSize = newSize;
350
// //assert nsPrefixes.length > size && nsPrefixes.length == newSize
351
}
352     }
353
354     /**
355      * simplistic implementation of hash function that has <b>constant</b>
356      * time to compute - so it also means diminishing hash quality for long strings
357      * but for XML parsing it should be good enough ...
358      */

359     protected static final int fastHash( char ch[], int off, int len ) {
360         if(len == 0) return 0;
361         //assert len >0
362
int hash = ch[off]; // hash at beginnig
363
//try {
364
hash = (hash << 7) + ch[ off + len - 1 ]; // hash at the end
365
//} catch(ArrayIndexOutOfBoundsException aie) {
366
// aie.printStackTrace(); //should never happen ...
367
// throw new RuntimeException("this is violation of pre-condition");
368
//}
369
if(len > 16) hash = (hash << 7) + ch[ off + (len / 4)]; // 1/4 from beginning
370
if(len > 8) hash = (hash << 7) + ch[ off + (len / 2)]; // 1/2 of string size ...
371
// notice that hash is at most done 3 times <<7 so shifted by 21 bits 8 bit value
372
// so max result == 29 bits so it is quite just below 31 bits for long (2^32) ...
373
//assert hash >= 0;
374
return hash;
375     }
376
377     // entity replacement stack
378
protected int entityEnd;
379     protected String JavaDoc entityName[];
380     protected char[] entityNameBuf[];
381     protected int entityNameHash[];
382     protected char[] entityReplacementBuf[];
383     protected String JavaDoc entityReplacement[];
384
385
386     protected void ensureEntityCapacity() {
387         int entitySize = entityReplacementBuf != null ? entityReplacementBuf.length : 0;
388         if(entityEnd >= entitySize) {
389             int newSize = entityEnd > 7 ? 2 * entityEnd : 8; // = lucky 7 + 1 //25
390
if(TRACE_SIZING) {
391                 System.err.println("TRACE_SIZING entitySize "+entitySize+" ==> "+newSize);
392             }
393             String JavaDoc[] newEntityName = new String JavaDoc[newSize];
394             char[] newEntityNameBuf[] = new char[newSize][];
395             String JavaDoc[] newEntityReplacement = new String JavaDoc[newSize];
396             char[] newEntityReplacementBuf[] = new char[newSize][];
397             if(entityName != null) {
398                 System.arraycopy(entityName, 0, newEntityName, 0, entityEnd);
399                 System.arraycopy(entityReplacementBuf, 0, newEntityReplacement, 0, entityEnd);
400                 System.arraycopy(entityReplacement, 0, newEntityReplacement, 0, entityEnd);
401                 System.arraycopy(entityReplacementBuf, 0, newEntityReplacementBuf, 0, entityEnd);
402             }
403             entityName = newEntityName;
404             entityNameBuf = newEntityNameBuf;
405             entityReplacement = newEntityReplacement;
406             entityReplacementBuf = newEntityReplacementBuf;
407
408             if( ! allStringsInterned ) {
409                 int[] newEntityNameHash = new int[newSize];
410                 if(entityNameHash != null) {
411                     System.arraycopy(entityNameHash, 0, newEntityNameHash, 0, entityEnd);
412                 }
413                 entityNameHash = newEntityNameHash;
414             }
415         }
416     }
417
418     // input buffer management
419
protected static final int READ_CHUNK_SIZE = 8*1024; //max data chars in one read() call
420
protected Reader JavaDoc reader;
421     protected String JavaDoc inputEncoding;
422
423
424     protected int bufLoadFactor = 95; // 99%
425
//protected int bufHardLimit; // only matters when expanding
426

427     protected char buf[] = new char[
428         Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 256 ];
429     protected int bufSoftLimit = ( bufLoadFactor * buf.length ) /100; // desirable size of buffer
430
protected boolean preventBufferCompaction;
431
432     protected int bufAbsoluteStart; // this is buf
433
protected int bufStart;
434     protected int bufEnd;
435     protected int pos;
436     protected int posStart;
437     protected int posEnd;
438
439     protected char pc[] = new char[
440         Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 64 ];
441     protected int pcStart;
442     protected int pcEnd;
443
444
445     // parsing state
446
//protected boolean needsMore;
447
//protected boolean seenMarkup;
448
protected boolean usePC;
449
450
451     protected boolean seenStartTag;
452     protected boolean seenEndTag;
453     protected boolean pastEndTag;
454     protected boolean seenAmpersand;
455     protected boolean seenMarkup;
456     protected boolean seenDocdecl;
457
458     // transient variable set during each call to next/Token()
459
protected boolean tokenize;
460     protected String JavaDoc text;
461     protected String JavaDoc entityRefName;
462
463     protected String JavaDoc xmlDeclVersion;
464     protected Boolean JavaDoc xmlDeclStandalone;
465     protected String JavaDoc xmlDeclContent;
466
467     protected void reset() {
468         //System.out.println("reset() called");
469
lineNumber = 1;
470         columnNumber = 0;
471         seenRoot = false;
472         reachedEnd = false;
473         eventType = START_DOCUMENT;
474         emptyElementTag = false;
475
476         depth = 0;
477
478         attributeCount = 0;
479
480         namespaceEnd = 0;
481
482         entityEnd = 0;
483
484         reader = null;
485         inputEncoding = null;
486
487         preventBufferCompaction = false;
488         bufAbsoluteStart = 0;
489         bufEnd = bufStart = 0;
490         pos = posStart = posEnd = 0;
491
492         pcEnd = pcStart = 0;
493
494         usePC = false;
495
496         seenStartTag = false;
497         seenEndTag = false;
498         pastEndTag = false;
499         seenAmpersand = false;
500         seenMarkup = false;
501         seenDocdecl = false;
502
503         xmlDeclVersion = null;
504         xmlDeclStandalone = null;
505         xmlDeclContent = null;
506
507         resetStringCache();
508     }
509
510     public MXParser() {
511     }
512
513
514     /**
515      * Method setFeature
516      *
517      * @param name a String
518      * @param state a boolean
519      *
520      * @throws XmlPullParserException
521      *
522      */

523     public void setFeature(String JavaDoc name,
524                            boolean state) throws XmlPullParserException
525     {
526         if(name == null) throw new IllegalArgumentException JavaDoc("feature name should not be nulll");
527         if(FEATURE_PROCESS_NAMESPACES.equals(name)) {
528             if(eventType != START_DOCUMENT) throw new XmlPullParserException(
529                     "namespace processing feature can only be changed before parsing", this, null);
530             processNamespaces = state;
531             // } else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
532
// if(type != START_DOCUMENT) throw new XmlPullParserException(
533
// "namespace reporting feature can only be changed before parsing", this, null);
534
// reportNsAttribs = state;
535
} else if(FEATURE_NAMES_INTERNED.equals(name)) {
536             if(state != false) {
537                 throw new XmlPullParserException(
538                     "interning names in this implementation is not supported");
539             }
540         } else if(FEATURE_PROCESS_DOCDECL.equals(name)) {
541             if(state != false) {
542                 throw new XmlPullParserException(
543                     "processing DOCDECL is not supported");
544             }
545             //} else if(REPORT_DOCDECL.equals(name)) {
546
// paramNotifyDoctype = state;
547
} else if(FEATURE_XML_ROUNDTRIP.equals(name)) {
548             //if(state == false) {
549
// throw new XmlPullParserException(
550
// "roundtrip feature can not be switched off");
551
//}
552
roundtripSupported = state;
553         } else {
554             throw new XmlPullParserException("unknown feature "+name);
555         }
556     }
557
558     /** Unknown properties are <string>always</strong> returned as false */
559     public boolean getFeature(String JavaDoc name)
560     {
561         if(name == null) throw new IllegalArgumentException JavaDoc("feature name should not be nulll");
562         if(FEATURE_PROCESS_NAMESPACES.equals(name)) {
563             return processNamespaces;
564             // } else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
565
// return reportNsAttribs;
566
} else if(FEATURE_NAMES_INTERNED.equals(name)) {
567             return false;
568         } else if(FEATURE_PROCESS_DOCDECL.equals(name)) {
569             return false;
570             //} else if(REPORT_DOCDECL.equals(name)) {
571
// return paramNotifyDoctype;
572
} else if(FEATURE_XML_ROUNDTRIP.equals(name)) {
573             //return true;
574
return roundtripSupported;
575         }
576         return false;
577     }
578
579     public void setProperty(String JavaDoc name,
580                             Object JavaDoc value)
581         throws XmlPullParserException
582     {
583         throw new XmlPullParserException("unsupported property: '"+name+"'");
584     }
585
586
587     public Object JavaDoc getProperty(String JavaDoc name)
588     {
589         if(name == null) throw new IllegalArgumentException JavaDoc("property name should not be nulll");
590         if(PROPERTY_XMLDECL_VERSION.equals(name)) {
591             return xmlDeclVersion;
592         } else if(PROPERTY_XMLDECL_STANDALONE.equals(name)) {
593             return xmlDeclStandalone;
594         } else if(PROPERTY_XMLDECL_CONTENT.equals(name)) {
595             return xmlDeclContent;
596         }
597         return null;
598     }
599
600
601     public void setInput(Reader JavaDoc in) throws XmlPullParserException
602     {
603         reset();
604         reader = in;
605     }
606
607
608     public void setInput(java.io.InputStream JavaDoc inputStream, String JavaDoc inputEncoding)
609         throws XmlPullParserException
610     {
611         if(inputStream == null) {
612             throw new IllegalArgumentException JavaDoc("input stream can not be null");
613         }
614         Reader JavaDoc reader;
615         if(inputEncoding != null) {
616             try {
617                 if(inputEncoding != null) {
618                     reader = new InputStreamReader JavaDoc(inputStream, inputEncoding);
619                 } else {
620                     reader = new InputStreamReader JavaDoc(inputStream);
621                 }
622             } catch (UnsupportedEncodingException JavaDoc une) {
623                 throw new XmlPullParserException(
624                     "could not create reader for encoding "+inputEncoding+" : "+une, this, une);
625             }
626         } else {
627             reader = new InputStreamReader JavaDoc(inputStream);
628         }
629         setInput(reader);
630         //must be here as reest() was called in setInput() and has set this.inputEncoding to null ...
631
this.inputEncoding = inputEncoding;
632     }
633
634     public String JavaDoc getInputEncoding() {
635         return inputEncoding;
636     }
637
638     public void defineEntityReplacementText(String JavaDoc entityName,
639                                             String JavaDoc replacementText)
640         throws XmlPullParserException
641     {
642         // throw new XmlPullParserException("not allowed");
643

644         //protected char[] entityReplacement[];
645
ensureEntityCapacity();
646
647         // this is to make sure that if interning works we wil take advatage of it ...
648
this.entityName[entityEnd] = newString(entityName.toCharArray(), 0, entityName.length());
649         entityNameBuf[entityEnd] = entityName.toCharArray();
650
651         entityReplacement[entityEnd] = replacementText;
652         entityReplacementBuf[entityEnd] = replacementText.toCharArray();
653         if(!allStringsInterned) {
654             entityNameHash[ entityEnd ] =
655                 fastHash(entityNameBuf[entityEnd], 0, entityNameBuf[entityEnd].length);
656         }
657         ++entityEnd;
658         //TODO disallow < or & in entity replacement text (or ]]>???)
659
// TOOD keepEntityNormalizedForAttributeValue cached as well ...
660
}
661
662     public int getNamespaceCount(int depth)
663         throws XmlPullParserException
664     {
665         if(processNamespaces == false || depth == 0) {
666             return 0;
667         }
668         //int maxDepth = eventType == END_TAG ? this.depth + 1 : this.depth;
669
//if(depth < 0 || depth > maxDepth) throw new IllegalArgumentException(
670
if(depth < 0 || depth > this.depth) throw new IllegalArgumentException JavaDoc(
671                 "napespace count mayt be for depth 0.."+this.depth+" not "+depth);
672         return elNamespaceCount[ depth ];
673     }
674
675     public String JavaDoc getNamespacePrefix(int pos)
676         throws XmlPullParserException
677     {
678
679         //int end = eventType == END_TAG ? elNamespaceCount[ depth + 1 ] : namespaceEnd;
680
//if(pos < end) {
681
if(pos < namespaceEnd) {
682             return namespacePrefix[ pos ];
683         } else {
684             throw new XmlPullParserException(
685                 "position "+pos+" exceeded number of available namespaces "+namespaceEnd);
686         }
687     }
688
689     public String JavaDoc getNamespaceUri(int pos) throws XmlPullParserException
690     {
691         //int end = eventType == END_TAG ? elNamespaceCount[ depth + 1 ] : namespaceEnd;
692
//if(pos < end) {
693
if(pos < namespaceEnd) {
694             return namespaceUri[ pos ];
695         } else {
696             throw new XmlPullParserException(
697                 "position "+pos+" exceedded number of available namespaces "+namespaceEnd);
698         }
699     }
700
701     public String JavaDoc getNamespace( String JavaDoc prefix )
702         //throws XmlPullParserException
703
{
704         //int count = namespaceCount[ depth ];
705
if(prefix != null) {
706             for( int i = namespaceEnd -1; i >= 0; i--) {
707                 if( prefix.equals( namespacePrefix[ i ] ) ) {
708                     return namespaceUri[ i ];
709                 }
710             }
711             if("xml".equals( prefix )) {
712                 return XML_URI;
713             } else if("xmlns".equals( prefix )) {
714                 return XMLNS_URI;
715             }
716         } else {
717             for( int i = namespaceEnd -1; i >= 0; i--) {
718                 if( namespacePrefix[ i ] == null ) {
719                     return namespaceUri[ i ];
720                 }
721             }
722
723         }
724         return null;
725     }
726
727
728     public int getDepth()
729     {
730         return depth;
731     }
732
733
734     private static int findFragment(int bufMinPos, char[] b, int start, int end) {
735         //System.err.println("bufStart="+bufStart+" b="+printable(new String(b, start, end - start))+" start="+start+" end="+end);
736
if(start < bufMinPos) {
737             start = bufMinPos;
738             if(start > end) start = end;
739             return start;
740         }
741         if(end - start > 65) {
742             start = end - 10; // try to find good location
743
}
744         int i = start + 1;
745         while(--i > bufMinPos) {
746             if((end - i) > 65) break;
747             char c = b[i];
748             if(c == '<' && (start - i) > 10) break;
749         }
750         return i;
751     }
752
753
754     /**
755      * Return string describing current position of parsers as
756      * text 'STATE [seen %s...] @line:column'.
757      */

758     public String JavaDoc getPositionDescription ()
759     {
760         String JavaDoc fragment = null;
761         if(posStart <= pos) {
762             int start = findFragment(0, buf, posStart, pos);
763             //System.err.println("start="+start);
764
if(start < pos) {
765                 fragment = new String JavaDoc(buf, start, pos - start);
766             }
767             if(bufAbsoluteStart > 0 || start > 0) fragment = "..." + fragment;
768         }
769         // return " at line "+tokenizerPosRow
770
// +" and column "+(tokenizerPosCol-1)
771
// +(fragment != null ? " seen "+printable(fragment)+"..." : "");
772
return " "+TYPES[ eventType ] +
773             (fragment != null ? " seen "+printable(fragment)+"..." : "")+
774             " @"+getLineNumber()+":"+getColumnNumber();
775     }
776
777     public int getLineNumber()
778     {
779         return lineNumber;
780     }
781
782     public int getColumnNumber()
783     {
784         return columnNumber;
785     }
786
787
788     public boolean isWhitespace() throws XmlPullParserException
789     {
790         if(eventType == TEXT || eventType == CDSECT) {
791             if(usePC) {
792                 for (int i = pcStart; i <pcEnd; i++)
793                 {
794                     if(!isS(pc[ i ])) return false;
795                 }
796                 return true;
797             } else {
798                 for (int i = posStart; i <posEnd; i++)
799                 {
800                     if(!isS(buf[ i ])) return false;
801                 }
802                 return true;
803             }
804         } else if(eventType == IGNORABLE_WHITESPACE) {
805             return true;
806         }
807         throw new XmlPullParserException("no content available to check for whitespaces");
808     }
809
810     public String JavaDoc getText()
811     {
812         if(eventType == START_DOCUMENT || eventType == END_DOCUMENT) {
813             //throw new XmlPullParserException("no content available to read");
814
// if(roundtripSupported) {
815
// text = new String(buf, posStart, posEnd - posStart);
816
// } else {
817
return null;
818             // }
819
} else if(eventType == ENTITY_REF) {
820             return text;
821         }
822         if(text == null) {
823             if(!usePC || eventType == START_TAG || eventType == END_TAG) {
824                 text = new String JavaDoc(buf, posStart, posEnd - posStart);
825             } else {
826                 text = new String JavaDoc(pc, pcStart, pcEnd - pcStart);
827             }
828         }
829         return text;
830     }
831
832     public char[] getTextCharacters(int [] holderForStartAndLength)
833     {
834         if( eventType == TEXT ) {
835             if(usePC) {
836                 holderForStartAndLength[0] = pcStart;
837                 holderForStartAndLength[1] = pcEnd - pcStart;
838                 return pc;
839             } else {
840                 holderForStartAndLength[0] = posStart;
841                 holderForStartAndLength[1] = posEnd - posStart;
842                 return buf;
843
844             }
845         } else if( eventType == START_TAG
846                   || eventType == END_TAG
847                   || eventType == CDSECT
848                   || eventType == COMMENT
849                   || eventType == ENTITY_REF
850                   || eventType == PROCESSING_INSTRUCTION
851                   || eventType == IGNORABLE_WHITESPACE
852                   || eventType == DOCDECL)
853         {
854             holderForStartAndLength[0] = posStart;
855             holderForStartAndLength[1] = posEnd - posStart;
856             return buf;
857         } else if(eventType == START_DOCUMENT
858                   || eventType == END_DOCUMENT) {
859             //throw new XmlPullParserException("no content available to read");
860
holderForStartAndLength[0] = holderForStartAndLength[1] = -1;
861             return null;
862         } else {
863             throw new IllegalArgumentException JavaDoc("unknown text eventType: "+eventType);
864         }
865         // String s = getText();
866
// char[] cb = null;
867
// if(s!= null) {
868
// cb = s.toCharArray();
869
// holderForStartAndLength[0] = 0;
870
// holderForStartAndLength[1] = s.length();
871
// } else {
872
// }
873
// return cb;
874
}
875
876     public String JavaDoc getNamespace()
877     {
878         if(eventType == START_TAG) {
879             //return processNamespaces ? elUri[ depth - 1 ] : NO_NAMESPACE;
880
return processNamespaces ? elUri[ depth ] : NO_NAMESPACE;
881         } else if(eventType == END_TAG) {
882             return processNamespaces ? elUri[ depth ] : NO_NAMESPACE;
883         }
884         return null;
885         // String prefix = elPrefix[ maxDepth ];
886
// if(prefix != null) {
887
// for( int i = namespaceEnd -1; i >= 0; i--) {
888
// if( prefix.equals( namespacePrefix[ i ] ) ) {
889
// return namespaceUri[ i ];
890
// }
891
// }
892
// } else {
893
// for( int i = namespaceEnd -1; i >= 0; i--) {
894
// if( namespacePrefix[ i ] == null ) {
895
// return namespaceUri[ i ];
896
// }
897
// }
898
//
899
// }
900
// return "";
901
}
902
903     public String JavaDoc getName()
904     {
905         if(eventType == START_TAG) {
906             //return elName[ depth - 1 ] ;
907
return elName[ depth ] ;
908         } else if(eventType == END_TAG) {
909             return elName[ depth ] ;
910         } else if(eventType == ENTITY_REF) {
911             if(entityRefName == null) {
912                 entityRefName = newString(buf, posStart, posEnd - posStart);
913             }
914             return entityRefName;
915         } else {
916             return null;
917         }
918     }
919
920     public String JavaDoc getPrefix()
921     {
922         if(eventType == START_TAG) {
923             //return elPrefix[ depth - 1 ] ;
924
return elPrefix[ depth ] ;
925         } else if(eventType == END_TAG) {
926             return elPrefix[ depth ] ;
927         }
928         return null;
929         // if(eventType != START_TAG && eventType != END_TAG) return null;
930
// int maxDepth = eventType == END_TAG ? depth : depth - 1;
931
// return elPrefix[ maxDepth ];
932
}
933
934
935     public boolean isEmptyElementTag() throws XmlPullParserException
936     {
937         if(eventType != START_TAG) throw new XmlPullParserException(
938                 "parser must be on START_TAG to check for empty element", this, null);
939         return emptyElementTag;
940     }
941
942     public int getAttributeCount()
943     {
944         if(eventType != START_TAG) return -1;
945         return attributeCount;
946     }
947
948     public String JavaDoc getAttributeNamespace(int index)
949     {
950         if(eventType != START_TAG) throw new IndexOutOfBoundsException JavaDoc(
951                 "only START_TAG can have attributes");
952         if(processNamespaces == false) return NO_NAMESPACE;
953         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException JavaDoc(
954                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
955         return attributeUri[ index ];
956     }
957
958     public String JavaDoc getAttributeName(int index)
959     {
960         if(eventType != START_TAG) throw new IndexOutOfBoundsException JavaDoc(
961                 "only START_TAG can have attributes");
962         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException JavaDoc(
963                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
964         return attributeName[ index ];
965     }
966
967     public String JavaDoc getAttributePrefix(int index)
968     {
969         if(eventType != START_TAG) throw new IndexOutOfBoundsException JavaDoc(
970                 "only START_TAG can have attributes");
971         if(processNamespaces == false) return null;
972         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException JavaDoc(
973                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
974         return attributePrefix[ index ];
975     }
976
977     public String JavaDoc getAttributeType(int index) {
978         if(eventType != START_TAG) throw new IndexOutOfBoundsException JavaDoc(
979                 "only START_TAG can have attributes");
980         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException JavaDoc(
981                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
982         return "CDATA";
983     }
984
985     public boolean isAttributeDefault(int index) {
986         if(eventType != START_TAG) throw new IndexOutOfBoundsException JavaDoc(
987                 "only START_TAG can have attributes");
988         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException JavaDoc(
989                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
990         return false;
991     }
992
993     public String JavaDoc getAttributeValue(int index)
994     {
995         if(eventType != START_TAG) throw new IndexOutOfBoundsException JavaDoc(
996                 "only START_TAG can have attributes");
997         if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException JavaDoc(
998                 "attribute position must be 0.."+(attributeCount-1)+" and not "+index);
999         return attributeValue[ index ];
1000    }
1001
1002    public String JavaDoc getAttributeValue(String JavaDoc namespace,
1003                                    String JavaDoc name)
1004    {
1005        if(eventType != START_TAG) throw new IndexOutOfBoundsException JavaDoc(
1006                "only START_TAG can have attributes");
1007        if(name == null) {
1008            throw new IllegalArgumentException JavaDoc("attribute name can not be null");
1009        }
1010        // TODO make check if namespace is interned!!! etc. for names!!!
1011
if(processNamespaces) {
1012            for(int i = 0; i < attributeCount; ++i) {
1013                if(namespace == attributeUri[ i ] // taking advantage of String.intern()
1014
&& name.equals(attributeName[i]))
1015                {
1016                    return attributeValue[i];
1017                }
1018            }
1019        } else {
1020            if(namespace != null && namespace.length() == 0) {
1021                namespace = null;
1022            }
1023            if(namespace != null) throw new IllegalArgumentException JavaDoc(
1024                    "when namespaces processing is disabled attribute namespace must be null");
1025            for(int i = 0; i < attributeCount; ++i) {
1026                if(name.equals(attributeName[i]))
1027                {
1028                    return attributeValue[i];
1029                }
1030            }
1031        }
1032        return null;
1033    }
1034
1035
1036    public int getEventType()
1037        throws XmlPullParserException
1038    {
1039        return eventType;
1040    }
1041
1042    public void require(int type, String JavaDoc namespace, String JavaDoc name)
1043        throws XmlPullParserException, IOException JavaDoc
1044    {
1045        if (type != getEventType()
1046            || (namespace != null && !namespace.equals (getNamespace()))
1047            || (name != null && !name.equals (getName ())) )
1048        {
1049            throw new XmlPullParserException (
1050                "expected event "+TYPES[ type ]
1051                    +(name != null ? " with name '"+name+"'" : "")
1052                    +(namespace != null && name != null ? " and" : "")
1053                    +(namespace != null ? " with namespace '"+namespace+"'" : "")
1054                    +" but got"
1055                    +(type != getEventType() ? " "+TYPES[ getEventType() ] : "")
1056                    +(name != null && getName() != null && !name.equals (getName ())
1057                          ? " name '"+getName()+"'" : "")
1058                    +(namespace != null && name != null
1059                          && getName() != null && !name.equals (getName ())
1060                          && getNamespace() != null && !namespace.equals (getNamespace())
1061                          ? " and" : "")
1062                    +(namespace != null && getNamespace() != null && !namespace.equals (getNamespace())
1063                          ? " namespace '"+getNamespace()+"'" : "")
1064                    +(" (postion:"+ getPositionDescription())+")");
1065        }
1066    }
1067
1068    // public String readText() throws XmlPullParserException, IOException
1069
// {
1070
// if (getEventType() != TEXT) return "";
1071
// String result = getText();
1072
// next();
1073
// return result;
1074
// }
1075

1076    public String JavaDoc nextText() throws XmlPullParserException, IOException JavaDoc
1077    {
1078        // String result = null;
1079
// boolean onStartTag = false;
1080
// if(eventType == START_TAG) {
1081
// onStartTag = true;
1082
// next();
1083
// }
1084
// if(eventType == TEXT) {
1085
// result = getText();
1086
// next();
1087
// } else if(onStartTag && eventType == END_TAG) {
1088
// result = "";
1089
// } else {
1090
// throw new XmlPullParserException(
1091
// "parser must be on START_TAG or TEXT to read text", this, null);
1092
// }
1093
// if(eventType != END_TAG) {
1094
// throw new XmlPullParserException(
1095
// "event TEXT it must be immediately followed by END_TAG", this, null);
1096
// }
1097
// return result;
1098
if(getEventType() != START_TAG) {
1099            throw new XmlPullParserException(
1100                "parser must be on START_TAG to read next text", this, null);
1101        }
1102        int eventType = next();
1103        if(eventType == TEXT) {
1104            String JavaDoc result = getText();
1105            eventType = next();
1106            if(eventType != END_TAG) {
1107                throw new XmlPullParserException(
1108                    "TEXT must be immediately followed by END_TAG and not "
1109                        +TYPES[ getEventType() ], this, null);
1110            }
1111            return result;
1112        } else if(eventType == END_TAG) {
1113            return "";
1114        } else {
1115            throw new XmlPullParserException(
1116                "parser must be on START_TAG or TEXT to read text", this, null);
1117        }
1118    }
1119
1120    public int nextTag() throws XmlPullParserException, IOException JavaDoc
1121    {
1122        next();
1123        if(eventType == TEXT && isWhitespace()) { // skip whitespace
1124
next();
1125        }
1126        if (eventType != START_TAG && eventType != END_TAG) {
1127            throw new XmlPullParserException("expected START_TAG or END_TAG not "
1128                                                 +TYPES[ getEventType() ], this, null);
1129        }
1130        return eventType;
1131    }
1132
1133    public int next()
1134        throws XmlPullParserException, IOException JavaDoc
1135    {
1136        tokenize = false;
1137        return nextImpl();
1138    }
1139
1140    public int nextToken()
1141        throws XmlPullParserException, IOException JavaDoc
1142    {
1143        tokenize = true;
1144        return nextImpl();
1145    }
1146
1147
1148    protected int nextImpl()
1149        throws XmlPullParserException, IOException JavaDoc
1150    {
1151        text = null;
1152        pcEnd = pcStart = 0;
1153        usePC = false;
1154        bufStart = posEnd;
1155        if(pastEndTag) {
1156            pastEndTag = false;
1157            --depth;
1158            namespaceEnd = elNamespaceCount[ depth ]; // less namespaces available
1159
}
1160        if(emptyElementTag) {
1161            emptyElementTag = false;
1162            pastEndTag = true;
1163            return eventType = END_TAG;
1164        }
1165
1166        // [1] document ::= prolog element Misc*
1167
if(depth > 0) {
1168
1169            if(seenStartTag) {
1170                seenStartTag = false;
1171                return eventType = parseStartTag();
1172            }
1173            if(seenEndTag) {
1174                seenEndTag = false;
1175                return eventType = parseEndTag();
1176            }
1177
1178            // ASSUMPTION: we are _on_ first character of content or markup!!!!
1179
// [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)*
1180
char ch;
1181            if(seenMarkup) { // we have read ahead ...
1182
seenMarkup = false;
1183                ch = '<';
1184            } else if(seenAmpersand) {
1185                seenAmpersand = false;
1186                ch = '&';
1187            } else {
1188                ch = more();
1189            }
1190            posStart = pos - 1; // VERY IMPORTANT: this is correct start of event!!!
1191

1192            // when true there is some potential event TEXT to return - keep gathering
1193
boolean hadCharData = false;
1194
1195            // when true TEXT data is not continous (like <![CDATA[text]]>) and requires PC merging
1196
boolean needsMerging = false;
1197
1198            MAIN_LOOP:
1199            while(true) {
1200                // work on MARKUP
1201
if(ch == '<') {
1202                    if(hadCharData) {
1203                        //posEnd = pos - 1;
1204
if(tokenize) {
1205                            seenMarkup = true;
1206                            return eventType = TEXT;
1207                        }
1208                    }
1209                    ch = more();
1210                    if(ch == '/') {
1211                        if(!tokenize && hadCharData) {
1212                            seenEndTag = true;
1213                            //posEnd = pos - 2;
1214
return eventType = TEXT;
1215                        }
1216                        return eventType = parseEndTag();
1217                    } else if(ch == '!') {
1218                        ch = more();
1219                        if(ch == '-') {
1220                            // note: if(tokenize == false) posStart/End is NOT changed!!!!
1221
parseComment();
1222                            if(tokenize) return eventType = COMMENT;
1223                            if( !usePC && hadCharData ) needsMerging = true;
1224                        } else if(ch == '[') {
1225                            //posEnd = pos - 3;
1226
// must remeber previous posStart/End as it merges with content of CDATA
1227
//int oldStart = posStart + bufAbsoluteStart;
1228
//int oldEnd = posEnd + bufAbsoluteStart;
1229
parseCDSect(hadCharData);
1230                            if(tokenize) return eventType = CDSECT;
1231                            int cdStart = posStart;
1232                            int cdEnd = posEnd;
1233                            int cdLen = cdEnd - cdStart;
1234
1235
1236                            if(cdLen > 0) { // was there anything inside CDATA section?
1237
if(!usePC) {
1238                                    hadCharData = true;
1239                                    needsMerging = true;
1240                                }
1241                            }
1242
1243                            // posStart = oldStart;
1244
// posEnd = oldEnd;
1245
// if(cdLen > 0) { // was there anything inside CDATA section?
1246
// if(hadCharData) {
1247
// // do merging if there was anything in CDSect!!!!
1248
// // if(!usePC) {
1249
// // // posEnd is correct already!!!
1250
// // if(posEnd > posStart) {
1251
// // joinPC();
1252
// // } else {
1253
// // usePC = true;
1254
// // pcStart = pcEnd = 0;
1255
// // }
1256
// // }
1257
// // if(pcEnd + cdLen >= pc.length) ensurePC(pcEnd + cdLen);
1258
// // // copy [cdStart..cdEnd) into PC
1259
// // System.arraycopy(buf, cdStart, pc, pcEnd, cdLen);
1260
// // pcEnd += cdLen;
1261
// if(!usePC) {
1262
// needsMerging = true;
1263
// posStart = cdStart;
1264
// posEnd = cdEnd;
1265
// }
1266
// } else {
1267
// if(!usePC) {
1268
// needsMerging = true;
1269
// posStart = cdStart;
1270
// posEnd = cdEnd;
1271
// hadCharData = true;
1272
// }
1273
// }
1274
// //hadCharData = true;
1275
// } else {
1276
// if( !usePC && hadCharData ) {
1277
// needsMerging = true;
1278
// }
1279
// }
1280
} else {
1281                            throw new XmlPullParserException(
1282                                "unexpected character in markup "+printable(ch), this, null);
1283                        }
1284                    } else if(ch == '?') {
1285                        parsePI();
1286                        if(tokenize) return eventType = PROCESSING_INSTRUCTION;
1287                        if( !usePC && hadCharData ) needsMerging = true;
1288                    } else if( isNameStartChar(ch) ) {
1289                        if(!tokenize && hadCharData) {
1290                            seenStartTag = true;
1291                            //posEnd = pos - 2;
1292
return eventType = TEXT;
1293                        }
1294                        return eventType = parseStartTag();
1295                    } else {
1296                        throw new XmlPullParserException(
1297                            "unexpected character in markup "+printable(ch), this, null);
1298                    }
1299                    // do content comapctation if it makes sense!!!!
1300

1301                } else if(ch == '&') {
1302                    // work on ENTITTY
1303
//posEnd = pos - 1;
1304
if(tokenize && hadCharData) {
1305                        seenAmpersand = true;
1306                        return eventType = TEXT;
1307                    }
1308                    int oldStart = posStart + bufAbsoluteStart;
1309                    int oldEnd = posEnd + + bufAbsoluteStart;
1310                    char[] resolvedEntity = parseEntityRef();
1311                    if(tokenize) return eventType = ENTITY_REF;
1312                    // check if replacement text can be resolved !!!
1313
if(resolvedEntity == null) {
1314                        if(entityRefName == null) {
1315                            entityRefName = newString(buf, posStart, posEnd - posStart);
1316                        }
1317                        throw new XmlPullParserException(
1318                            "could not resolve entity named '"+printable(entityRefName)+"'",
1319                            this, null);
1320                    }
1321                    //int entStart = posStart;
1322
//int entEnd = posEnd;
1323
posStart = oldStart - bufAbsoluteStart;
1324                    posEnd = oldEnd - bufAbsoluteStart;
1325                    if(!usePC) {
1326                        if(hadCharData) {
1327                            joinPC(); // posEnd is already set correctly!!!
1328
needsMerging = false;
1329                        } else {
1330                            usePC = true;
1331                            pcStart = pcEnd = 0;
1332                        }
1333                    }
1334                    //assert usePC == true;
1335
// write into PC replacement text - do merge for replacement text!!!!
1336
for (int i = 0; i < resolvedEntity.length; i++)
1337                    {
1338                        if(pcEnd >= pc.length) ensurePC(pcEnd);
1339                        pc[pcEnd++] = resolvedEntity[ i ];
1340
1341                    }
1342                    //assert needsMerging == false;
1343
} else {
1344
1345                    if(needsMerging) {
1346                        //assert usePC == false;
1347
joinPC(); // posEnd is already set correctly!!!
1348
//posStart = pos - 1;
1349
needsMerging = false;
1350                    }
1351
1352
1353                    //no MARKUP not ENTITIES so work on character data ...
1354

1355
1356
1357                    // [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
1358

1359
1360                    hadCharData = true;
1361
1362                    boolean normalizedCR = false;
1363                    boolean normalizeInput = tokenize == false || roundtripSupported == false;
1364                    // use loop locality here!!!!
1365
do {
1366
1367                        // TODO: check that ]]> does not show in
1368
//if(ch == ']')
1369
// seenTwoBrackets = false;
1370
//if(seenBracket && ch == ']')
1371
// seenTwoBracket = true;
1372
//if(seenTwoBarckets && ch == '>')
1373
// throw new XmlPullParserException("characters ]]> are not allowed in content", this, null);
1374
// else seenBracket = false;
1375
if(normalizeInput) {
1376                            // deal with normalization issues ...
1377
if(ch == '\r') {
1378                                normalizedCR = true;
1379                                posEnd = pos -1;
1380                                // posEnd is alreadys set
1381
if(!usePC) {
1382                                    if(posEnd > posStart) {
1383                                        joinPC();
1384                                    } else {
1385                                        usePC = true;
1386                                        pcStart = pcEnd = 0;
1387                                    }
1388                                }
1389                                //assert usePC == true;
1390
if(pcEnd >= pc.length) ensurePC(pcEnd);
1391                                pc[pcEnd++] = '\n';
1392                            } else if(ch == '\n') {
1393                                // if(!usePC) { joinPC(); } else { if(pcEnd >= pc.length) ensurePC(); }
1394
if(!normalizedCR && usePC) {
1395                                    if(pcEnd >= pc.length) ensurePC(pcEnd);
1396                                    pc[pcEnd++] = '\n';
1397                                }
1398                                normalizedCR = false;
1399                            } else {
1400                                if(usePC) {
1401                                    if(pcEnd >= pc.length) ensurePC(pcEnd);
1402                                    pc[pcEnd++] = ch;
1403                                }
1404                                normalizedCR = false;
1405                            }
1406                        }
1407                        ch = more();
1408                    } while(ch != '<' && ch != '&');
1409                    posEnd = pos - 1;
1410                    continue MAIN_LOOP; // skip ch = more() from below - we are alreayd ahead ...
1411
}
1412                ch = more();
1413            } // endless while(true)
1414
} else {
1415            if(seenRoot) {
1416                return parseEpilog();
1417            } else {
1418                return parseProlog();
1419            }
1420        }
1421    }
1422
1423
1424    protected int parseProlog()
1425        throws XmlPullParserException, IOException JavaDoc
1426    {
1427        // [2] prolog: ::= XMLDecl? Misc* (doctypedecl Misc*)? and look for [39] element
1428

1429        char ch;
1430        if(seenMarkup) {
1431            ch = buf[ pos - 1 ];
1432        } else {
1433            ch = more();
1434        }
1435
1436        if(eventType == START_DOCUMENT) {
1437            // bootstrap parsing with getting first character input!
1438
// deal with BOM
1439
// detect BOM and frop it (Unicode int Order Mark)
1440
if(ch == '\uFFFE') {
1441                throw new XmlPullParserException(
1442                    "first character in input was UNICODE noncharacter (0xFFFE)"+
1443                        "- input requires int swapping", this, null);
1444            }
1445            if(ch == '\uFEFF') {
1446                // skipping UNICODE int Order Mark (so called BOM)
1447
ch = more();
1448            }
1449        }
1450        seenMarkup = false;
1451        boolean gotS = false;
1452        posStart = pos - 1;
1453        boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false;
1454        boolean normalizedCR = false;
1455        while(true) {
1456            // deal with Misc
1457
// [27] Misc ::= Comment | PI | S
1458
// deal with docdecl --> mark it!
1459
// else parseStartTag seen <[^/]
1460
if(ch == '<') {
1461                if(gotS && tokenize) {
1462                    posEnd = pos - 1;
1463                    seenMarkup = true;
1464                    return eventType = IGNORABLE_WHITESPACE;
1465                }
1466                ch = more();
1467                if(ch == '?') {
1468                    // check if it is 'xml'
1469
// deal with XMLDecl
1470
if(parsePI()) { // make sure to skip XMLDecl
1471
if(tokenize) {
1472                            return eventType = PROCESSING_INSTRUCTION;
1473                        }
1474                    } else {
1475                        // skip over - continue tokenizing
1476
posStart = pos;
1477                        gotS = false;
1478                    }
1479
1480                } else if(ch == '!') {
1481                    ch = more();
1482                    if(ch == 'D') {
1483                        if(seenDocdecl) {
1484                            throw new XmlPullParserException(
1485                                "only one docdecl allowed in XML document", this, null);
1486                        }
1487                        seenDocdecl = true;
1488                        parseDocdecl();
1489                        if(tokenize) return eventType = DOCDECL;
1490                    } else if(ch == '-') {
1491                        parseComment();
1492                        if(tokenize) return eventType = COMMENT;
1493                    } else {
1494                        throw new XmlPullParserException(
1495                            "unexpected markup <!"+printable(ch), this, null);
1496                    }
1497                } else if(ch == '/') {
1498                    throw new XmlPullParserException(
1499                        "expected start tag name and not "+printable(ch), this, null);
1500                } else if(isNameStartChar(ch)) {
1501                    seenRoot = true;
1502                    return parseStartTag();
1503                } else {
1504                    throw new XmlPullParserException(
1505                        "expected start tag name and not "+printable(ch), this, null);
1506                }
1507            } else if(isS(ch)) {
1508                gotS = true;
1509                if(normalizeIgnorableWS) {
1510                    if(ch == '\r') {
1511                        normalizedCR = true;
1512                        //posEnd = pos -1;
1513
//joinPC();
1514
// posEnd is alreadys set
1515
if(!usePC) {
1516                            posEnd = pos -1;
1517                            if(posEnd > posStart) {
1518                                joinPC();
1519                            } else {
1520                                usePC = true;
1521                                pcStart = pcEnd = 0;
1522                            }
1523                        }
1524                        //assert usePC == true;
1525
if(pcEnd >= pc.length) ensurePC(pcEnd);
1526                        pc[pcEnd++] = '\n';
1527                    } else if(ch == '\n') {
1528                        if(!normalizedCR && usePC) {
1529                            if(pcEnd >= pc.length) ensurePC(pcEnd);
1530                            pc[pcEnd++] = '\n';
1531                        }
1532                        normalizedCR = false;
1533                    } else {
1534                        if(usePC) {
1535                            if(pcEnd >= pc.length) ensurePC(pcEnd);
1536                            pc[pcEnd++] = ch;
1537                        }
1538                        normalizedCR = false;
1539                    }
1540                }
1541            } else {
1542                throw new XmlPullParserException(
1543                    "only whitespace content allowed before start tag and not "+printable(ch),
1544                    this, null);
1545            }
1546            ch = more();
1547        }
1548    }
1549
1550    protected int parseEpilog()
1551        throws XmlPullParserException, IOException JavaDoc
1552    {
1553        if(eventType == END_DOCUMENT) {
1554            throw new XmlPullParserException("already reached end document", this, null);
1555        }
1556        if(reachedEnd) {
1557            return eventType = END_DOCUMENT;
1558        }
1559        boolean gotS = false;
1560        boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false;
1561        boolean normalizedCR = false;
1562        try {
1563            // epilog: Misc*
1564
char ch;
1565            if(seenMarkup) {
1566                ch = buf[ pos - 1 ];
1567            } else {
1568                ch = more();
1569            }
1570            seenMarkup = false;
1571            posStart = pos - 1;
1572            while(true) {
1573                // deal with Misc
1574
// [27] Misc ::= Comment | PI | S
1575
if(ch == '<') {
1576                    if(gotS && tokenize) {
1577                        posEnd = pos - 1;
1578                        seenMarkup = true;
1579                        return eventType = IGNORABLE_WHITESPACE;
1580                    }
1581                    ch = more();
1582                    if(ch == '?') {
1583                        // check if it is 'xml'
1584
// deal with XMLDecl
1585
parsePI();
1586                        if(tokenize) return eventType = PROCESSING_INSTRUCTION;
1587
1588                    } else if(ch == '!') {
1589                        ch = more();
1590                        if(ch == 'D') {
1591                            parseDocdecl(); //FIXME
1592
if(tokenize) return eventType = DOCDECL;
1593                        } else if(ch == '-') {
1594                            parseComment();
1595                            if(tokenize) return eventType = COMMENT;
1596                        } else {
1597                            throw new XmlPullParserException(
1598                                "unexpected markup <!"+printable(ch), this, null);
1599                        }
1600                    } else if(ch == '/') {
1601                        throw new XmlPullParserException(
1602                            "end tag not allowed in epilog but got "+printable(ch), this, null);
1603                    } else if(isNameStartChar(ch)) {
1604                        throw new XmlPullParserException(
1605                            "start tag not allowed in epilog but got "+printable(ch), this, null);
1606                    } else {
1607                        throw new XmlPullParserException(
1608                            "in epilog expected ignorable content and not "+printable(ch),
1609                            this, null);
1610                    }
1611                } else if(isS(ch)) {
1612                    gotS = true;
1613                    if(normalizeIgnorableWS) {
1614                        if(ch == '\r') {
1615                            normalizedCR = true;
1616                            //posEnd = pos -1;
1617
//joinPC();
1618
// posEnd is alreadys set
1619
if(!usePC) {
1620                                posEnd = pos -1;
1621                                if(posEnd > posStart) {
1622                                    joinPC();
1623                                } else {
1624                                    usePC = true;
1625                                    pcStart = pcEnd = 0;
1626                                }
1627                            }
1628                            //assert usePC == true;
1629
if(pcEnd >= pc.length) ensurePC(pcEnd);
1630                            pc[pcEnd++] = '\n';
1631                        } else if(ch == '\n') {
1632                            if(!normalizedCR && usePC) {
1633                                if(pcEnd >= pc.length) ensurePC(pcEnd);
1634                                pc[pcEnd++] = '\n';
1635                            }
1636                            normalizedCR = false;
1637                        } else {
1638                            if(usePC) {
1639                                if(pcEnd >= pc.length) ensurePC(pcEnd);
1640                                pc[pcEnd++] = ch;
1641                            }
1642                            normalizedCR = false;
1643                        }
1644                    }
1645                } else {
1646                    throw new XmlPullParserException(
1647                        "in epilog non whitespace content is not allowed but got "+printable(ch),
1648                        this, null);
1649                }
1650                ch = more();
1651            }
1652
1653            // throw Exceptin("unexpected content in epilog
1654
// cach EOFException return END_DOCUEMENT
1655
//try {
1656
} catch(EOFException JavaDoc ex) {
1657            reachedEnd = true;
1658            if(tokenize && gotS) {
1659                posEnd = pos; // well - this is LAST available character pos
1660
return eventType = IGNORABLE_WHITESPACE;
1661            }
1662            return eventType = END_DOCUMENT;
1663        }
1664    }
1665
1666
1667    public int parseEndTag() throws XmlPullParserException, IOException JavaDoc {
1668        //ASSUMPTION ch is past "</"
1669
// [42] ETag ::= '</' Name S? '>'
1670
char ch = more();
1671        if(!isNameStartChar(ch)) {
1672            throw new XmlPullParserException(
1673                "expected name start and not "+printable(ch), this, null);
1674        }
1675        posStart = pos - 3;
1676        int nameStart = pos - 1 + bufAbsoluteStart;
1677        do {
1678            ch = more();
1679        } while(isNameChar(ch));
1680
1681        // now we go one level down -- do checks
1682
//--depth; //FIXME
1683

1684        // check that end tag name is the same as start tag
1685
//String name = new String(buf, nameStart - bufAbsoluteStart,
1686
// (pos - 1) - (nameStart - bufAbsoluteStart));
1687
int last = pos - 1;
1688        int off = nameStart - bufAbsoluteStart;
1689        int len = last - off;
1690        char[] cbuf = elRawName[depth];
1691        if(elRawNameEnd[depth] != len) {
1692            // construct strings for exception
1693
String JavaDoc startname = new String JavaDoc(cbuf, 0, elRawNameEnd[depth]);
1694            String JavaDoc endname = new String JavaDoc(buf, off, len);
1695            throw new XmlPullParserException(
1696                "end tag name '"+endname+"' must match start tag name '"+startname+"'",
1697                this, null);
1698        }
1699        for (int i = 0; i < len; i++)
1700        {
1701            if(buf[off++] != cbuf[i]) {
1702                // construct strings for exception
1703
String JavaDoc startname = new String JavaDoc(cbuf, 0, len);
1704                String JavaDoc endname = new String JavaDoc(buf, off - i - 1, len);
1705                throw new XmlPullParserException(
1706                    "end tag name '"+endname+"' must be the same as start tag '"+startname+"'",
1707                    this, null);
1708            }
1709        }
1710
1711        while(isS(ch)) { ch = more(); } // skip additional white spaces
1712
if(ch != '>') throw new XmlPullParserException(
1713                "expected > to finsh end tag not "+printable(ch), this, null);
1714
1715
1716
1717        //namespaceEnd = elNamespaceCount[ depth ]; //FIXME
1718

1719        posEnd = pos;
1720        pastEndTag = true;
1721        return eventType = END_TAG;
1722    }
1723
1724    public int parseStartTag() throws XmlPullParserException, IOException JavaDoc {
1725        //ASSUMPTION ch is past <T
1726
// [40] STag ::= '<' Name (S Attribute)* S? '>'
1727
// [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
1728
++depth; //FIXME
1729

1730        posStart = pos - 2;
1731
1732        emptyElementTag = false;
1733        attributeCount = 0;
1734        // retrieve name
1735
int nameStart = pos - 1 + bufAbsoluteStart;
1736        int colonPos = -1;
1737        char ch = buf[ pos - 1];
1738        if(ch == ':' && processNamespaces) throw new XmlPullParserException(
1739                "when namespaces processing enabled colon can not be at element name start",
1740                this, null);
1741        while(true) {
1742            ch = more();
1743            if(!isNameChar(ch)) break;
1744            if(ch == ':' && processNamespaces) {
1745                if(colonPos != -1) throw new XmlPullParserException(
1746                        "only one colon is allowed in name of element when namespaces are enabled",
1747                        this, null);
1748                colonPos = pos - 1 + bufAbsoluteStart;
1749            }
1750        }
1751
1752        // retrieve name
1753
ensureElementsCapacity();
1754
1755
1756        //TODO check for efficient interning and then use elRawNameInterned!!!!
1757

1758        int elLen = (pos - 1) - (nameStart - bufAbsoluteStart);
1759        if(elRawName[ depth ] == null || elRawName[ depth ].length < elLen) {
1760            elRawName[ depth ] = new char[ 2 * elLen ];
1761        }
1762        System.arraycopy(buf, nameStart - bufAbsoluteStart, elRawName[ depth ], 0, elLen);
1763        elRawNameEnd[ depth ] = elLen;
1764
1765        String JavaDoc name = null;
1766
1767        // work on prefixes and namespace URI
1768
String JavaDoc prefix = null;
1769        if(processNamespaces) {
1770            if(colonPos != -1) {
1771                prefix = elPrefix[ depth ] = newString(buf, nameStart - bufAbsoluteStart,
1772                                                       colonPos - nameStart);
1773                name = elName[ depth ] = newString(buf, colonPos + 1 - bufAbsoluteStart,
1774                                                   //(pos -1) - (colonPos + 1));
1775
pos - 2 - (colonPos - bufAbsoluteStart));
1776            } else {
1777                prefix = elPrefix[ depth ] = null;
1778                name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen);
1779            }
1780        } else {
1781
1782            name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen);
1783
1784        }
1785
1786
1787        while(true) {
1788
1789            while(isS(ch)) { ch = more(); } // skip additional white spaces
1790

1791            if(ch == '>') {
1792                break;
1793            } else if(ch == '/') {
1794                if(emptyElementTag) throw new XmlPullParserException(
1795                        "repeated / in tag declaration", this, null);
1796                emptyElementTag = true;
1797                ch = more();
1798                if(ch != '>') throw new XmlPullParserException(
1799                        "expected > to end empty tag not "+printable(ch), this, null);
1800                break;
1801            } else if(isNameStartChar(ch)) {
1802                ch = parseAttribute();
1803                ch = more();
1804                continue;
1805            } else {
1806                throw new XmlPullParserException(
1807                    "start tag unexpected character "+printable(ch), this, null);
1808            }
1809            //ch = more(); // skip space
1810
}
1811
1812        // now when namespaces were declared we can resolve them
1813
if(processNamespaces) {
1814            String JavaDoc uri = getNamespace(prefix);
1815            if(uri == null) {
1816                if(prefix == null) { // no prefix and no uri => use default namespace
1817
uri = NO_NAMESPACE;
1818                } else {
1819                    throw new XmlPullParserException(
1820                        "could not determine namespace bound to element prefix "+prefix,
1821                        this, null);
1822                }
1823
1824            }
1825            elUri[ depth ] = uri;
1826
1827
1828            //String uri = getNamespace(prefix);
1829
//if(uri == null && prefix == null) { // no prefix and no uri => use default namespace
1830
// uri = "";
1831
//}
1832
// resolve attribute namespaces
1833
for (int i = 0; i < attributeCount; i++)
1834            {
1835                String JavaDoc attrPrefix = attributePrefix[ i ];
1836                if(attrPrefix != null) {
1837                    String JavaDoc attrUri = getNamespace(attrPrefix);
1838                    if(attrUri == null) {
1839                        throw new XmlPullParserException(
1840                            "could not determine namespace bound to attribute prefix "+attrPrefix,
1841                            this, null);
1842
1843                    }
1844                    attributeUri[ i ] = attrUri;
1845                } else {
1846                    attributeUri[ i ] = NO_NAMESPACE;
1847                }
1848            }
1849
1850            //TODO
1851
//[ WFC: Unique Att Spec ]
1852
// check namespaced attribute uniqueness contraint!!!
1853

1854            for (int i = 1; i < attributeCount; i++)
1855            {
1856                for (int j = 0; j < i; j++)
1857                {
1858                    if( attributeUri[j] == attributeUri[i]
1859                       && (allStringsInterned && attributeName[j].equals(attributeName[i])
1860                               || (!allStringsInterned
1861                                       && attributeNameHash[ j ] == attributeNameHash[ i ]
1862                                       && attributeName[j].equals(attributeName[i])) )
1863
1864                      ) {
1865                        // prepare data for nice error messgae?
1866
String JavaDoc attr1 = attributeName[j];
1867                        if(attributeUri[j] != null) attr1 = attributeUri[j]+":"+attr1;
1868                        String JavaDoc attr2 = attributeName[i];
1869                        if(attributeUri[i] != null) attr2 = attributeUri[i]+":"+attr2;
1870                        throw new XmlPullParserException(
1871                            "duplicated attributes "+attr1+" and "+attr2, this, null);
1872                    }
1873                }
1874            }
1875
1876
1877        } else { // ! processNamespaces
1878

1879            //[ WFC: Unique Att Spec ]
1880
// check raw attribute uniqueness contraint!!!
1881
for (int i = 1; i < attributeCount; i++)
1882            {
1883                for (int j = 0; j < i; j++)
1884                {
1885                    if((allStringsInterned && attributeName[j].equals(attributeName[i])
1886                            || (!allStringsInterned
1887                                    && attributeNameHash[ j ] == attributeNameHash[ i ]
1888                                    && attributeName[j].equals(attributeName[i])) )
1889
1890                      ) {
1891                        // prepare data for nice error messgae?
1892
String JavaDoc attr1 = attributeName[j];
1893                        String JavaDoc attr2 = attributeName[i];
1894                        throw new XmlPullParserException(
1895                            "duplicated attributes "+attr1+" and "+attr2, this, null);
1896                    }
1897                }
1898            }
1899        }
1900
1901        elNamespaceCount[ depth ] = namespaceEnd;
1902        posEnd = pos;
1903        return eventType = START_TAG;
1904    }
1905
1906    protected char parseAttribute() throws XmlPullParserException, IOException JavaDoc
1907    {
1908        // parse attribute
1909
// [41] Attribute ::= Name Eq AttValue
1910
// [WFC: No External Entity References]
1911
// [WFC: No < in Attribute Values]
1912
int prevPosStart = posStart + bufAbsoluteStart;
1913        int nameStart = pos - 1 + bufAbsoluteStart;
1914        int colonPos = -1;
1915        char ch = buf[ pos - 1 ];
1916        if(ch == ':' && processNamespaces) throw new XmlPullParserException(
1917                "when namespaces processing enabled colon can not be at attribute name start",
1918                this, null);
1919
1920
1921        boolean startsWithXmlns = processNamespaces && ch == 'x';
1922        int xmlnsPos = 0;
1923
1924        ch = more();
1925        while(isNameChar(ch)) {
1926            if(processNamespaces) {
1927                if(startsWithXmlns && xmlnsPos < 5) {
1928                    ++xmlnsPos;
1929                    if(xmlnsPos == 1) { if(ch != 'm') startsWithXmlns = false; }
1930                    else if(xmlnsPos == 2) { if(ch != 'l') startsWithXmlns = false; }
1931                    else if(xmlnsPos == 3) { if(ch != 'n') startsWithXmlns = false; }
1932                    else if(xmlnsPos == 4) { if(ch != 's') startsWithXmlns = false; }
1933                    else if(xmlnsPos == 5) {
1934                        if(ch != ':') throw new XmlPullParserException(
1935                                "after xmlns in attribute name must be colon"
1936                                    +"when namespaces are enabled", this, null);
1937                        //colonPos = pos - 1 + bufAbsoluteStart;
1938
}
1939                }
1940                if(ch == ':') {
1941                    if(colonPos != -1) throw new XmlPullParserException(
1942                            "only one colon is allowed in attribute name"
1943                                +" when namespaces are enabled", this, null);
1944                    colonPos = pos - 1 + bufAbsoluteStart;
1945                }
1946            }
1947            ch = more();
1948        }
1949
1950        ensureAttributesCapacity(attributeCount);
1951
1952        // --- start processing attributes
1953
String JavaDoc name = null;
1954        String JavaDoc prefix = null;
1955        // work on prefixes and namespace URI
1956
if(processNamespaces) {
1957            if(xmlnsPos < 4) startsWithXmlns = false;
1958            if(startsWithXmlns) {
1959                if(colonPos != -1) {
1960                    //prefix = attributePrefix[ attributeCount ] = null;
1961
name = //attributeName[ attributeCount ] =
1962
newString(buf, colonPos - bufAbsoluteStart + 1,
1963                                  //pos - 1 - (colonPos + 1 - bufAbsoluteStart)
1964
pos - 2 - (colonPos - bufAbsoluteStart)
1965                                 );
1966                }
1967            } else {
1968                if(colonPos != -1) {
1969                    prefix = attributePrefix[ attributeCount ] =
1970                        newString(buf, nameStart - bufAbsoluteStart,
1971                                  //colonPos - (nameStart - bufAbsoluteStart));
1972
colonPos - nameStart);
1973                    name = attributeName[ attributeCount ] =
1974                        newString(buf, colonPos - bufAbsoluteStart + 1,
1975                                  //pos - 1 - (colonPos + 1 - bufAbsoluteStart));
1976
pos - 2 - (colonPos - bufAbsoluteStart));
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
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                    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                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 (int i = 0; i < resolvedEntity.length; i++)
2057                {
2058                    if(pcEnd >= pc.length) ensurePC(pcEnd);
2059                    pc[pcEnd++] = resolvedEntity[ i ];
2060                }
2061            } else if(ch == '\t' || ch == '\n' || ch == '\r') {
2062                // do attribute value normalization
2063
// as described in http://www.w3.org/TR/REC-xml#AVNormalize
2064
// TODO add test for it form spec ...
2065
// handle EOL normalization ...
2066
if(!usePC) {
2067                    posEnd = pos - 1;
2068                    if(posEnd > posStart) {
2069                        joinPC();
2070                    } else {
2071                        usePC = true;
2072                        pcEnd = pcStart = 0;
2073                    }
2074                }
2075                //assert usePC == true;
2076
if(pcEnd >= pc.length) ensurePC(pcEnd);
2077                if(ch != '\n' || !normalizedCR) {
2078                    pc[pcEnd++] = ' '; //'\n';
2079
}
2080
2081            } else {
2082                if(usePC) {
2083                    if(pcEnd >= pc.length) ensurePC(pcEnd);
2084                    pc[pcEnd++] = ch;
2085                }
2086            }
2087            normalizedCR = ch == '\r';
2088        }
2089
2090
2091        if(processNamespaces && startsWithXmlns) {
2092            String JavaDoc ns = null;
2093            if(!usePC) {
2094                ns = newStringIntern(buf, posStart, pos - 1 - posStart);
2095            } else {
2096                ns = newStringIntern(pc, pcStart, pcEnd - pcStart);
2097            }
2098            ensureNamespacesCapacity(namespaceEnd);
2099            int prefixHash = -1;
2100            if(colonPos != -1) {
2101                if(ns.length() == 0) {
2102                    throw new XmlPullParserException(
2103                        "non-default namespace can not be declared to be empty string", this, null);
2104                }
2105                // declare new namespace
2106
namespacePrefix[ namespaceEnd ] = name;
2107                if(!allStringsInterned) {
2108                    prefixHash = namespacePrefixHash[ namespaceEnd ] = name.hashCode();
2109                }
2110            } else {
2111                // declare new default namespace ...
2112
namespacePrefix[ namespaceEnd ] = null;
2113                if(!allStringsInterned) {
2114                    prefixHash = namespacePrefixHash[ namespaceEnd ] = -1;
2115                }
2116            }
2117            namespaceUri[ namespaceEnd ] = ns;
2118
2119            // detect duplicate namespace declarations!!!
2120
int startNs = elNamespaceCount[ depth - 1 ];
2121            for (int i = namespaceEnd - 1; i >= startNs; --i)
2122            {
2123                if(((allStringsInterned || name == null) && namespacePrefix[ i ] == name)
2124                   || (!allStringsInterned && name != null &&
2125                           namespacePrefixHash[ i ] == prefixHash
2126                           && name.equals(namespacePrefix[ i ])
2127                      ))
2128                {
2129                    String JavaDoc s = name == null ? "default" : "'"+name+"'";
2130                    throw new XmlPullParserException(
2131                        "duplicated namespace declaration for "+s+" prefix", this, null);
2132                }
2133            }
2134
2135            ++namespaceEnd;
2136
2137        } else {
2138            if(!usePC) {
2139                attributeValue[ attributeCount ] =
2140                    new String JavaDoc(buf, posStart, pos - 1 - posStart);
2141            } else {
2142                attributeValue[ attributeCount ] =
2143                    new String JavaDoc(pc, pcStart, pcEnd - pcStart);
2144            }
2145            ++attributeCount;
2146        }
2147        posStart = prevPosStart - bufAbsoluteStart;
2148        return ch;
2149    }
2150
2151    protected char[] charRefOneCharBuf = new char[1];
2152
2153    protected char[] parseEntityRef()
2154        throws XmlPullParserException, IOException JavaDoc
2155    {
2156        // ASSUMPTION just after &
2157
entityRefName = null;
2158        posStart = pos;
2159        char ch = more();
2160        if(ch == '#') {
2161            // parse character reference
2162
char charRef = 0;
2163            ch = more();
2164            if(ch == 'x') {
2165                //encoded in hex
2166
while(true) {
2167                    ch = more();
2168                    if(ch >= '0' && ch <= '9') {
2169                        charRef = (char)(charRef * 16 + (ch - '0'));
2170                    } else if(ch >= 'a' && ch <= 'f') {
2171                        charRef = (char)(charRef * 16 + (ch - ('a' - 10)));
2172                    } else if(ch >= 'A' && ch <= 'F') {
2173                        charRef = (char)(charRef * 16 + (ch - ('A' - 10)));
2174                    } else if(ch == ';') {
2175                        break;
2176                    } else {
2177                        throw new XmlPullParserException(
2178                            "character reference (with hex value) may not contain "
2179                                +printable(ch), this, null);
2180                    }
2181                }
2182            } else {
2183                // encoded in decimal
2184
while(true) {
2185                    if(ch >= '0' && ch <= '9') {
2186                        charRef = (char)(charRef * 10 + (ch - '0'));
2187                    } else if(ch == ';') {
2188                        break;
2189                    } else {
2190                        throw new XmlPullParserException(
2191                            "character reference (with decimal value) may not contain "
2192                                +printable(ch), this, null);
2193                    }
2194                    ch = more();
2195                }
2196            }
2197            posEnd = pos - 1;
2198            charRefOneCharBuf[0] = charRef;
2199            if(tokenize) {
2200                text = newString(charRefOneCharBuf, 0, 1);
2201            }
2202            return charRefOneCharBuf;
2203        } else {
2204            // name reference
2205

2206            // scan until ;
2207
do{ ch = more(); } while(ch != ';');
2208            posEnd = pos - 1;
2209            // determine what name maps to
2210
int len = posEnd - posStart;
2211            if(len == 2 && buf[posStart] == 'l' && buf[posStart+1] == 't') {
2212                if(tokenize) {
2213                    text = "<";
2214                }
2215                charRefOneCharBuf[0] = '<';
2216                return charRefOneCharBuf;
2217                //if(paramPC || isParserTokenizing) {
2218
// if(pcEnd >= pc.length) ensurePC();
2219
// pc[pcEnd++] = '<';
2220
//}
2221
} else if(len == 3 && buf[posStart] == 'a'
2222                      && buf[posStart+1] == 'm' && buf[posStart+2] == 'p') {
2223                if(tokenize) {
2224                    text = "&";
2225                }
2226                charRefOneCharBuf[0] = '&';
2227                return charRefOneCharBuf;
2228            } else if(len == 2 && buf[posStart] == 'g' && buf[posStart+1] == 't') {
2229                if(tokenize) {
2230                    text = ">";
2231                }
2232                charRefOneCharBuf[0] = '>';
2233                return charRefOneCharBuf;
2234            } else if(len == 4 && buf[posStart] == 'a' && buf[posStart+1] == 'p'
2235                      && buf[posStart+2] == 'o' && buf[posStart+3] == 's')
2236            {
2237                if(tokenize) {
2238                    text = "'";
2239                }
2240                charRefOneCharBuf[0] = '\'';
2241                return charRefOneCharBuf;
2242            } else if(len == 4 && buf[posStart] == 'q' && buf[posStart+1] == 'u'
2243                      && buf[posStart+2] == 'o' && buf[posStart+3] == 't')
2244            {
2245                if(tokenize) {
2246                    text = "\"";
2247                }
2248                charRefOneCharBuf[0] = '"';
2249                return charRefOneCharBuf;
2250            } else {
2251                char[] result = lookuEntityReplacement(len);
2252                if(result != null) {
2253                    return result;
2254                }
2255            }
2256            if(tokenize) text = null;
2257            return null;
2258        }
2259    }
2260
2261    protected char[] lookuEntityReplacement(int entitNameLen)
2262        throws XmlPullParserException, IOException JavaDoc
2263
2264    {
2265        if(!allStringsInterned) {
2266            int hash = fastHash(buf, posStart, posEnd - posStart);
2267            LOOP:
2268            for (int i = entityEnd - 1; i >= 0; --i)
2269            {
2270                if(hash == entityNameHash[ i ] && entitNameLen == entityNameBuf[ i ].length) {
2271                    char[] entityBuf = entityNameBuf[ i ];
2272                    for (int j = 0; j < entitNameLen; j++)
2273                    {
2274                        if(buf[posStart + j] != entityBuf[j]) continue LOOP;
2275                    }
2276                    if(tokenize) text = entityReplacement[ i ];
2277                    return entityReplacementBuf[ i ];
2278                }
2279            }
2280        } else {
2281            entityRefName = newString(buf, posStart, posEnd - posStart);
2282            for (int i = entityEnd - 1; i >= 0; --i)
2283            {
2284                // take advantage that interning for newStirng is enforced
2285
if(entityRefName == entityName[ i ]) {
2286                    if(tokenize) text = entityReplacement[ i ];
2287                    return entityReplacementBuf[ i ];
2288                }
2289            }
2290        }
2291        return null;
2292    }
2293
2294
2295    protected void parseComment()
2296        throws XmlPullParserException, IOException JavaDoc
2297    {
2298        // implements XML 1.0 Section 2.5 Comments
2299

2300        //ASSUMPTION: seen <!-
2301
char ch = more();
2302        if(ch != '-') throw new XmlPullParserException(
2303                "expected <!-- for comment start", this, null);
2304        if(tokenize) posStart = pos;
2305
2306        int curLine = lineNumber;
2307        int curColumn = columnNumber;
2308        try {
2309            boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false;
2310            boolean normalizedCR = false;
2311
2312            boolean seenDash = false;
2313            boolean seenDashDash = false;
2314            while(true) {
2315                // scan until it hits -->
2316
ch = more();
2317                if(seenDashDash && ch != '>') {
2318                    throw new XmlPullParserException(
2319                        "in comment after two dashes (--) next character must be >"
2320                            +" not "+printable(ch), this, null);
2321                }
2322                if(ch == '-') {
2323                    if(!seenDash) {
2324                        seenDash = true;
2325                    } else {
2326                        seenDashDash = true;
2327                        seenDash = false;
2328                    }
2329                } else if(ch == '>') {
2330                    if(seenDashDash) {
2331                        break; // found end sequence!!!!
2332
} else {
2333                        seenDashDash = false;
2334                    }
2335                    seenDash = false;
2336                } else {
2337                    seenDash = false;
2338                    if(normalizeIgnorableWS) {
2339                        if(ch == '\r') {
2340                            normalizedCR = true;
2341                            //posEnd = pos -1;
2342
//joinPC();
2343
// posEnd is alreadys set
2344
if(!usePC) {
2345                                posEnd = pos -1;
2346                                if(posEnd > posStart) {
2347                                    joinPC();
2348                                } else {
2349                                    usePC = true;
2350                                    pcStart = pcEnd = 0;
2351                                }
2352                            }
2353                            //assert usePC == true;
2354
if(pcEnd >= pc.length) ensurePC(pcEnd);
2355                            pc[pcEnd++] = '\n';
2356                        } else if(ch == '\n') {
2357                            if(!normalizedCR && usePC) {
2358                                if(pcEnd >= pc.length) ensurePC(pcEnd);
2359                                pc[pcEnd++] = '\n';
2360                            }
2361                            normalizedCR = false;
2362                        } else {
2363                            if(usePC) {
2364                                if(pcEnd >= pc.length) ensurePC(pcEnd);
2365                                pc[pcEnd++] = ch;
2366                            }
2367                            normalizedCR = false;
2368                        }
2369                    }
2370                }
2371            }
2372        } catch(EOFException JavaDoc ex) {
2373            // detect EOF and create meaningful error ...
2374
throw new XmlPullParserException(
2375                "comment started on line "+curLine+" and column "+curColumn+" was not closed",
2376                this, ex);
2377        }
2378        if(tokenize) posEnd = pos - 3;
2379    }
2380
2381    protected boolean parsePI()
2382        throws XmlPullParserException, IOException JavaDoc
2383    {
2384        // implements XML 1.0 Section 2.6 Processing Instructions
2385

2386        // [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
2387

2388        //ASSUMPTION: seen <?
2389
if(tokenize) posStart = pos;
2390        int curLine = lineNumber;
2391        int curColumn = columnNumber;
2392        int piTargetStart = pos + bufAbsoluteStart;
2393        int piTargetEnd = -1;
2394        boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false;
2395        boolean normalizedCR = false;
2396
2397        try {
2398            boolean seenQ = false;
2399            char ch;
2400            while(true) {
2401                // scan until it hits -->
2402
ch = more();
2403                if(ch == '?') {
2404                    seenQ = true;
2405                } else if(ch == '>') {
2406                    if(seenQ) {
2407                        break; // found end sequence!!!!
2408
}
2409                    seenQ = false;
2410                } else {
2411                    if(piTargetEnd == -1 && isS(ch)) {
2412                        piTargetEnd = pos - 1 + bufAbsoluteStart;
2413
2414                        // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
2415
if((piTargetEnd - piTargetStart) == 3) {
2416                            if((buf[piTargetStart] == 'x' || buf[piTargetStart] == 'X')
2417                               && (buf[piTargetStart+1] == 'm' || buf[piTargetStart+1] == 'M')
2418                               && (buf[piTargetStart+2] == 'l' || buf[piTargetStart+2] == 'L')
2419                              )
2420                            {
2421                                if(piTargetStart > 3) { //<?xml is allowed as first characters in input ...
2422
throw new XmlPullParserException(
2423                                        "processing instruction can not have PITarget with reserveld xml name",
2424                                        this, null);
2425                                } else {
2426                                    if(buf[piTargetStart] != 'x'
2427                                       && buf[piTargetStart+1] != 'm'
2428                                       && buf[piTargetStart+2] != 'l')
2429                                    {
2430                                        throw new XmlPullParserException(
2431                                            "XMLDecl must have xml name in lowercase",
2432                                            this, null);
2433                                    }
2434                                }
2435                                parseXmlDecl(ch);
2436                                if(tokenize) posEnd = pos - 2;
2437                                int off = piTargetStart - bufAbsoluteStart + 3;
2438                                int len = pos - 2 - off;
2439                                xmlDeclContent = newString(buf, off, len);
2440                                return false;
2441                            }
2442                        }
2443                    }
2444                    seenQ = false;
2445                    if(normalizeIgnorableWS) {
2446                        if(ch == '\r') {
2447                            normalizedCR = true;
2448                            //posEnd = pos -1;
2449
//joinPC();
2450
// posEnd is alreadys set
2451
if(!usePC) {
2452                                posEnd = pos -1;
2453                                if(posEnd > posStart) {
2454                                    joinPC();
2455                                } else {
2456                                    usePC = true;
2457                                    pcStart = pcEnd = 0;
2458                                }
2459                            }
2460                            //assert usePC == true;
2461
if(pcEnd >= pc.length) ensurePC(pcEnd);
2462                            pc[pcEnd++] = '\n';
2463                        } else if(ch == '\n') {
2464                            if(!normalizedCR && usePC) {
2465                                if(pcEnd >= pc.length) ensurePC(pcEnd);
2466                                pc[pcEnd++] = '\n';
2467                            }
2468                            normalizedCR = false;
2469                        } else {
2470                            if(usePC) {
2471                                if(pcEnd >= pc.length) ensurePC(pcEnd);
2472                                pc[pcEnd++] = ch;
2473                            }
2474                            normalizedCR = false;
2475                        }
2476                    }
2477                }
2478            }
2479        } catch(EOFException JavaDoc ex) {
2480            // detect EOF and create meaningful error ...
2481
throw new XmlPullParserException(
2482                "processing instruction started on line "+curLine+" and column "+curColumn
2483                    +" was not closed",
2484                this, ex);
2485        }
2486        if(piTargetEnd == -1) {
2487            throw new XmlPullParserException(
2488                "processing instruction must have PITarget name", this, null);
2489        }
2490        piTargetStart -= bufAbsoluteStart;
2491        piTargetEnd -= bufAbsoluteStart;
2492        if(tokenize) posEnd = pos - 2;
2493        return true;
2494    }
2495
2496    protected final static char[] VERSION = {'v','e','r','s','i','o','n'};
2497    protected final static char[] NCODING = {'n','c','o','d','i','n','g'};
2498    protected final static char[] TANDALONE = {'t','a','n','d','a','l','o','n','e'};
2499    protected final static char[] YES = {'y','e','s'};
2500    protected final static char[] NO = {'n','o'};
2501
2502    protected char requireInput(char ch, char[] input)
2503        throws XmlPullParserException, IOException JavaDoc
2504    {
2505        for (int i = 0; i < input.length; i++)
2506        {
2507            if(ch != input[i]) {
2508                throw new XmlPullParserException(
2509                    "expected "+printable(input[i])+" in "+new String JavaDoc(input)
2510                        +" and not "+printable(ch), this, null);
2511            }
2512            ch = more();
2513        }
2514        return ch;
2515    }
2516
2517
2518    protected char requireNextS()
2519        throws XmlPullParserException, IOException JavaDoc
2520    {
2521        char ch = more();
2522        if(!isS(ch)) {
2523            throw new XmlPullParserException(
2524                "white space is required and not "+printable(ch), this, null);
2525        }
2526        return skipS(ch);
2527    }
2528
2529    protected char skipS(char ch)
2530        throws XmlPullParserException, IOException JavaDoc
2531    {
2532        while(isS(ch)) { ch = more(); } // skip additional spaces
2533
return ch;
2534    }
2535
2536    protected void parseXmlDecl(char ch)
2537        throws XmlPullParserException, IOException JavaDoc
2538    {
2539        // [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
2540

2541        // first make sure that relative positions will stay OK
2542
preventBufferCompaction = true;
2543        bufStart = 0; // necessary to keep pos unchnaged during expansion!
2544

2545        // --- parse VersionInfo
2546

2547        // [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
2548
// parse is positioned just on first S past <?xml
2549
ch = skipS(ch);
2550        ch = requireInput(ch, VERSION);
2551        // [25] Eq ::= S? '=' S?
2552
ch = skipS(ch);
2553        if(ch != '=') {
2554            throw new XmlPullParserException(
2555                "expected equals sign (=) after version and not "+printable(ch), this, null);
2556        }
2557        ch = more();
2558        ch = skipS(ch);
2559        if(ch != '\'' && ch != '"') {
2560            throw new XmlPullParserException(
2561                "expected apostrophe (') or quotation mark (\") after version and not "
2562                    +printable(ch), this, null);
2563        }
2564        char quotChar = ch;
2565        //int versionStart = pos + bufAbsoluteStart; // required if preventBufferCompaction==false
2566
int versionStart = pos;
2567        ch = more();
2568        // [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
2569
while(ch != quotChar) {
2570            if((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9')
2571               && ch != '_' && ch != '.' && ch != ':' && ch != '-')
2572            {
2573                throw new XmlPullParserException(
2574                    "<?xml version value expected to be in ([a-zA-Z0-9_.:] | '-')"
2575                        +" not "+printable(ch), this, null);
2576            }
2577            ch = more();
2578        }
2579        int versionEnd = pos - 1;
2580        parseXmlDeclWithVersion(versionStart, versionEnd);
2581        preventBufferCompaction = false; // alow again buffer commpaction - pos MAY chnage
2582
}
2583    //protected String xmlDeclVersion;
2584

2585    protected void parseXmlDeclWithVersion(int versionStart, int versionEnd)
2586        throws XmlPullParserException, IOException JavaDoc
2587    {
2588        // check version is "1.0"
2589
if((versionEnd - versionStart != 3)
2590           || buf[versionStart] != '1'
2591           || buf[versionStart+1] != '.'
2592           || buf[versionStart+2] != '0')
2593        {
2594            throw new XmlPullParserException(
2595                "only 1.0 is supported as <?xml version not '"
2596                    +printable(new String JavaDoc(buf, versionStart, versionEnd - versionStart))+"'", this, null);
2597        }
2598        xmlDeclVersion = newString(buf, versionStart, versionEnd - versionStart);
2599
2600        // [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" )
2601
char ch = more();
2602        ch = skipS(ch);
2603        if(ch == 'e') {
2604            ch = more();
2605            ch = requireInput(ch, NCODING);
2606            ch = skipS(ch);
2607            if(ch != '=') {
2608                throw new XmlPullParserException(
2609                    "expected equals sign (=) after encoding and not "+printable(ch), this, null);
2610            }
2611            ch = more();
2612            ch = skipS(ch);
2613            if(ch != '\'' && ch != '"') {
2614                throw new XmlPullParserException(
2615                    "expected apostrophe (') or quotation mark (\") after encoding and not "
2616                        +printable(ch), this, null);
2617            }
2618            char quotChar = ch;
2619            int encodingStart = pos;
2620            ch = more();
2621            // [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
2622
if((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z'))
2623            {
2624                throw new XmlPullParserException(
2625                    "<?xml encoding name expected to start with [A-Za-z]"
2626                        +" not "+printable(ch), this, null);
2627            }
2628            ch = more();
2629            while(ch != quotChar) {
2630                if((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9')
2631                   && ch != '.' && ch != '_' && ch != '-')
2632                {
2633                    throw new XmlPullParserException(
2634                        "<?xml encoding value expected to be in ([A-Za-z0-9._] | '-')"
2635                            +" not "+printable(ch), this, null);
2636                }
2637                ch = more();
2638            }
2639            int encodingEnd = pos - 1;
2640
2641
2642            // TODO reconcile with setInput encodingName
2643
inputEncoding = newString(buf, encodingStart, encodingEnd - encodingStart);
2644            ch = more();
2645        }
2646
2647        ch = skipS(ch);
2648        // [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
2649
if(ch == 's') {
2650            ch = more();
2651            ch = requireInput(ch, TANDALONE);
2652            ch = skipS(ch);
2653            if(ch != '=') {
2654                throw new XmlPullParserException(
2655                    "expected equals sign (=) after standalone and not "+printable(ch),
2656                    this, null);
2657            }
2658            ch = more();
2659            ch = skipS(ch);
2660            if(ch != '\'' && ch != '"') {
2661                throw new XmlPullParserException(
2662                    "expected apostrophe (') or quotation mark (\") after encoding and not "
2663                        +printable(ch), this, null);
2664            }
2665            char quotChar = ch;
2666            int standaloneStart = pos;
2667            ch = more();
2668            if(ch == 'y') {
2669                ch = requireInput(ch, YES);
2670                //Boolean standalone = new Boolean(true);
2671
xmlDeclStandalone = new Boolean JavaDoc(true);
2672            } else if(ch == 'n') {
2673                ch = requireInput(ch, NO);
2674                //Boolean standalone = new Boolean(false);
2675
xmlDeclStandalone = new Boolean JavaDoc(false);
2676            } else {
2677                throw new XmlPullParserException(
2678                    "expected 'yes' or 'no' after standalone and not "
2679                        +printable(ch), this, null);
2680            }
2681            if(ch != quotChar) {
2682                throw new XmlPullParserException(
2683                    "expected "+quotChar+" after standalone value not "
2684                        +printable(ch), this, null);
2685            }
2686            ch = more();
2687        }
2688
2689
2690        ch = skipS(ch);
2691        if(ch != '?') {
2692            throw new XmlPullParserException(
2693                "expected ?> as last part of <?xml not "
2694                    +printable(ch), this, null);
2695        }
2696        ch = more();
2697        if(ch != '>') {
2698            throw new XmlPullParserException(
2699                "expected ?> as last part of <?xml not "
2700                    +printable(ch), this, null);
2701        }
2702
2703    }
2704    protected void parseDocdecl()
2705        throws XmlPullParserException, IOException JavaDoc
2706    {
2707        //ASSUMPTION: seen <!D
2708
char ch = more();
2709        if(ch != 'O') throw new XmlPullParserException(
2710                "expected <!DOCTYPE", this, null);
2711        ch = more();
2712        if(ch != 'C') throw new XmlPullParserException(
2713                "expected <!DOCTYPE", this, null);
2714        ch = more();
2715        if(ch != 'T') throw new XmlPullParserException(
2716                "expected <!DOCTYPE", this, null);
2717        ch = more();
2718        if(ch != 'Y') throw new XmlPullParserException(
2719                "expected <!DOCTYPE", this, null);
2720        ch = more();
2721        if(ch != 'P') throw new XmlPullParserException(
2722                "expected <!DOCTYPE", this, null);
2723        ch = more();
2724        if(ch != 'E') throw new XmlPullParserException(
2725                "expected <!DOCTYPE", this, null);
2726        posStart = pos;
2727        // do simple and crude scanning for end of doctype
2728

2729        // [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('['
2730
// (markupdecl | DeclSep)* ']' S?)? '>'
2731
int bracketLevel = 0;
2732        boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false;
2733        boolean normalizedCR = false;
2734        while(true) {
2735            ch = more();
2736            if(ch == '[') ++bracketLevel;
2737            if(ch == ']') --bracketLevel;
2738            if(ch == '>' && bracketLevel == 0) break;
2739            if(normalizeIgnorableWS) {
2740                if(ch == '\r') {
2741                    normalizedCR = true;
2742                    //posEnd = pos -1;
2743
//joinPC();
2744
// posEnd is alreadys set
2745
if(!usePC) {
2746                        posEnd = pos -1;
2747                        if(posEnd > posStart) {
2748                            joinPC();
2749                        } else {
2750                            usePC = true;
2751                            pcStart = pcEnd = 0;
2752                        }
2753                    }
2754                    //assert usePC == true;
2755
if(pcEnd >= pc.length) ensurePC(pcEnd);
2756                    pc[pcEnd++] = '\n';
2757                } else if(ch == '\n') {
2758                    if(!normalizedCR && usePC) {
2759                        if(pcEnd >= pc.length) ensurePC(pcEnd);
2760                        pc[pcEnd++] = '\n';
2761                    }
2762                    normalizedCR = false;
2763                } else {
2764                    if(usePC) {
2765                        if(pcEnd >= pc.length) ensurePC(pcEnd);
2766                        pc[pcEnd++] = ch;
2767                    }
2768                    normalizedCR = false;
2769                }
2770            }
2771
2772        }
2773        posEnd = pos - 1;
2774    }
2775
2776    protected void parseCDSect(boolean hadCharData)
2777        throws XmlPullParserException, IOException JavaDoc
2778    {
2779        // implements XML 1.0 Section 2.7 CDATA Sections
2780

2781        // [18] CDSect ::= CDStart CData CDEnd
2782
// [19] CDStart ::= '<![CDATA['
2783
// [20] CData ::= (Char* - (Char* ']]>' Char*))
2784
// [21] CDEnd ::= ']]>'
2785

2786        //ASSUMPTION: seen <![
2787
char ch = more();
2788        if(ch != 'C') throw new XmlPullParserException(
2789                "expected <[CDATA[ for comment start", this, null);
2790        ch = more();
2791        if(ch != 'D') throw new XmlPullParserException(
2792                "expected <[CDATA[ for comment start", this, null);
2793        ch = more();
2794        if(ch != 'A') throw new XmlPullParserException(
2795                "expected <[CDATA[ for comment start", this, null);
2796        ch = more();
2797        if(ch != 'T') throw new XmlPullParserException(
2798                "expected <[CDATA[ for comment start", this, null);
2799        ch = more();
2800        if(ch != 'A') throw new XmlPullParserException(
2801                "expected <[CDATA[ for comment start", this, null);
2802        ch = more();
2803        if(ch != '[') throw new XmlPullParserException(
2804                "expected <[CDATA[ for comment start", this, null);
2805
2806        //if(tokenize) {
2807
int cdStart = pos + bufAbsoluteStart;
2808        int curLine = lineNumber;
2809        int curColumn = columnNumber;
2810        boolean normalizeInput = tokenize == false || roundtripSupported == false;
2811        try {
2812            boolean seenBracket = false;
2813            boolean seenBracketBracket = false;
2814            boolean normalizedCR = false;
2815            if(normalizeInput) {
2816                if(hadCharData) {
2817                    if(!usePC) {
2818                        // posEnd is correct already!!!
2819
if(posEnd > posStart) {
2820                            joinPC();
2821                        } else {
2822                            usePC = true;
2823                            pcStart = pcEnd = 0;
2824                        }
2825                    }
2826                }
2827            }
2828            while(true) {
2829                // scan until it hits "]]>"
2830
ch = more();
2831                if(ch == ']') {
2832                    if(!seenBracket) {
2833                        seenBracket = true;
2834                    } else {
2835                        seenBracketBracket = true;
2836                        //seenBracket = false;
2837
}
2838                } else if(ch == '>') {
2839                    if(seenBracketBracket) {
2840                        break; // found end sequence!!!!
2841
} else {
2842                        seenBracketBracket = false;
2843                    }
2844                    seenBracket = false;
2845                } else {
2846                    seenBracket = false;
2847                }
2848                if(normalizeInput) {
2849                    // deal with normalization issues ...
2850
if(ch == '\r') {
2851                        normalizedCR = true;
2852                        // posEnd is alreadys set
2853
posStart = cdStart - bufAbsoluteStart;
2854                        posEnd = pos;
2855                        if(!usePC) {
2856                            if(posEnd > posStart) {
2857                                joinPC();
2858                            } else {
2859                                usePC = true;
2860                                pcStart = pcEnd = 0;
2861                            }
2862                        }
2863                        //assert usePC == true;
2864
if(pcEnd >= pc.length) ensurePC(pcEnd);
2865                        pc[pcEnd++] = '\n';
2866                    } else if(ch == '\n') {
2867                        if(!normalizedCR && usePC) {
2868                            if(pcEnd >= pc.length) ensurePC(pcEnd);
2869                            pc[pcEnd++] = '\n';
2870                        }
2871                        normalizedCR = false;
2872                    } else {
2873                        if(usePC) {
2874                            if(pcEnd >= pc.length) ensurePC(pcEnd);
2875                            pc[pcEnd++] = ch;
2876                        }
2877                        normalizedCR = false;
2878                    }
2879                }
2880            }
2881        } catch(EOFException JavaDoc ex) {
2882            // detect EOF and create meaningful error ...
2883
throw new XmlPullParserException(
2884                "CDATA section started on line "+curLine+" and column "+curColumn+" was not closed",
2885                this, ex);
2886        }
2887        if(normalizeInput) {
2888            if(usePC) {
2889                pcEnd = pcEnd - 2;
2890            }
2891        }
2892        posStart = cdStart - bufAbsoluteStart;
2893        posEnd = pos - 3;
2894    }
2895
2896    protected void fillBuf() throws IOException JavaDoc, XmlPullParserException {
2897        if(reader == null) throw new XmlPullParserException(
2898                "reader must be set before parsing is started");
2899
2900        // see if we are in compaction area
2901
if(bufEnd > bufSoftLimit) {
2902
2903            // expand buffer it makes sense!!!!
2904
boolean compact = bufStart > bufSoftLimit;
2905            boolean expand = false;
2906            if(preventBufferCompaction) {
2907                compact = false;
2908                expand = true;
2909            } else if(!compact) {
2910                //freeSpace
2911
if(bufStart < buf.length / 2) {
2912                    // less then half buffer available forcompactin --> expand instead!!!
2913
expand = true;
2914                } else {
2915                    // at least half of buffer can be reclaimed --> worthwhile effort!!!
2916
compact = true;
2917                }
2918            }
2919
2920            // if buffer almost full then compact it
2921
if(compact) {
2922                //TODO: look on trashing
2923
// //assert bufStart > 0
2924
System.arraycopy(buf, bufStart, buf, 0, bufEnd - bufStart);
2925                if(TRACE_SIZING) System.out.println(
2926                        "TRACE_SIZING fillBuf() compacting "+bufStart
2927                            +" bufEnd="+bufEnd
2928                            +" pos="+pos+" posStart="+posStart+" posEnd="+posEnd
2929                            +" buf first 100 chars:"+new String JavaDoc(buf, bufStart,
2930                                                                bufEnd - bufStart < 100 ? bufEnd - bufStart : 100 ));
2931
2932            } else if(expand) {
2933                int newSize = 2 * buf.length;
2934                char newBuf[] = new char[ newSize ];
2935                if(TRACE_SIZING) System.out.println("TRACE_SIZING fillBuf() "+buf.length+" => "+newSize);
2936                System.arraycopy(buf, bufStart, newBuf, 0, bufEnd - bufStart);
2937                buf = newBuf;
2938                if(bufLoadFactor > 0) {
2939                    bufSoftLimit = ( bufLoadFactor * buf.length ) /100;
2940                }
2941
2942            } else {
2943                throw new XmlPullParserException("internal error in fillBuffer()");
2944            }
2945            bufEnd -= bufStart;
2946            pos -= bufStart;
2947            posStart -= bufStart;
2948            posEnd -= bufStart;
2949            bufAbsoluteStart += bufStart;
2950            bufStart = 0;
2951            if(TRACE_SIZING) System.out.println(
2952                    "TRACE_SIZING fillBuf() after bufEnd="+bufEnd
2953                        +" pos="+pos+" posStart="+posStart+" posEnd="+posEnd
2954                        +" buf first 100 chars:"+new String JavaDoc(buf, 0, bufEnd < 100 ? bufEnd : 100));
2955        }
2956        // at least one charcter must be read or error
2957
int len = buf.length - bufEnd > READ_CHUNK_SIZE ? READ_CHUNK_SIZE : buf.length - bufEnd;
2958        int ret = reader.read(buf, bufEnd, len);
2959        if(ret > 0) {
2960            bufEnd += ret;
2961            if(TRACE_SIZING) System.out.println(
2962                    "TRACE_SIZING fillBuf() after filling in buffer"
2963                        +" buf first 100 chars:"+new String JavaDoc(buf, 0, bufEnd < 100 ? bufEnd : 100));
2964
2965            return;
2966        }
2967        if(ret == -1) {
2968            throw new EOFException JavaDoc("no more data available");
2969        } else {
2970            throw new IOException JavaDoc("error reading input, returned "+ret);
2971        }
2972    }
2973
2974    protected char more() throws IOException JavaDoc, XmlPullParserException {
2975        if(pos >= bufEnd) fillBuf();
2976        char ch = buf[pos++];
2977        //line/columnNumber
2978
if(ch == '\n') { ++lineNumber; columnNumber = 1; }
2979        else { ++columnNumber; }
2980        //System.out.print(ch);
2981
return ch;
2982    }
2983
2984    //protected char printable(char ch) { return ch; }
2985
protected String JavaDoc printable(char ch) {
2986        if(ch == '\n') {
2987            return "\\n";
2988        } else if(ch == '\r') {
2989            return "\\r";
2990        } else if(ch == '\t') {
2991            return "\\t";
2992        } else if(ch == '\'') {
2993            return "\\'";
2994        } if(ch > 127 || ch < 32) {
2995            return "\\u"+Integer.toHexString((int)ch);
2996        }
2997        return ""+ch;
2998    }
2999
3000    protected String JavaDoc printable(String JavaDoc s) {
3001        if(s == null) return null;
3002        StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
3003        for(int i = 0; i < s.length(); ++i) {
3004            buf.append(printable(s.charAt(i)));
3005        }
3006        s = buf.toString();
3007        return s;
3008    }
3009
3010    protected void ensurePC(int end) {
3011        //assert end >= pc.length;
3012
int newSize = end > READ_CHUNK_SIZE ? 2 * end : 2 * READ_CHUNK_SIZE;
3013        char[] newPC = new char[ newSize ];
3014        if(TRACE_SIZING) System.out.println("TRACE_SIZING ensurePC() "+pc.length+" ==> "+newSize+" end="+end);
3015        System.arraycopy(pc, 0, newPC, 0, pcEnd);
3016        pc = newPC;
3017        //assert end < pc.length;
3018
}
3019
3020    protected void joinPC() {
3021        //assert usePC == false;
3022
//assert posEnd > posStart;
3023
int len = posEnd - posStart;
3024        int newEnd = pcEnd + len + 1;
3025        if(newEnd >= pc.length) ensurePC(newEnd); // add 1 for extra space for one char
3026
//assert newEnd < pc.length;
3027
System.arraycopy(buf, posStart, pc, pcEnd, len);
3028        pcEnd += len;
3029        usePC = true;
3030
3031    }
3032
3033}
3034
3035
3036/*
3037 * Indiana University Extreme! Lab Software License, Version 1.1.1
3038 *
3039 *
3040 * Copyright (c) 2002 Extreme! Lab, Indiana University. All rights
3041 * reserved.
3042 *
3043 * Redistribution and use in source and binary forms, with or without
3044 * modification, are permitted provided that the following conditions
3045 * are met:
3046 *
3047 * 1. Redistributions of source code must retain the above copyright
3048 * notice, this list of conditions and the following disclaimer.
3049 *
3050 * 2. Redistributions in binary form must reproduce the above copyright
3051 * notice, this list of conditions and the following disclaimer in
3052 * the documentation and/or other materials provided with the
3053 * distribution.
3054 *
3055 * 3. The end-user documentation included with the redistribution,
3056 * if any, must include the following acknowledgment:
3057 * "This product includes software developed by the Indiana
3058 * University Extreme! Lab (http://www.extreme.indiana.edu/)."
3059 * Alternately, this acknowledgment may appear in the software itself,
3060 * if and wherever such third-party acknowledgments normally appear.
3061 *
3062 * 4. The names "Indiana University" and "Indiana University
3063 * Extreme! Lab" must not be used to endorse or promote products
3064 * derived from this software without prior written permission. For
3065 * written permission, please contact http://www.extreme.indiana.edu/.
3066 *
3067 * 5. Products derived from this software may not use "Indiana
3068 * University" name nor may "Indiana University" appear in their name,
3069 * without prior written permission of the Indiana University.
3070 *
3071 *
3072 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
3073 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3074 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3075 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
3076 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3077 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3078 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
3079 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3080 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3081 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3082 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3083 * SUCH DAMAGE.
3084 */

3085
3086
3087
3088
Popular Tags