KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > xml > stream > XMLStreamReaderImpl


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2006 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.xml.stream;
10
11 import java.io.IOException JavaDoc;
12 import java.io.InputStream JavaDoc;
13 import java.io.InputStreamReader JavaDoc;
14 import java.io.Reader JavaDoc;
15 import java.io.UnsupportedEncodingException JavaDoc;
16
17 import javolution.context.ObjectFactory;
18 import javolution.io.UTF8StreamReader;
19 import javolution.lang.Reusable;
20 import javolution.text.CharArray;
21 import javolution.xml.sax.Attributes;
22 import j2me.lang.CharSequence;
23 import j2me.lang.IllegalStateException;
24 import j2me.util.Map;
25 import j2mex.realtime.MemoryArea;
26
27 /**
28  * <p> This class represents a {@link javolution.lang.Reusable reusable}
29  * implementation of {@link XMLStreamWriter}.</p>
30  *
31  * <p> Except for the types being used ({@link CharArray CharArray}/
32  * {@link CharSequence CharSequence} instead of {@link String}) the
33  * parsing behavior is about the same as for the standard
34  * <code>javax.xml.stream.XMLStreamReader</code> (although several times
35  * faster).</p>
36  *
37  * <p> The {@link CharArray CharArray} instances returned by this reader
38  * supports fast primitive conversions as illustrated below:[code]
39  *
40  * // Creates reader for an input sream with unknown encoding.
41  * XMLStreamReaderImpl xmlReader = new XMLStreamReaderImpl().setInput(inputStream);
42  *
43  * // Parses.
44  * for (int e=xmlReader.next(); e != XMLStreamConstants.END_DOCUMENT; e = xmlReader.next()) {
45  * switch (e) { // Event.
46  * case XMLStreamConstants.START_ELEMENT:
47  * if (xmlReader.getLocalName().equals("Time")) {
48  * // Reads primitive types (int) attributes directly.
49  * int hour = xmlReader.getAttributeValue("hour").toInt();
50  * int minute = xmlReader.getAttributeValue("minute").toInt();
51  * int second = xmlReader.getAttributeValue("second").toInt();
52  * ...
53  * }
54  * ...
55  * break;
56  * }
57  * }
58  *
59  * // Closes reader, it is automatically reset() and can be reused!
60  * xmlReader.close();
61  * [/code]</p>
62  *
63  * <p> This reader returns all contiguous character data in a single
64  * chunk (always coalescing). It is non-validating (DTD is returned
65  * unparsed). Although, users may define custom entities mapping using
66  * the {@link #setEntities} method (e.g. after parsing/resolving
67  * external entities).</p>
68  *
69  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
70  * @version 4.0, September 4, 2006
71  */

72 public final class XMLStreamReaderImpl implements XMLStreamReader, Reusable {
73
74     /**
75      * Holds the textual representation for events.
76      */

77     static final String JavaDoc[] NAMES_OF_EVENTS = new String JavaDoc[] { "UNDEFINED",
78             "START_ELEMENT", "END_ELEMENT", "PROCESSING_INSTRUCTIONS",
79             "CHARACTERS", "COMMENT", "SPACE", "START_DOCUMENT", "END_DOCUMENT",
80             "ENTITY_REFERENCE", "ATTRIBUTE", "DTD", "CDATA", "NAMESPACE",
81             "NOTATION_DECLARATION", "ENTITY_DECLARATION" };
82
83     /**
84      * Holds the reader buffer capacity.
85      */

86     static final int READER_BUFFER_CAPACITY = 4096;
87
88     /**
89      * Holds the prolog if any.
90      */

91     CharArray _prolog;
92
93     /**
94      * Holds object factory when factory-produced.
95      */

96     ObjectFactory _objectFactory;
97
98     /**
99      * Holds the current index in the character buffer.
100      */

101     private int _readIndex;
102
103     /**
104      * Number of characters read from reader
105      */

106     private int _readCount;
107
108     /**
109      * Holds the data buffer for CharSequence produced by this parser.
110      */

111     private char[] _data = new char[READER_BUFFER_CAPACITY * 2];
112
113     /**
114      * Holds the current index of the data buffer (_data).
115      */

116     private int _index;
117
118     /**
119      * Holds the current element nesting.
120      */

121     private int _nesting;
122
123     /**
124      * Holds qualified name (include prefix).
125      */

126     private CharArray _qName;
127
128     /**
129      * Holds element prefix separator index.
130      */

131     private int _prefixSep;
132
133     /**
134      * Holds attribute qualified name.
135      */

136     private CharArray _attrQName;
137
138     /**
139      * Holds attribute prefix separator index.
140      */

141     private int _attrPrefixSep;
142
143     /**
144      * Holds attribute value.
145      */

146     private CharArray _attrValue;
147
148     /**
149      * Holds current event type
150      */

151     private int _eventType = START_DOCUMENT;
152
153     /**
154      * Indicates if event type is START_TAG, and tag is empty, i.e. <sometag/>
155      */

156     private boolean _isEmpty;
157
158     /**
159      * Indicates if characters are pending for potential coalescing.
160      */

161     boolean _charactersPending = false;
162
163     /**
164      * Holds the start index for the current state within _data array.
165      */

166     private int _start;
167
168     /**
169      * Holds the parser state.
170      */

171     private int _state = STATE_CHARACTERS;
172
173     /**
174      * Holds the current text.
175      */

176     private CharArray _text;
177
178     /**
179      * Holds the reader input source (<code>null</code> when unused).
180      */

181     private Reader JavaDoc _reader;
182
183     /**
184      * Holds the character buffer used for reading.
185      */

186     private final char[] _readBuffer = new char[READER_BUFFER_CAPACITY];
187
188     /**
189      * Holds the start offset in the character buffer (due to auto detection
190      * of encoding).
191      */

192     private int _startOffset; // Byte Order Mark count.
193

194     /**
195      * Holds the location object.
196      */

197     private final LocationImpl _location = new LocationImpl();
198
199     /**
200      * Holds the namespace stack.
201      */

202     private final NamespacesImpl _namespaces = new NamespacesImpl();
203
204     /**
205      * Holds the current attributes.
206      */

207     private final AttributesImpl _attributes = new AttributesImpl(_namespaces);
208
209     /**
210      * Holds working stack (by nesting level).
211      */

212     private CharArray[] _elemStack = new CharArray[16];
213
214     /**
215      * Holds stream encoding if known.
216      */

217     private String JavaDoc _encoding;
218
219     /**
220      * Holds the entities.
221      */

222     private final EntitiesImpl _entities = new EntitiesImpl();
223
224     /**
225      * Holds the reader for input streams.
226      */

227     private final UTF8StreamReader _utf8StreamReader = new UTF8StreamReader();
228
229     /**
230      * Default constructor.
231      */

232     public XMLStreamReaderImpl() {
233     }
234
235     /**
236      * Sets the input stream source for this XML stream reader
237      * (encoding retrieved from XML prolog if any).
238      *
239      * @param in the input source with unknown encoding.
240      */

241     public void setInput(InputStream JavaDoc in) throws XMLStreamException {
242         setInput(in, detectEncoding(in));
243         CharArray prologEncoding = getCharacterEncodingScheme();
244
245         // Checks if necessary to change the reader.
246
if ((prologEncoding != null) && !prologEncoding.equals(_encoding)
247                 && !(isUTF8(prologEncoding) && isUTF8(_encoding))) {
248             // Changes reader (keep characters already read).
249
int startOffset = _readCount;
250             reset();
251             _startOffset = startOffset;
252             setInput(in, prologEncoding.toString());
253         }
254     }
255
256     private static boolean isUTF8(Object JavaDoc encoding) {
257         return encoding.equals("utf-8") || encoding.equals("UTF-8")
258                 || encoding.equals("ASCII") || encoding.equals("utf8")
259                 || encoding.equals("UTF8");
260     }
261
262     /**
263      * Sets the input stream source and encoding for this XML stream reader.
264      *
265      * @param in the input source.
266      * @param encoding the associated encoding.
267      */

268     public void setInput(InputStream JavaDoc in, String JavaDoc encoding)
269             throws XMLStreamException {
270         _encoding = encoding;
271         if (isUTF8(encoding)) { // Use our fast UTF-8 Reader.
272
setInput(_utf8StreamReader.setInput(in));
273         } else {
274             try {
275                 setInput(new InputStreamReader JavaDoc(in, encoding));
276             } catch (UnsupportedEncodingException JavaDoc e) {
277                 throw new XMLStreamException(e);
278             }
279         }
280     }
281
282     /**
283      * Sets the reader input source for this XML stream reader.
284      * This method reads the prolog (if any).
285      *
286      * @param reader the input source reader.
287      * @see javolution.io.UTF8StreamReader
288      * @see javolution.io.UTF8ByteBufferReader
289      * @see javolution.io.CharSequenceReader
290      */

291     public void setInput(Reader JavaDoc reader) throws XMLStreamException {
292         if (_reader != null)
293             throw new IllegalStateException JavaDoc("Reader not closed or reset");
294         _reader = reader;
295         try { // Reads prolog (if there)
296
int readCount = reader.read(_readBuffer, _startOffset,
297                     _readBuffer.length - _startOffset);
298             _readCount = (readCount >= 0) ? readCount + _startOffset
299                     : _startOffset;
300             if ((_readCount >= 5) && (_readBuffer[0] == '<')
301                     && (_readBuffer[1] == '?') && (_readBuffer[2] == 'x')
302                     && (_readBuffer[3] == 'm') && (_readBuffer[4] == 'l')
303                     && (_readBuffer[5] == ' ')) { // Prolog detected.
304
next(); // Processing instruction.
305
_prolog = this.getPIData();
306                 _index = _prolog.offset() + _prolog.length(); // Keep prolog.
307
_start = _index; // Default state.
308
_eventType = START_DOCUMENT; // Resets to START_DOCUMENT.
309
}
310         } catch (IOException JavaDoc e) {
311             throw new XMLStreamException(e);
312         }
313     }
314
315     /**
316      * Returns the qualified name of the current event.
317      *
318      * @return the qualified name.
319      * @throws IllegalStateException if this not a START_ELEMENT or END_ELEMENT.
320      */

321     public CharArray getQName() {
322         if ((_eventType != XMLStreamConstants.START_ELEMENT)
323                 && (_eventType != XMLStreamConstants.END_ELEMENT))
324             throw new IllegalStateException JavaDoc(
325                     "Not a start element or an end element");
326         return _qName;
327     }
328
329     /**
330      * Returns the current attributes (SAX2-Like).
331      *
332      * @return returns the number of attributes.
333      * @throws IllegalStateException if not a START_ELEMENT.
334      */

335     public Attributes getAttributes() {
336         if (_eventType != XMLStreamConstants.START_ELEMENT)
337             throw new IllegalStateException JavaDoc("Not a start element");
338         return _attributes;
339     }
340
341     /**
342      * Defines a custom entities to replacement text mapping for this reader.
343      * For example:[code]
344      * FastMap<String, String> HTML_ENTITIES = new FastMap<String, String>();
345      * HTML_ENTITIES.put("nbsp", " ");
346      * HTML_ENTITIES.put("copy", "©");
347      * HTML_ENTITIES.put("eacute", "é");
348      * ...
349      * XMLStreamReaderImpl reader = new XMLStreamReaderImpl();
350      * reader.setEntities(HTML_ENTITIES);
351      * [/code]
352      * The entities mapping may be changed dynamically (e.g.
353      * after reading the DTD and all external entities references are resolved).
354      *
355      * @param entities the entities to replacement texts mapping
356      * (both must be <code>CharSequence</code> instances).
357      */

358     public void setEntities(Map entities) {
359         _entities.setEntitiesMapping(entities);
360     }
361
362     /**
363      * Returns the textual representation of this reader current state.
364      *
365      * @return the textual representation of the current state.
366      */

367     public String JavaDoc toString() {
368         return "XMLStreamReader - State: " + NAMES_OF_EVENTS[_eventType]
369                 + ", Location: " + _location.toString();
370     }
371
372     // Implements XMLStreamReader Interface.
373
public int next() throws XMLStreamException {
374
375         // Clears previous state.
376
if (_eventType == START_ELEMENT) {
377             _attributes.reset();
378             if (_isEmpty) { // Previous empty tag, generates END_TAG automatically.
379
_isEmpty = false;
380                 return _eventType = END_ELEMENT;
381             }
382         } else if (_eventType == END_ELEMENT) {
383             _namespaces.pop();
384             CharArray startElem = _elemStack[_nesting--];
385             _start = _index = startElem.offset();
386             while (_seqs[--_seqsIndex] != startElem) { // Recycles CharArray instances.
387
}
388         }
389         // Reader loop.
390
while (true) {
391
392             // Main character reading block.
393
if ((_readIndex >= _readCount) && isEndOfStream())
394                 return _eventType; // END_DOCUMENT or CHARACTERS.
395
char c = _readBuffer[_readIndex++];
396             if (c <= '&')
397                 c = (c == '&') ? replaceEntity()
398                         : (c < ' ') ? handleEndOfLine(c) : c;
399             _data[_index++] = c;
400
401             // Main processing.
402
//
403
switch (_state) {
404
405             case STATE_CHARACTERS:
406                 while (true) { // Read characters data all at once.
407

408                     if (c == '<') {
409                         int length = _index - _start - 1;
410                         if (length > 0) {
411                             if (_charactersPending) {
412                                _text.setArray(_data, _text.offset(), _text
413                                       .length()
414                                       + length); // Coalescing.
415
} else {
416                                _text = newSeq(_start, length);
417                                _charactersPending = true;
418                            }
419                            _start = _index - 1; // Keeps '<' as part of markup.
420
}
421                         _state = STATE_MARKUP;
422                         break;
423                     }
424
425                     // Local character reading block.
426
if ((_readIndex >= _readCount) && isEndOfStream())
427                         return _eventType;
428                     c = _readBuffer[_readIndex++];
429                     if (c <= '&')
430                         c = (c == '&') ? replaceEntity()
431                                 : (c < ' ') ? handleEndOfLine(c) : c;
432                     _data[_index++] = c;
433                 }
434                 break;
435
436             case STATE_CDATA:
437                 while (true) { // Reads CDATA all at once.
438

439                     if ((c == '>') && (_index - _start >= 3)
440                             && (_data[_index - 2] == ']')
441                             && (_data[_index - 3] == ']')) {
442                         _index -= 3;
443                         int length = _index - _start;
444                         if (length > 0) { // Not empty.
445
if (_charactersPending) {
446                                 _text.setArray(_data, _text.offset(), _text
447                                         .length()
448                                         + length); // Coalescing.
449
} else {
450                                 _text = newSeq(_start, length);
451                                 _charactersPending = true;
452                             }
453                         }
454                         _start = _index;
455                         _state = STATE_CHARACTERS;
456                         break;
457                     }
458
459                     // Local character reading block.
460
if (_readIndex >= _readCount)
461                         reloadBuffer();
462                     c = _readBuffer[_readIndex++];
463                     if (c < ' ')
464                         c = handleEndOfLine(c);
465                     _data[_index++] = c;
466                 }
467                 break;
468
469             case STATE_DTD:
470                 if (c == '>') {
471                     _text = newSeq(_start, _index - _start);
472                     _index = _start; // Do not keep DTD.
473
_state = STATE_CHARACTERS;
474                     return _eventType = DTD;
475                 } else if (c == '[') {
476                     _state = STATE_DTD_INTERNAL;
477                 }
478                 break;
479
480             case STATE_DTD_INTERNAL:
481                 if (c == ']') {
482                     _state = STATE_DTD;
483                 }
484                 break;
485
486             case STATE_MARKUP: // Starts with '<'
487
if (_index - _start == 2) {
488                     if (c == '/') {
489                         _start = _index = _index - 2;
490                         _state = STATE_CLOSE_TAGxREAD_ELEM_NAME;
491                         _prefixSep = -1;
492                         if (_charactersPending) { // Flush characters event.
493
_charactersPending = false;
494                             return _eventType = CHARACTERS;
495                         }
496                     } else if (c == '?') {
497                         _start = _index = _index - 2;
498                         _state = STATE_PI;
499                         if (_charactersPending) { // Flush characters event.
500
_charactersPending = false;
501                             return _eventType = CHARACTERS;
502                         }
503                     } else if (c != '!') { // Element tag (first letter).
504
_data[_start] = c;
505                         _index = _start + 1;
506                         _state = STATE_OPEN_TAGxREAD_ELEM_NAME;
507                         _prefixSep = -1;
508                         if (_charactersPending) { // Flush character event.
509
_charactersPending = false;
510                             return _eventType = CHARACTERS;
511                         }
512                     }
513                 } else if ((_index - _start == 4) && (_data[_start + 1] == '!')
514                         && (_data[_start + 2] == '-')
515                         && (_data[_start + 3] == '-')) {
516                     _start = _index = _index - 4; // Removes <!--
517
_state = STATE_COMMENT;
518                     if (_charactersPending) { // Flush character event.
519
_charactersPending = false;
520                         return _eventType = CHARACTERS;
521                     }
522
523                 } else if ((_index - _start == 9) && (_data[_start + 1] == '!')
524                         && (_data[_start + 2] == '[')
525                         && (_data[_start + 3] == 'C')
526                         && (_data[_start + 4] == 'D')
527                         && (_data[_start + 5] == 'A')
528                         && (_data[_start + 6] == 'T')
529                         && (_data[_start + 7] == 'A')
530                         && (_data[_start + 8] == '[')) {
531                     _start = _index = _index - 9; // Do not keep <![CDATA[
532
_state = STATE_CDATA;
533
534                 } else if ((_index - _start == 9) && (_data[_start + 1] == '!')
535                         && (_data[_start + 2] == 'D')
536                         && (_data[_start + 3] == 'O')
537                         && (_data[_start + 4] == 'C')
538                         && (_data[_start + 5] == 'T')
539                         && (_data[_start + 6] == 'Y')
540                         && (_data[_start + 7] == 'P')
541                         && (_data[_start + 8] == 'E')) {
542                     // Keeps <!DOCTYPE as part of DTD.
543
_state = STATE_DTD;
544                 } else {
545                     // Ignores, e.g. <!ELEMENT <!ENTITY...
546
}
547                 break;
548
549             case STATE_COMMENT:
550                 while (true) { // Read comment all at once.
551

552                     if ((c == '>') && (_index - _start >= 3)
553                             && (_data[_index - 2] == '-')
554                             && (_data[_index - 3] == '-')) {
555                         _index -= 3; // Removes -->
556
_text = newSeq(_start, _index - _start);
557                         _state = STATE_CHARACTERS;
558                         _index = _start; // Do not keep comments.
559
return _eventType = COMMENT;
560                     }
561
562                     // Local character reading block.
563
if (_readIndex >= _readCount)
564                         reloadBuffer();
565                     c = _readBuffer[_readIndex++];
566                     if (c < ' ')
567                         c = handleEndOfLine(c);
568                     _data[_index++] = c;
569                 }
570
571             case STATE_PI:
572                 if ((c == '>') && (_index - _start >= 2)
573                         && (_data[_index - 2] == '?')) {
574                     _index -= 2; // Removes ?>
575
_text = newSeq(_start, _index - _start);
576                     _state = STATE_CHARACTERS;
577                     _index = _start; // Do not keep processing instructions.
578
return _eventType = PROCESSING_INSTRUCTION;
579                 }
580                 break;
581
582             // OPEN_TAG:
583
case STATE_OPEN_TAGxREAD_ELEM_NAME:
584                 while (true) { // Read element name all at once.
585

586                     if (c < '@') { // Else avoid multiple checks.
587
if (c == '>') {
588                             _qName = newSeq(_start, --_index - _start);
589                             _start = _index;
590                             _state = STATE_CHARACTERS;
591                             processStartTag();
592                             _isEmpty = false;
593                             return _eventType = START_ELEMENT;
594                         } else if (c == '/') {
595                             _qName = newSeq(_start, --_index - _start);
596                             _start = _index;
597                             _state = STATE_OPEN_TAGxEMPTY_TAG;
598                             break;
599                         } else if (c == ':') {
600                             _prefixSep = _index - 1;
601                         } else if (c <= ' ') {
602                             _qName = newSeq(_start, --_index - _start);
603                             _state = STATE_OPEN_TAGxELEM_NAME_READ;
604                             break;
605                         }
606                     }
607
608                     if (_readIndex >= _readCount)
609                         reloadBuffer();
610                     c = _data[_index++] = _readBuffer[_readIndex++];
611                 }
612                 break;
613
614             case STATE_OPEN_TAGxELEM_NAME_READ:
615                 if (c == '>') {
616                     _start = --_index;
617                     _state = STATE_CHARACTERS;
618                     processStartTag();
619                     _isEmpty = false;
620                     return _eventType = START_ELEMENT;
621                 } else if (c == '/') {
622                     _state = STATE_OPEN_TAGxEMPTY_TAG;
623                 } else if (c > ' ') {
624                     _start = _index - 1; // Includes current character.
625
_attrPrefixSep = -1;
626                     _state = STATE_OPEN_TAGxREAD_ATTR_NAME;
627                 }
628                 break;
629
630             case STATE_OPEN_TAGxREAD_ATTR_NAME:
631                 while (true) { // Read attribute name all at once.
632

633                     if (c < '@') { // Else avoid multiple checks.
634
if (c <= ' ') {
635                             _attrQName = newSeq(_start, --_index - _start);
636                             _state = STATE_OPEN_TAGxATTR_NAME_READ;
637                             break;
638                         } else if (c == '=') {
639                             _attrQName = newSeq(_start, --_index - _start);
640                             _state = STATE_OPEN_TAGxEQUAL_READ;
641                             break;
642                         } else if (c == ':') {
643                             _attrPrefixSep = _index - 1;
644                         }
645                     }
646
647                     if (_readIndex >= _readCount)
648                         reloadBuffer();
649                     _data[_index++] = c = _readBuffer[_readIndex++];
650                 }
651                 break;
652
653             case STATE_OPEN_TAGxATTR_NAME_READ:
654                 if (c == '=') {
655                     --_index;
656                     _state = STATE_OPEN_TAGxEQUAL_READ;
657                 } else if (c > ' ') {
658                     throw new XMLStreamException("'=' expected", _location);
659                 }
660                 break;
661
662             case STATE_OPEN_TAGxEQUAL_READ:
663                 if (c == '\'') {
664                     _start = --_index;
665                     _state = STATE_OPEN_TAGxREAD_ATTR_VALUE_SIMPLE_QUOTE;
666                 } else if (c == '\"') {
667                     _start = --_index;
668                     _state = STATE_OPEN_TAGxREAD_ATTR_VALUE_DOUBLE_QUOTE;
669                 } else if (c > ' ') {
670                     throw new XMLStreamException("Quotes expected", _location);
671                 }
672                 break;
673
674             case STATE_OPEN_TAGxREAD_ATTR_VALUE_SIMPLE_QUOTE:
675                 while (true) { // Read attribute value all at once.
676

677                     if (c == '\'') {
678                         _attrValue = newSeq(_start, --_index - _start);
679                         processAttribute();
680                         _state = STATE_OPEN_TAGxELEM_NAME_READ;
681                         break;
682                     }
683
684                     // Local character reading block.
685
if (_readIndex >= _readCount)
686                         reloadBuffer();
687                     c = _readBuffer[_readIndex++];
688                     if (c == '&')
689                         c = replaceEntity();
690                     _data[_index++] = c;
691                 }
692                 break;
693
694             case STATE_OPEN_TAGxREAD_ATTR_VALUE_DOUBLE_QUOTE:
695                 while (true) { // Read attribute value all at once.
696

697                     if (c == '\"') {
698                         _attrValue = newSeq(_start, --_index - _start);
699                         processAttribute();
700                         _state = STATE_OPEN_TAGxELEM_NAME_READ;
701                         break;
702                     }
703
704                     // Local character reading block.
705
if (_readIndex >= _readCount)
706                         reloadBuffer();
707                     c = _readBuffer[_readIndex++];
708                     if (c == '&')
709                         c = replaceEntity();
710                     _data[_index++] = c;
711                 }
712                 break;
713
714             case STATE_OPEN_TAGxEMPTY_TAG:
715                 if (c == '>') {
716                     _start = --_index;
717                     _state = STATE_CHARACTERS;
718                     processStartTag();
719                     _isEmpty = true;
720                     return _eventType = START_ELEMENT;
721                 } else {
722                     throw new XMLStreamException("'>' expected", _location);
723                 }
724
725                 // CLOSE_TAG:
726
case STATE_CLOSE_TAGxREAD_ELEM_NAME:
727                 while (true) { // Element name can be read all at once.
728

729                     if (c < '@') { // Else avoid multiple checks.
730
if (c == '>') {
731                             _qName = newSeq(_start, --_index - _start);
732                             _start = _index;
733                             _state = STATE_CHARACTERS;
734                             processEndTag();
735                             return _eventType = END_ELEMENT;
736                         } else if (c == ':') {
737                             _prefixSep = _index - 1;
738                         } else if (c <= ' ') {
739                             _qName = newSeq(_start, --_index - _start);
740                             _state = STATE_CLOSE_TAGxELEM_NAME_READ;
741                             break;
742                         }
743                     }
744
745                     if (_readIndex >= _readCount)
746                         reloadBuffer();
747                     c = _data[_index++] = _readBuffer[_readIndex++];
748                 }
749                 break;
750
751             case STATE_CLOSE_TAGxELEM_NAME_READ:
752                 if (c == '>') {
753                     _start = --_index;
754                     _state = STATE_CHARACTERS;
755                     processEndTag();
756                     return _eventType = END_ELEMENT;
757                 } else if (c > ' ') {
758                     throw new XMLStreamException("'>' expected", _location);
759                 }
760                 break;
761
762             default:
763                 throw new XMLStreamException("State unknown: " + _state,
764                         _location);
765             }
766         }
767     }
768
769     // Defines parsing states (keep values close together to avoid lookup).
770
private static final int STATE_CHARACTERS = 1;
771
772     private static final int STATE_MARKUP = 2;
773
774     private static final int STATE_COMMENT = 3;
775
776     private static final int STATE_PI = 4;
777
778     private static final int STATE_CDATA = 5;
779
780     private static final int STATE_OPEN_TAGxREAD_ELEM_NAME = 6;
781
782     private static final int STATE_OPEN_TAGxELEM_NAME_READ = 7;
783
784     private static final int STATE_OPEN_TAGxREAD_ATTR_NAME = 8;
785
786     private static final int STATE_OPEN_TAGxATTR_NAME_READ = 9;
787
788     private static final int STATE_OPEN_TAGxEQUAL_READ = 10;
789
790     private static final int STATE_OPEN_TAGxREAD_ATTR_VALUE_SIMPLE_QUOTE = 11;
791
792     private static final int STATE_OPEN_TAGxREAD_ATTR_VALUE_DOUBLE_QUOTE = 12;
793
794     private static final int STATE_OPEN_TAGxEMPTY_TAG = 13;
795
796     private static final int STATE_CLOSE_TAGxREAD_ELEM_NAME = 14;
797
798     private static final int STATE_CLOSE_TAGxELEM_NAME_READ = 15;
799
800     private static final int STATE_DTD = 16;
801
802     private static final int STATE_DTD_INTERNAL = 17;
803
804     /**
805      * Reloads data buffer.
806      *
807      * @param detectEndOfStream indicates
808      * @return <code>true</code> if the buffer has been reloaded;
809      * <code>false</code> if the end of stream has being reached
810      * and the event type (CHARACTERS or END_DOCUMENT) has been set.
811      */

812     private void reloadBuffer() throws XMLStreamException {
813         _location._column += _readIndex;
814         _location._charactersRead += _readIndex;
815         _readIndex = 0;
816         try {
817             _readCount = _reader.read(_readBuffer, 0, _readBuffer.length);
818             if ((_readCount <= 0)
819                     && ((_nesting != 0) || (_state != STATE_CHARACTERS)))
820                 throw new XMLStreamException("Unexpected end of document",
821                         _location);
822         } catch (IOException JavaDoc e) {
823             throw new XMLStreamException(e);
824         }
825         while ((_index + _readCount) >= _data.length) { // Potential overflow.
826
increaseDataBuffer();
827         }
828     }
829
830     /**
831      * Detects end of stream.
832      *
833      * @return <code>true</code> if end of stream has being reached
834      * and the event type (CHARACTERS or END_DOCUMENT) has been set;
835      * <code>false</code> otherwise.
836      */

837     private boolean isEndOfStream() throws XMLStreamException {
838         if (_readIndex >= _readCount)
839             reloadBuffer();
840         if (_readCount <= 0) {
841             if (_eventType == END_DOCUMENT)
842                 throw new XMLStreamException(
843                         "End document has already been reached");
844             int length = _index - _start - 1;
845             if ((_state == STATE_CHARACTERS) && (length > 0)) { // Flushes trailing characters.
846
if (_charactersPending) {
847                     _text.setArray(_data, _text.offset(), _text.length()
848                             + length); // Coalescing.
849
} else {
850                     _text = newSeq(_start, length);
851                 }
852                 _eventType = CHARACTERS;
853                 _state = STATE_CHARACTERS;
854             } else {
855                 _eventType = END_DOCUMENT;
856                 _state = STATE_CHARACTERS;
857             }
858             return true;
859         }
860         return false;
861     }
862
863     /**
864      * Handles end of line as per XML Spec. 2.11
865      *
866      * @param c the potential end of line character.
867      * @return the replacement character for end of line.
868      */

869     private char handleEndOfLine(char c) throws XMLStreamException {
870         if (c == 0xD) { // Replaces #xD with #xA
871
// Unless next char is #xA, then skip,
872
// #xD#xA will be replaced by #xA
873
if (_readIndex >= _readCount)
874                 reloadBuffer();
875             if ((_readIndex < _readCount) && (_readBuffer[_readIndex] == 0xA))
876                 _readIndex++; // Skips 0xD
877
c = (char) 0xA;
878         }
879         if (c == 0xA) {
880             _location._line++;
881             _location._column = -_readIndex; // column = 0
882
} else if (c == 0x0) {
883             throw new XMLStreamException("Illegal XML character U+0000",
884                     _location);
885         }
886         return c;
887     }
888
889     /**
890      * Replaces an entity if the current state allows it.
891      *
892      * @return the next character after the text replacement or '&' if no
893      * replacement took place.
894      */

895     private char replaceEntity() throws XMLStreamException {
896         if ((_state == STATE_COMMENT) || (_state == STATE_PI)
897                 || (_state == STATE_CDATA))
898             return '&'; // (&2.4)
899

900         int start = _index; // Index of first replacement character.
901
_data[_index++] = '&';
902         while (true) {
903             if (_readIndex >= _readCount)
904                 reloadBuffer();
905             char c = _data[_index++] = _readBuffer[_readIndex++];
906             if (c == ';')
907                 break;
908             if (c <= ' ')
909                 throw new XMLStreamException("';' expected", _location);
910         }
911         // Ensures that the replacement string holds in the data buffer.
912
while (start + _entities.getMaxLength() >= _data.length)
913             increaseDataBuffer();
914
915         // Replaces the entity.
916
int length = _entities.replaceEntity(_data, start, _index - start);
917
918         // Returns the next character after entity unless ampersand.
919
_index = start + length;
920
921         // Local character reading block.
922
if (_readIndex >= _readCount)
923             reloadBuffer();
924         char c = _readBuffer[_readIndex++];
925         return (c == '&') ? (c = replaceEntity()) : c;
926     }
927
928     /**
929      * Processes the attribute just read.
930      */

931     private void processAttribute() throws XMLStreamException {
932         if (_attrPrefixSep < 0) { // No prefix.
933
if (isXMLNS(_attrQName)) { // Sets default namespace.
934
_namespaces.setPrefix(_namespaces._defaultNsPrefix, _attrValue);
935             } else {
936                 _attributes.addAttribute(_attrQName, null, _attrQName,
937                         _attrValue);
938             }
939         } else { // Prefix.
940
final int offset = _attrQName.offset();
941             final int length = _attrQName.length();
942
943             CharArray prefix = newSeq(offset, _attrPrefixSep - offset);
944
945             CharArray localName = newSeq(_attrPrefixSep + 1, offset + length
946                     - _attrPrefixSep - 1);
947
948             if (isXMLNS(prefix)) { // Namespace association.
949
_namespaces.setPrefix(localName, _attrValue);
950             } else {
951                 _attributes.addAttribute(localName, prefix, _attrQName,
952                         _attrValue);
953             }
954         }
955     }
956
957     private static boolean isXMLNS(CharArray chars) {
958         return (chars.length() == 5) && (chars.charAt(0) == 'x')
959                 && (chars.charAt(1) == 'm') && (chars.charAt(2) == 'l')
960                 && (chars.charAt(3) == 'n') && (chars.charAt(4) == 's');
961     }
962
963     private void processEndTag() throws XMLStreamException {
964         if (!_qName.equals(_elemStack[_nesting]))
965             throw new XMLStreamException("Unexpected end tag for " + _qName,
966                     _location);
967     }
968
969     private void processStartTag() throws XMLStreamException {
970         if (++_nesting >= _elemStack.length) {
971             increaseStack();
972         }
973         _elemStack[_nesting] = _qName;
974         _namespaces.push();
975     }
976
977     // Implements Reusable.
978
public void reset() {
979         // Resets all members (alphabetically ordered).
980
_attributes.reset();
981         _attrPrefixSep = 0;
982         _attrQName = null;
983         _attrValue = null;
984         _attrQName = null;
985         _charactersPending = false;
986         _encoding = null;
987         _entities.reset();
988         _eventType = START_DOCUMENT;
989         _index = 0;
990         _isEmpty = false;
991         _location.reset();
992         _namespaces.reset();
993         _objectFactory = null;
994         _prolog = null;
995         _readCount = 0;
996         _reader = null;
997         _nesting = 0;
998         _readIndex = 0;
999         _seqsIndex = 0;
1000        _start = 0;
1001        _startOffset = 0;
1002        _state = STATE_CHARACTERS;
1003        _utf8StreamReader.reset();
1004    }
1005
1006    // Returns a new character sequence from the pool.
1007
private CharArray newSeq(int offset, int length) {
1008        CharArray seq = (_seqsIndex < _seqsCapacity) ? _seqs[_seqsIndex++]
1009                : newSeq2();
1010        return seq.setArray(_data, offset, length);
1011    }
1012
1013    private CharArray newSeq2() {
1014        MemoryArea.getMemoryArea(this).executeInArea(_createSeqLogic);
1015        return _seqs[_seqsIndex++];
1016    }
1017
1018    private final Runnable JavaDoc _createSeqLogic = new Runnable JavaDoc() {
1019        public void run() {
1020            if (_seqsCapacity >= _seqs.length) { // Resizes.
1021
CharArray[] tmp = new CharArray[_seqs.length * 2];
1022                System.arraycopy(_seqs, 0, tmp, 0, _seqs.length);
1023                _seqs = tmp;
1024            }
1025            CharArray seq = new CharArray();
1026            _seqs[_seqsCapacity++] = seq;
1027        }
1028    };
1029
1030    private CharArray[] _seqs = new CharArray[256];
1031
1032    private int _seqsIndex;
1033
1034    private int _seqsCapacity;
1035
1036    // Increases internal data buffer capacity.
1037
private void increaseDataBuffer() {
1038        // Note: The character data at any nesting level is discarded
1039
// only when moving to outer nesting level (due to coalescing).
1040
// This accumulation may cause resize of the data buffer if
1041
// numerous elements at the same nesting level are separated by
1042
// spaces or indentation.
1043
MemoryArea.getMemoryArea(this).executeInArea(new Runnable JavaDoc() {
1044            public void run() {
1045                char[] tmp = new char[_data.length * 2];
1046                javolution.context.LogContext.info(new CharArray(
1047                        "XMLStreamReaderImpl: Data buffer increased to "
1048                                + tmp.length));
1049                System.arraycopy(_data, 0, tmp, 0, _data.length);
1050                _data = tmp;
1051            }
1052        });
1053    }
1054
1055    // Increases statck.
1056
private void increaseStack() {
1057        MemoryArea.getMemoryArea(this).executeInArea(new Runnable JavaDoc() {
1058            public void run() {
1059                CharArray[] tmp = new CharArray[_elemStack.length * 2];
1060                javolution.context.LogContext.info(new CharArray(
1061                        "XMLStreamReaderImpl: CharArray stack increased to "
1062                                + tmp.length));
1063                System.arraycopy(_elemStack, 0, tmp, 0, _elemStack.length);
1064                _elemStack = tmp;
1065            }
1066        });
1067    }
1068
1069    /**
1070     * This inner class represents the parser location.
1071     */

1072    private final class LocationImpl implements Location, Reusable {
1073
1074        int _column;
1075
1076        int _line;
1077
1078        int _charactersRead;
1079
1080        public int getLineNumber() {
1081            return _line + 1;
1082        }
1083
1084        public int getColumnNumber() {
1085            return _column + _readIndex;
1086        }
1087
1088        public int getCharacterOffset() {
1089            return _charactersRead + _readIndex;
1090        }
1091
1092        public String JavaDoc getPublicId() {
1093            return null; // Not available.
1094
}
1095
1096        public String JavaDoc getSystemId() {
1097            return null; // Not available.
1098
}
1099
1100        public String JavaDoc toString() {
1101            return "Line " + getLineNumber() + ", Column " + getColumnNumber();
1102        }
1103
1104        public void reset() {
1105            _line = 0;
1106            _column = 0;
1107            _charactersRead = 0;
1108        }
1109    }
1110
1111    //////////////////////////////////////////
1112
// Implements XMLStreamReader Interface //
1113
//////////////////////////////////////////
1114

1115    // Implements XMLStreamReader Interface.
1116
public void require(int type, CharSequence JavaDoc namespaceURI,
1117            CharSequence JavaDoc localName) throws XMLStreamException {
1118        if (_eventType != type)
1119            throw new XMLStreamException("Expected event: "
1120                    + NAMES_OF_EVENTS[type] + ", found event: "
1121                    + NAMES_OF_EVENTS[_eventType]);
1122        if ((namespaceURI != null) && !getNamespaceURI().equals(namespaceURI))
1123            throw new XMLStreamException("Expected namespace URI: "
1124                    + namespaceURI + ", found: " + getNamespaceURI());
1125        if ((localName != null) && !getLocalName().equals(localName))
1126            throw new XMLStreamException("Expected local name: " + localName
1127                    + ", found: " + getLocalName());
1128    }
1129
1130    // Implements XMLStreamReader Interface.
1131
public CharArray getElementText() throws XMLStreamException {
1132        // Derived from interface specification code.
1133
if (getEventType() != XMLStreamConstants.START_ELEMENT) {
1134            throw new XMLStreamException(
1135                    "Parser must be on START_ELEMENT to read next text",
1136                    getLocation());
1137        }
1138        CharArray text = null;
1139        int eventType = next();
1140        while (eventType != XMLStreamConstants.END_ELEMENT) {
1141            if (eventType == XMLStreamConstants.CHARACTERS) {
1142                if (text == null) {
1143                    text = getText();
1144                } else { // Merge (adjacent text, comments and PI are not kept).
1145
text.setArray(_data, text.offset(), text.length()
1146                            + getText().length());
1147                }
1148            } else if (eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
1149                    || eventType == XMLStreamConstants.COMMENT) {
1150                // Skips (not kept).
1151
} else if (eventType == XMLStreamConstants.END_DOCUMENT) {
1152                throw new XMLStreamException(
1153                        "Unexpected end of document when reading element text content",
1154                        getLocation());
1155            } else if (eventType == XMLStreamConstants.START_ELEMENT) {
1156                throw new XMLStreamException(
1157                        "Element text content may not contain START_ELEMENT",
1158                        getLocation());
1159            } else {
1160                throw new XMLStreamException("Unexpected event type "
1161                        + NAMES_OF_EVENTS[eventType], getLocation());
1162            }
1163            eventType = next();
1164        }
1165        return (text != null) ? text : newSeq(0, 0);
1166    }
1167
1168    // Implements XMLStreamReader Interface.
1169
public Object JavaDoc getProperty(String JavaDoc name) throws IllegalArgumentException JavaDoc {
1170        if (name.equals(XMLInputFactory.IS_COALESCING)) {
1171            return new Boolean JavaDoc(true);
1172        } else if (name.equals(XMLInputFactory.ENTITIES)) {
1173            return _entities.getEntitiesMapping();
1174        } else {
1175            throw new IllegalArgumentException JavaDoc("Property: " + name
1176                    + " not supported");
1177        }
1178    }
1179
1180    // Implements XMLStreamReader Interface.
1181
public void close() throws XMLStreamException {
1182        if (_objectFactory != null) {
1183            _objectFactory.recycle(this); // Automatic reset.
1184
} else {
1185            reset();
1186        }
1187    }
1188
1189    public int getAttributeCount() {
1190        if (_eventType != XMLStreamConstants.START_ELEMENT)
1191            throw illegalState("Not a start element");
1192        return _attributes.getLength();
1193    }
1194
1195    public CharArray getAttributeLocalName(int index) {
1196        if (_eventType != XMLStreamConstants.START_ELEMENT)
1197            throw illegalState("Not a start element");
1198        return _attributes.getLocalName(index);
1199    }
1200
1201    public CharArray getAttributeNamespace(int index) {
1202        if (_eventType != XMLStreamConstants.START_ELEMENT)
1203            throw illegalState("Not a start element");
1204        CharArray prefix = _attributes.getPrefix(index);
1205        return (prefix == null) ? null : _namespaces.getNamespaceURI(prefix);
1206    }
1207
1208    public CharArray getAttributePrefix(int index) {
1209        if (_eventType != XMLStreamConstants.START_ELEMENT)
1210            throw illegalState("Not a start element");
1211        return _attributes.getPrefix(index);
1212    }
1213
1214    public CharArray getAttributeType(int index) {
1215        if (_eventType != XMLStreamConstants.START_ELEMENT)
1216            throw illegalState("Not a start element");
1217        return _attributes.getType(index);
1218    }
1219
1220    public CharArray getAttributeValue(CharSequence JavaDoc uri, CharSequence JavaDoc localName) {
1221        if (_eventType != XMLStreamConstants.START_ELEMENT)
1222            throw illegalState("Not a start element");
1223        return (uri == null) ? _attributes.getValue(localName) : _attributes
1224                .getValue(uri, localName);
1225    }
1226
1227    public CharArray getAttributeValue(int index) {
1228        if (_eventType != XMLStreamConstants.START_ELEMENT)
1229            throw illegalState("Not a start element");
1230        return _attributes.getValue(index);
1231    }
1232
1233    public CharArray getCharacterEncodingScheme() {
1234        return readPrologAttribute(ENCODING);
1235    }
1236
1237    private static final CharArray ENCODING = new CharArray("encoding");
1238
1239    public String JavaDoc getEncoding() {
1240        return _encoding;
1241    }
1242
1243    public int getEventType() {
1244        return _eventType;
1245    }
1246
1247    public CharArray getLocalName() {
1248        if ((_eventType != XMLStreamConstants.START_ELEMENT)
1249                && (_eventType != XMLStreamConstants.END_ELEMENT))
1250            throw illegalState("Not a start or end element");
1251        if (_prefixSep < 0)
1252            return _qName;
1253        CharArray localName = newSeq(_prefixSep + 1, _qName.offset()
1254                + _qName.length() - _prefixSep - 1);
1255        return localName;
1256    }
1257
1258    public Location getLocation() {
1259        return _location;
1260    }
1261
1262    public int getNamespaceCount() {
1263        if ((_eventType != XMLStreamConstants.START_ELEMENT)
1264                && (_eventType != XMLStreamConstants.END_ELEMENT))
1265            throw illegalState("Not a start or end element");
1266        return _namespaces._namespacesCount[_nesting];
1267    }
1268
1269    public CharArray getNamespacePrefix(int index) {
1270        if ((_eventType != XMLStreamConstants.START_ELEMENT)
1271                && (_eventType != XMLStreamConstants.END_ELEMENT))
1272            throw illegalState("Not a start or end element");
1273        return _namespaces._prefixes[index];
1274    }
1275
1276    public CharArray getNamespaceURI(CharSequence JavaDoc prefix) {
1277        if ((_eventType != XMLStreamConstants.START_ELEMENT)
1278                && (_eventType != XMLStreamConstants.END_ELEMENT))
1279            throw illegalState("Not a start or end element");
1280        return _namespaces.getNamespaceURI(prefix);
1281    }
1282
1283    public CharArray getNamespaceURI(int index) {
1284        if ((_eventType != XMLStreamConstants.START_ELEMENT)
1285                && (_eventType != XMLStreamConstants.END_ELEMENT))
1286            throw illegalState("Not a start or end element");
1287        return _namespaces._namespaces[index];
1288    }
1289
1290    public NamespaceContext getNamespaceContext() {
1291        return _namespaces;
1292    }
1293
1294    public CharArray getNamespaceURI() {
1295        if ((_eventType != XMLStreamConstants.START_ELEMENT)
1296                && (_eventType != XMLStreamConstants.END_ELEMENT))
1297            throw illegalState("Not a start or end element");
1298        CharArray prefix = getPrefix();
1299        return (prefix != null) ? getNamespaceURI(prefix) : null;
1300    }
1301
1302    public CharArray getPrefix() {
1303        if ((_eventType != XMLStreamConstants.START_ELEMENT)
1304                && (_eventType != XMLStreamConstants.END_ELEMENT))
1305            throw illegalState("Not a start or end element");
1306        if (_prefixSep < 0)
1307            return null;
1308        int offset = _qName.offset();
1309        CharArray prefix = newSeq(offset, _prefixSep - offset);
1310        return prefix;
1311    }
1312
1313    public CharArray getPIData() {
1314        if (_eventType != XMLStreamConstants.PROCESSING_INSTRUCTION)
1315            throw illegalState("Not a processing instruction");
1316        int offset = _text.offsetOf(' ') + 1;
1317        CharArray piData = newSeq(offset, _text.length() - offset);
1318        return piData;
1319    }
1320
1321    public CharArray getPITarget() {
1322        if (_eventType != XMLStreamConstants.PROCESSING_INSTRUCTION)
1323            throw illegalState("Not a processing instruction");
1324        CharArray piTarget = newSeq(_text.offset(), _text.offsetOf(' '));
1325        return piTarget;
1326    }
1327
1328    public CharArray getText() {
1329        if ((_eventType != XMLStreamConstants.CHARACTERS)
1330                && (_eventType != XMLStreamConstants.COMMENT)
1331                && (_eventType != XMLStreamConstants.DTD))
1332            throw illegalState("Not a text event");
1333        return _text;
1334    }
1335
1336    public char[] getTextCharacters() {
1337        return getText().array();
1338    }
1339
1340    public int getTextCharacters(int sourceStart, char[] target,
1341            int targetStart, int length) throws XMLStreamException {
1342        CharArray text = getText();
1343        int copyLength = Math.min(length, text.length());
1344        System.arraycopy(text.array(), sourceStart + text.offset(), target,
1345                targetStart, copyLength);
1346        return copyLength;
1347    }
1348
1349    public int getTextLength() {
1350        return getText().length();
1351    }
1352
1353    public int getTextStart() {
1354        return getText().offset();
1355    }
1356
1357    public CharArray getVersion() {
1358        return readPrologAttribute(VERSION);
1359    }
1360
1361    private static final CharArray VERSION = new CharArray("version");
1362
1363    public boolean isStandalone() {
1364        CharArray standalone = readPrologAttribute(STANDALONE);
1365        return (standalone != null) ? standalone.equals("no") : true;
1366    }
1367
1368    public boolean standaloneSet() {
1369        return readPrologAttribute(STANDALONE) != null;
1370    }
1371
1372    private static final CharArray STANDALONE = new CharArray("standalone");
1373
1374    public boolean hasName() {
1375        return (_eventType == XMLStreamConstants.START_ELEMENT)
1376                || (_eventType == XMLStreamConstants.END_ELEMENT);
1377    }
1378
1379    public boolean hasNext() throws XMLStreamException {
1380        return _eventType != XMLStreamConstants.END_DOCUMENT;
1381    }
1382
1383    public boolean hasText() {
1384        return ((_eventType == XMLStreamConstants.CHARACTERS)
1385                || (_eventType == XMLStreamConstants.COMMENT) || (_eventType == XMLStreamConstants.DTD))
1386                && (_text.length() > 0);
1387    }
1388
1389    public boolean isAttributeSpecified(int index) {
1390        if (_eventType != XMLStreamConstants.START_ELEMENT)
1391            throw new IllegalStateException JavaDoc("Not a start element");
1392        return _attributes.getValue(index) != null;
1393    }
1394
1395    public boolean isCharacters() {
1396        return _eventType == XMLStreamConstants.CHARACTERS;
1397    }
1398
1399    public boolean isEndElement() {
1400        return _eventType == XMLStreamConstants.END_ELEMENT;
1401    }
1402
1403    public boolean isStartElement() {
1404        return _eventType == XMLStreamConstants.START_ELEMENT;
1405    }
1406
1407    public boolean isWhiteSpace() {
1408        if (isCharacters()) {
1409            char[] chars = _text.array();
1410            for (int i = _text.offset(), end = _text.offset() + _text.length(); i < end;) {
1411                if (!isWhiteSpace(chars[i++]))
1412                    return false;
1413            }
1414            return true;
1415        }
1416        return false;
1417    }
1418
1419    // Whitespaces according to XML 1.1 Specification.
1420
private static boolean isWhiteSpace(char c) {
1421        return (c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA);
1422    }
1423
1424    public int nextTag() throws XMLStreamException {
1425        int eventType = next();
1426        while (eventType == XMLStreamConstants.COMMENT
1427                || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
1428                || (eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace())) {
1429            eventType = next();
1430        }
1431        if (eventType != XMLStreamConstants.START_ELEMENT
1432                && eventType != XMLStreamConstants.END_ELEMENT)
1433            throw new XMLStreamException("Tag expected (but found "
1434                    + NAMES_OF_EVENTS[_eventType] + ")");
1435        return eventType;
1436    }
1437
1438    private IllegalStateException JavaDoc illegalState(String JavaDoc msg) {
1439        return new IllegalStateException JavaDoc(msg + " ("
1440                + NAMES_OF_EVENTS[_eventType] + ")");
1441    }
1442
1443    private String JavaDoc detectEncoding(InputStream JavaDoc input) throws XMLStreamException {
1444        // Autodetect encoding (see http://en.wikipedia.org/wiki/UTF-16)
1445
int byte0;
1446        try {
1447            byte0 = input.read();
1448        } catch (IOException JavaDoc e) {
1449            throw new XMLStreamException(e);
1450        }
1451        if (byte0 == -1)
1452            throw new XMLStreamException("Premature End-Of-File");
1453        if (byte0 == '<') { // UTF-8 or compatible encoding.
1454
_readBuffer[_startOffset++] = '<';
1455            return "UTF-8";
1456        } else {
1457            int byte1;
1458            try {
1459                byte1 = input.read();
1460            } catch (IOException JavaDoc e) {
1461                throw new XMLStreamException(e);
1462            }
1463            if (byte1 == -1)
1464                throw new XMLStreamException("Premature End-Of-File");
1465            if ((byte0 == 0) && (byte1 == '<')) { // UTF-16 BIG ENDIAN
1466
_readBuffer[_startOffset++] = '<';
1467                return "UTF-16BE";
1468            } else if ((byte0 == '<') && (byte1 == 0)) { // UTF-16 LITTLE ENDIAN
1469
_readBuffer[_startOffset++] = '<';
1470                return "UTF-16LE";
1471            } else if ((byte0 == 0xFF) && (byte1 == 0xFE)) { // BOM for UTF-16 LITTLE ENDIAN
1472
return "UTF-16";
1473            } else if ((byte0 == 0xFE) && (byte1 == 0xFF)) { // BOM for UTF-16 BIG ENDIAN
1474
return "UTF-16";
1475            } else { // Encoding unknown (or no prolog) assumes UTF-8
1476
_readBuffer[_startOffset++] = (char) byte0;
1477                _readBuffer[_startOffset++] = (char) byte1;
1478                return "UTF-8";
1479            }
1480        }
1481    }
1482
1483    private final CharArray readPrologAttribute(CharSequence JavaDoc name) {
1484        if (_prolog == null)
1485            return null;
1486        final int READ_EQUAL = 0;
1487        final int READ_QUOTE = 1;
1488        final int VALUE_SIMPLE_QUOTE = 2;
1489        final int VALUE_DOUBLE_QUOTE = 3;
1490
1491        int i = _prolog.offsetOf(name);
1492        if (i >= 0) {
1493            int maxIndex = _prolog.offset() + _prolog.length();
1494            i += name.length();
1495            int state = READ_EQUAL;
1496            int valueOffset = 0;
1497            while (i < maxIndex) {
1498                char c = _prolog.array()[i++];
1499                switch (state) {
1500                case READ_EQUAL:
1501                    if (c == '=') {
1502                        state = READ_QUOTE;
1503                    }
1504                    break;
1505                case READ_QUOTE:
1506                    if (c == '"') {
1507                        state = VALUE_DOUBLE_QUOTE;
1508                        valueOffset = i;
1509                    } else if (c == '\'') {
1510                        state = VALUE_SIMPLE_QUOTE;
1511                        valueOffset = i;
1512                    }
1513                    break;
1514                case VALUE_SIMPLE_QUOTE:
1515                    if (c == '\'')
1516                        return newSeq(valueOffset, i - valueOffset - 1);
1517                    break;
1518                case VALUE_DOUBLE_QUOTE:
1519                    if (c == '"')
1520                        return newSeq(valueOffset, i - valueOffset - 1);
1521                    break;
1522                }
1523            }
1524        }
1525        return null;
1526    }
1527}
Popular Tags