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