Tue, 06 Mar 2012 16:09:35 -0800
7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom
1 /*
2 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.xml.internal.stream.buffer.stax;
28 import com.sun.xml.internal.stream.buffer.AbstractProcessor;
29 import com.sun.xml.internal.stream.buffer.AttributesHolder;
30 import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
31 import com.sun.xml.internal.stream.buffer.XMLStreamBufferMark;
32 import com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx;
33 import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx;
35 import javax.xml.XMLConstants;
36 import javax.xml.namespace.QName;
37 import javax.xml.stream.Location;
38 import javax.xml.stream.XMLStreamException;
39 import javax.xml.stream.XMLStreamReader;
40 import java.util.*;
42 /**
43 * A processor of a {@link XMLStreamBuffer} that reads the XML infoset as
44 * {@link XMLStreamReader}.
45 *
46 * <p>
47 * Because of {@link XMLStreamReader} design, this processor always produce
48 * a full document infoset, even if the buffer just contains a fragment.
49 *
50 * <p>
51 * When {@link XMLStreamBuffer} contains a multiple tree (AKA "forest"),
52 * {@link XMLStreamReader} will behave as if there are multiple root elements
53 * (so you'll see {@link #START_ELEMENT} event where you'd normally expect
54 * {@link #END_DOCUMENT}.)
55 *
56 * @author Paul.Sandoz@Sun.Com
57 * @author K.Venugopal@sun.com
58 */
59 public class StreamReaderBufferProcessor extends AbstractProcessor implements XMLStreamReaderEx {
60 private static final int CACHE_SIZE = 16;
62 // Stack to hold element and namespace declaration information
63 protected ElementStackEntry[] _stack = new ElementStackEntry[CACHE_SIZE];
64 /** The top-most active entry of the {@link #_stack}. */
65 protected ElementStackEntry _stackTop;
66 /** The element depth that we are in. Used to determine when we are done with a tree. */
67 protected int _depth;
69 // Arrays to hold all namespace declarations
70 /**
71 * Namespace prefixes. Can be empty but not null.
72 */
73 protected String[] _namespaceAIIsPrefix = new String[CACHE_SIZE];
74 protected String[] _namespaceAIIsNamespaceName = new String[CACHE_SIZE];
75 protected int _namespaceAIIsEnd;
77 // Internal namespace context implementation
78 protected InternalNamespaceContext _nsCtx = new InternalNamespaceContext();
80 // The current event type
81 protected int _eventType;
83 /**
84 * Holder of the attributes.
85 *
86 * Be careful that this follows the SAX convention of using "" instead of null.
87 */
88 protected AttributesHolder _attributeCache;
90 // Characters as a CharSequence
91 protected CharSequence _charSequence;
93 // Characters as a char array with offset and length
94 protected char[] _characters;
95 protected int _textOffset;
96 protected int _textLen;
98 protected String _piTarget;
99 protected String _piData;
101 //
102 // Represents the parser state wrt the end of parsing.
103 //
104 /**
105 * The parser is in the middle of parsing a document,
106 * with no end in sight.
107 */
108 private static final int PARSING = 1;
109 /**
110 * The parser has already reported the {@link #END_ELEMENT},
111 * and we are parsing a fragment. We'll report {@link #END_DOCUMENT}
112 * next and be done.
113 */
114 private static final int PENDING_END_DOCUMENT = 2;
115 /**
116 * The parser has reported the {@link #END_DOCUMENT} event,
117 * so we are really done parsing.
118 */
119 private static final int COMPLETED = 3;
121 /**
122 * True if processing is complete.
123 */
124 private int _completionState;
126 public StreamReaderBufferProcessor() {
127 for (int i=0; i < _stack.length; i++){
128 _stack[i] = new ElementStackEntry();
129 }
131 _attributeCache = new AttributesHolder();
132 }
134 public StreamReaderBufferProcessor(XMLStreamBuffer buffer) throws XMLStreamException {
135 this();
136 setXMLStreamBuffer(buffer);
137 }
139 public void setXMLStreamBuffer(XMLStreamBuffer buffer) throws XMLStreamException {
140 setBuffer(buffer,buffer.isFragment());
142 _completionState = PARSING;
143 _namespaceAIIsEnd = 0;
144 _characters = null;
145 _charSequence = null;
146 _eventType = START_DOCUMENT;
147 }
149 /**
150 * Does {@link #nextTag()} and if the parser moved to a new start tag,
151 * returns a {@link XMLStreamBufferMark} that captures the infoset starting
152 * from the newly discovered element.
153 *
154 * <p>
155 * (Ideally we should have a method that works against the current position,
156 * but the way the data structure is read makes this somewhat difficult.)
157 *
158 * This creates a new {@link XMLStreamBufferMark} that shares the underlying
159 * data storage, thus it's fairly efficient.
160 */
161 public XMLStreamBuffer nextTagAndMark() throws XMLStreamException {
162 while (true) {
163 int s = peekStructure();
164 if((s &TYPE_MASK)==T_ELEMENT) {
165 // next is start element.
166 Map<String,String> inscope = new HashMap<String, String>(_namespaceAIIsEnd);
168 for (int i=0 ; i<_namespaceAIIsEnd; i++)
169 inscope.put(_namespaceAIIsPrefix[i],_namespaceAIIsNamespaceName[i]);
171 XMLStreamBufferMark mark = new XMLStreamBufferMark(inscope, this);
172 next();
173 return mark;
174 } else if((s &TYPE_MASK)==T_DOCUMENT) {
175 //move the pointer to next structure.
176 readStructure();
177 //mark the next start element
178 XMLStreamBufferMark mark = new XMLStreamBufferMark(new HashMap<String, String>(_namespaceAIIsEnd), this);
179 next();
180 return mark;
181 }
183 if(next()==END_ELEMENT)
184 return null;
185 }
186 }
188 public Object getProperty(String name) {
189 return null;
190 }
192 public int next() throws XMLStreamException {
193 switch(_completionState) {
194 case COMPLETED:
195 throw new XMLStreamException("Invalid State");
196 case PENDING_END_DOCUMENT:
197 _namespaceAIIsEnd = 0;
198 _completionState = COMPLETED;
199 return _eventType = END_DOCUMENT;
200 }
202 // Pop the stack of elements
203 // This is a post-processing operation
204 // The stack of the element should be poppoed after
205 // the END_ELEMENT event is returned so that the correct element name
206 // and namespace scope is returned
207 switch(_eventType) {
208 case END_ELEMENT:
209 if (_depth > 1) {
210 _depth--;
211 // _depth index is always set to the next free stack entry
212 // to push
213 popElementStack(_depth);
214 } else if (_depth == 1) {
215 _depth--;
216 }
217 }
219 _characters = null;
220 _charSequence = null;
221 while(true) {// loop only if we read STATE_DOCUMENT
222 int eiiState = readEiiState();
223 switch(eiiState) {
224 case STATE_DOCUMENT:
225 // we'll always produce a full document, and we've already report START_DOCUMENT event.
226 // so simply skil this
227 continue;
228 case STATE_ELEMENT_U_LN_QN: {
229 final String uri = readStructureString();
230 final String localName = readStructureString();
231 final String prefix = getPrefixFromQName(readStructureString());
233 processElement(prefix, uri, localName, isInscope(_depth));
234 return _eventType = START_ELEMENT;
235 }
236 case STATE_ELEMENT_P_U_LN:
237 processElement(readStructureString(), readStructureString(), readStructureString(),isInscope(_depth));
238 return _eventType = START_ELEMENT;
239 case STATE_ELEMENT_U_LN:
240 processElement(null, readStructureString(), readStructureString(),isInscope(_depth));
241 return _eventType = START_ELEMENT;
242 case STATE_ELEMENT_LN:
243 processElement(null, null, readStructureString(),isInscope(_depth));
244 return _eventType = START_ELEMENT;
245 case STATE_TEXT_AS_CHAR_ARRAY_SMALL:
246 _textLen = readStructure();
247 _textOffset = readContentCharactersBuffer(_textLen);
248 _characters = _contentCharactersBuffer;
250 return _eventType = CHARACTERS;
251 case STATE_TEXT_AS_CHAR_ARRAY_MEDIUM:
252 _textLen = readStructure16();
253 _textOffset = readContentCharactersBuffer(_textLen);
254 _characters = _contentCharactersBuffer;
256 return _eventType = CHARACTERS;
257 case STATE_TEXT_AS_CHAR_ARRAY_COPY:
258 _characters = readContentCharactersCopy();
259 _textLen = _characters.length;
260 _textOffset = 0;
262 return _eventType = CHARACTERS;
263 case STATE_TEXT_AS_STRING:
264 _eventType = CHARACTERS;
265 _charSequence = readContentString();
267 return _eventType = CHARACTERS;
268 case STATE_TEXT_AS_OBJECT:
269 _eventType = CHARACTERS;
270 _charSequence = (CharSequence)readContentObject();
272 return _eventType = CHARACTERS;
273 case STATE_COMMENT_AS_CHAR_ARRAY_SMALL:
274 _textLen = readStructure();
275 _textOffset = readContentCharactersBuffer(_textLen);
276 _characters = _contentCharactersBuffer;
278 return _eventType = COMMENT;
279 case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM:
280 _textLen = readStructure16();
281 _textOffset = readContentCharactersBuffer(_textLen);
282 _characters = _contentCharactersBuffer;
284 return _eventType = COMMENT;
285 case STATE_COMMENT_AS_CHAR_ARRAY_COPY:
286 _characters = readContentCharactersCopy();
287 _textLen = _characters.length;
288 _textOffset = 0;
290 return _eventType = COMMENT;
291 case STATE_COMMENT_AS_STRING:
292 _charSequence = readContentString();
294 return _eventType = COMMENT;
295 case STATE_PROCESSING_INSTRUCTION:
296 _piTarget = readStructureString();
297 _piData = readStructureString();
299 return _eventType = PROCESSING_INSTRUCTION;
300 case STATE_END:
301 if (_depth > 1) {
302 // normal case
303 return _eventType = END_ELEMENT;
304 } else if (_depth == 1) {
305 // this is the last end element for the current tree.
306 if (_fragmentMode) {
307 if(--_treeCount==0) // is this the last tree in the forest?
308 _completionState = PENDING_END_DOCUMENT;
309 }
310 return _eventType = END_ELEMENT;
311 } else {
312 // this only happens when we are processing a full document
313 // and we hit the "end of document" marker
314 _namespaceAIIsEnd = 0;
315 _completionState = COMPLETED;
316 return _eventType = END_DOCUMENT;
317 }
318 default:
319 throw new XMLStreamException("Internal XSB error: Invalid State="+eiiState);
320 }
321 // this should be unreachable
322 }
323 }
325 public final void require(int type, String namespaceURI, String localName) throws XMLStreamException {
326 if( type != _eventType) {
327 throw new XMLStreamException("");
328 }
329 if( namespaceURI != null && !namespaceURI.equals(getNamespaceURI())) {
330 throw new XMLStreamException("");
331 }
332 if(localName != null && !localName.equals(getLocalName())) {
333 throw new XMLStreamException("");
334 }
335 }
337 public final String getElementTextTrim() throws XMLStreamException {
338 // TODO getElementText* methods more efficiently
339 return getElementText().trim();
340 }
342 public final String getElementText() throws XMLStreamException {
343 if(_eventType != START_ELEMENT) {
344 throw new XMLStreamException("");
345 }
347 next();
348 return getElementText(true);
349 }
351 public final String getElementText(boolean startElementRead) throws XMLStreamException {
352 if (!startElementRead) {
353 throw new XMLStreamException("");
354 }
356 int eventType = getEventType();
357 StringBuffer content = new StringBuffer();
358 while(eventType != END_ELEMENT ) {
359 if(eventType == CHARACTERS
360 || eventType == CDATA
361 || eventType == SPACE
362 || eventType == ENTITY_REFERENCE) {
363 content.append(getText());
364 } else if(eventType == PROCESSING_INSTRUCTION
365 || eventType == COMMENT) {
366 // skipping
367 } else if(eventType == END_DOCUMENT) {
368 throw new XMLStreamException("");
369 } else if(eventType == START_ELEMENT) {
370 throw new XMLStreamException("");
371 } else {
372 throw new XMLStreamException("");
373 }
374 eventType = next();
375 }
376 return content.toString();
377 }
379 public final int nextTag() throws XMLStreamException {
380 next();
381 return nextTag(true);
382 }
384 public final int nextTag(boolean currentTagRead) throws XMLStreamException {
385 int eventType = getEventType();
386 if (!currentTagRead) {
387 eventType = next();
388 }
389 while((eventType == CHARACTERS && isWhiteSpace()) // skip whitespace
390 || (eventType == CDATA && isWhiteSpace())
391 || eventType == SPACE
392 || eventType == PROCESSING_INSTRUCTION
393 || eventType == COMMENT) {
394 eventType = next();
395 }
396 if (eventType != START_ELEMENT && eventType != END_ELEMENT) {
397 throw new XMLStreamException("");
398 }
399 return eventType;
400 }
402 public final boolean hasNext() {
403 return (_eventType != END_DOCUMENT);
404 }
406 public void close() throws XMLStreamException {
407 }
409 public final boolean isStartElement() {
410 return (_eventType == START_ELEMENT);
411 }
413 public final boolean isEndElement() {
414 return (_eventType == END_ELEMENT);
415 }
417 public final boolean isCharacters() {
418 return (_eventType == CHARACTERS);
419 }
421 public final boolean isWhiteSpace() {
422 if(isCharacters() || (_eventType == CDATA)){
423 char [] ch = this.getTextCharacters();
424 int start = this.getTextStart();
425 int length = this.getTextLength();
426 for (int i = start; i < length; i++){
427 final char c = ch[i];
428 if (!(c == 0x20 || c == 0x9 || c == 0xD || c == 0xA))
429 return false;
430 }
431 return true;
432 }
433 return false;
434 }
436 public final String getAttributeValue(String namespaceURI, String localName) {
437 if (_eventType != START_ELEMENT) {
438 throw new IllegalStateException("");
439 }
441 if (namespaceURI == null) {
442 // Set to the empty string to be compatible with the
443 // org.xml.sax.Attributes interface
444 namespaceURI = "";
445 }
447 return _attributeCache.getValue(namespaceURI, localName);
448 }
450 public final int getAttributeCount() {
451 if (_eventType != START_ELEMENT) {
452 throw new IllegalStateException("");
453 }
455 return _attributeCache.getLength();
456 }
458 public final javax.xml.namespace.QName getAttributeName(int index) {
459 if (_eventType != START_ELEMENT) {
460 throw new IllegalStateException("");
461 }
463 final String prefix = _attributeCache.getPrefix(index);
464 final String localName = _attributeCache.getLocalName(index);
465 final String uri = _attributeCache.getURI(index);
466 return new QName(uri,localName,prefix);
467 }
470 public final String getAttributeNamespace(int index) {
471 if (_eventType != START_ELEMENT) {
472 throw new IllegalStateException("");
473 }
474 return fixEmptyString(_attributeCache.getURI(index));
475 }
477 public final String getAttributeLocalName(int index) {
478 if (_eventType != START_ELEMENT) {
479 throw new IllegalStateException("");
480 }
481 return _attributeCache.getLocalName(index);
482 }
484 public final String getAttributePrefix(int index) {
485 if (_eventType != START_ELEMENT) {
486 throw new IllegalStateException("");
487 }
488 return fixEmptyString(_attributeCache.getPrefix(index));
489 }
491 public final String getAttributeType(int index) {
492 if (_eventType != START_ELEMENT) {
493 throw new IllegalStateException("");
494 }
495 return _attributeCache.getType(index);
496 }
498 public final String getAttributeValue(int index) {
499 if (_eventType != START_ELEMENT) {
500 throw new IllegalStateException("");
501 }
503 return _attributeCache.getValue(index);
504 }
506 public final boolean isAttributeSpecified(int index) {
507 return false;
508 }
510 public final int getNamespaceCount() {
511 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) {
512 return _stackTop.namespaceAIIsEnd - _stackTop.namespaceAIIsStart;
513 }
515 throw new IllegalStateException("");
516 }
518 public final String getNamespacePrefix(int index) {
519 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) {
520 return _namespaceAIIsPrefix[_stackTop.namespaceAIIsStart + index];
521 }
523 throw new IllegalStateException("");
524 }
526 public final String getNamespaceURI(int index) {
527 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) {
528 return _namespaceAIIsNamespaceName[_stackTop.namespaceAIIsStart + index];
529 }
531 throw new IllegalStateException("");
532 }
534 public final String getNamespaceURI(String prefix) {
535 return _nsCtx.getNamespaceURI(prefix);
536 }
538 public final NamespaceContextEx getNamespaceContext() {
539 return _nsCtx;
540 }
542 public final int getEventType() {
543 return _eventType;
544 }
546 public final String getText() {
547 if (_characters != null) {
548 String s = new String(_characters, _textOffset, _textLen);
549 _charSequence = s;
550 return s;
551 } else if (_charSequence != null) {
552 return _charSequence.toString();
553 } else {
554 throw new IllegalStateException();
555 }
556 }
558 public final char[] getTextCharacters() {
559 if (_characters != null) {
560 return _characters;
561 } else if (_charSequence != null) {
562 // TODO try to avoid creation of a temporary String for some
563 // CharSequence implementations
564 _characters = _charSequence.toString().toCharArray();
565 _textLen = _characters.length;
566 _textOffset = 0;
567 return _characters;
568 } else {
569 throw new IllegalStateException();
570 }
571 }
573 public final int getTextStart() {
574 if (_characters != null) {
575 return _textOffset;
576 } else if (_charSequence != null) {
577 return 0;
578 } else {
579 throw new IllegalStateException();
580 }
581 }
583 public final int getTextLength() {
584 if (_characters != null) {
585 return _textLen;
586 } else if (_charSequence != null) {
587 return _charSequence.length();
588 } else {
589 throw new IllegalStateException();
590 }
591 }
593 public final int getTextCharacters(int sourceStart, char[] target,
594 int targetStart, int length) throws XMLStreamException {
595 if (_characters != null) {
596 } else if (_charSequence != null) {
597 _characters = _charSequence.toString().toCharArray();
598 _textLen = _characters.length;
599 _textOffset = 0;
600 } else {
601 throw new IllegalStateException("");
602 }
604 try {
605 int remaining = _textLen - sourceStart;
606 int len = remaining > length ? length : remaining;
607 sourceStart += _textOffset;
608 System.arraycopy(_characters, sourceStart, target, targetStart, len);
609 return len;
610 } catch (IndexOutOfBoundsException e) {
611 throw new XMLStreamException(e);
612 }
613 }
615 private class CharSequenceImpl implements CharSequence {
616 private final int _offset;
617 private final int _length;
619 CharSequenceImpl(int offset, int length) {
620 _offset = offset;
621 _length = length;
622 }
624 public int length() {
625 return _length;
626 }
628 public char charAt(int index) {
629 if (index >= 0 && index < _textLen) {
630 return _characters[_textOffset + index];
631 } else {
632 throw new IndexOutOfBoundsException();
633 }
634 }
636 public CharSequence subSequence(int start, int end) {
637 final int length = end - start;
638 if (end < 0 || start < 0 || end > length || start > end) {
639 throw new IndexOutOfBoundsException();
640 }
642 return new CharSequenceImpl(_offset + start, length);
643 }
645 public String toString() {
646 return new String(_characters, _offset, _length);
647 }
648 }
650 public final CharSequence getPCDATA() {
651 if (_characters != null) {
652 return new CharSequenceImpl(_textOffset, _textLen);
653 } else if (_charSequence != null) {
654 return _charSequence;
655 } else {
656 throw new IllegalStateException();
657 }
658 }
660 public final String getEncoding() {
661 return "UTF-8";
662 }
664 public final boolean hasText() {
665 return (_characters != null || _charSequence != null);
666 }
668 public final Location getLocation() {
669 return new DummyLocation();
670 }
672 public final boolean hasName() {
673 return (_eventType == START_ELEMENT || _eventType == END_ELEMENT);
674 }
676 public final QName getName() {
677 return _stackTop.getQName();
678 }
680 public final String getLocalName() {
681 return _stackTop.localName;
682 }
684 public final String getNamespaceURI() {
685 return _stackTop.uri;
686 }
688 public final String getPrefix() {
689 return _stackTop.prefix;
691 }
693 public final String getVersion() {
694 return "1.0";
695 }
697 public final boolean isStandalone() {
698 return false;
699 }
701 public final boolean standaloneSet() {
702 return false;
703 }
705 public final String getCharacterEncodingScheme() {
706 return "UTF-8";
707 }
709 public final String getPITarget() {
710 if (_eventType == PROCESSING_INSTRUCTION) {
711 return _piTarget;
712 }
713 throw new IllegalStateException("");
714 }
716 public final String getPIData() {
717 if (_eventType == PROCESSING_INSTRUCTION) {
718 return _piData;
719 }
720 throw new IllegalStateException("");
721 }
723 protected void processElement(String prefix, String uri, String localName, boolean inscope) {
724 pushElementStack();
725 _stackTop.set(prefix, uri, localName);
727 _attributeCache.clear();
729 int item = peekStructure();
730 if ((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE || inscope) {
731 // Skip the namespace declarations on the element
732 // they will have been added already
733 item = processNamespaceAttributes(item, inscope);
734 }
735 if ((item & TYPE_MASK) == T_ATTRIBUTE) {
736 processAttributes(item);
737 }
738 }
740 private boolean isInscope(int depth) {
741 return _buffer.getInscopeNamespaces().size() > 0 && depth ==0;
742 }
744 private void resizeNamespaceAttributes() {
745 final String[] namespaceAIIsPrefix = new String[_namespaceAIIsEnd * 2];
746 System.arraycopy(_namespaceAIIsPrefix, 0, namespaceAIIsPrefix, 0, _namespaceAIIsEnd);
747 _namespaceAIIsPrefix = namespaceAIIsPrefix;
749 final String[] namespaceAIIsNamespaceName = new String[_namespaceAIIsEnd * 2];
750 System.arraycopy(_namespaceAIIsNamespaceName, 0, namespaceAIIsNamespaceName, 0, _namespaceAIIsEnd);
751 _namespaceAIIsNamespaceName = namespaceAIIsNamespaceName;
752 }
754 private int processNamespaceAttributes(int item, boolean inscope){
755 _stackTop.namespaceAIIsStart = _namespaceAIIsEnd;
756 Set<String> prefixSet = inscope ? new HashSet<String>() : Collections.<String>emptySet();
758 while((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE) {
759 if (_namespaceAIIsEnd == _namespaceAIIsPrefix.length) {
760 resizeNamespaceAttributes();
761 }
763 switch(getNIIState(item)){
764 case STATE_NAMESPACE_ATTRIBUTE:
765 // Undeclaration of default namespace
766 _namespaceAIIsPrefix[_namespaceAIIsEnd] =
767 _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = "";
768 if (inscope) {
769 prefixSet.add("");
770 }
771 break;
772 case STATE_NAMESPACE_ATTRIBUTE_P:
773 // Undeclaration of namespace
774 _namespaceAIIsPrefix[_namespaceAIIsEnd] = readStructureString();
775 if (inscope) {
776 prefixSet.add(_namespaceAIIsPrefix[_namespaceAIIsEnd]);
777 }
778 _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = "";
779 break;
780 case STATE_NAMESPACE_ATTRIBUTE_P_U:
781 // Declaration with prefix
782 _namespaceAIIsPrefix[_namespaceAIIsEnd] = readStructureString();
783 if (inscope) {
784 prefixSet.add(_namespaceAIIsPrefix[_namespaceAIIsEnd]);
785 }
786 _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = readStructureString();
787 break;
788 case STATE_NAMESPACE_ATTRIBUTE_U:
789 // Default declaration
790 _namespaceAIIsPrefix[_namespaceAIIsEnd] = "";
791 if (inscope) {
792 prefixSet.add("");
793 }
794 _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = readStructureString();
795 break;
796 }
797 readStructure();
799 item = peekStructure();
800 }
802 if (inscope) {
803 for (Map.Entry<String, String> e : _buffer.getInscopeNamespaces().entrySet()) {
804 String key = fixNull(e.getKey());
805 // If the prefix is already written, do not write the prefix
806 if (!prefixSet.contains(key)) {
807 if (_namespaceAIIsEnd == _namespaceAIIsPrefix.length) {
808 resizeNamespaceAttributes();
809 }
810 _namespaceAIIsPrefix[_namespaceAIIsEnd] = key;
811 _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = e.getValue();
812 }
813 }
814 }
815 _stackTop.namespaceAIIsEnd = _namespaceAIIsEnd;
817 return item;
818 }
820 private static String fixNull(String s) {
821 if (s == null) return "";
822 else return s;
823 }
825 private void processAttributes(int item){
826 do {
827 switch(getAIIState(item)){
828 case STATE_ATTRIBUTE_U_LN_QN: {
829 final String uri = readStructureString();
830 final String localName = readStructureString();
831 final String prefix = getPrefixFromQName(readStructureString());
832 _attributeCache.addAttributeWithPrefix(prefix, uri, localName, readStructureString(), readContentString());
833 break;
834 }
835 case STATE_ATTRIBUTE_P_U_LN:
836 _attributeCache.addAttributeWithPrefix(readStructureString(), readStructureString(), readStructureString(), readStructureString(), readContentString());
837 break;
838 case STATE_ATTRIBUTE_U_LN:
839 // _attributeCache follows SAX convention
840 _attributeCache.addAttributeWithPrefix("", readStructureString(), readStructureString(), readStructureString(), readContentString());
841 break;
842 case STATE_ATTRIBUTE_LN: {
843 _attributeCache.addAttributeWithPrefix("", "", readStructureString(), readStructureString(), readContentString());
844 break;
845 }
846 default :
847 assert false : "Internal XSB Error: wrong attribute state, Item="+item;
848 }
849 readStructure();
851 item = peekStructure();
852 } while((item & TYPE_MASK) == T_ATTRIBUTE);
853 }
855 private void pushElementStack() {
856 if (_depth == _stack.length) {
857 // resize stack
858 ElementStackEntry [] tmp = _stack;
859 _stack = new ElementStackEntry[_stack.length * 3 /2 + 1];
860 System.arraycopy(tmp, 0, _stack, 0, tmp.length);
861 for (int i = tmp.length; i < _stack.length; i++){
862 _stack[i] = new ElementStackEntry();
863 }
864 }
866 _stackTop = _stack[_depth++];
867 }
869 private void popElementStack(int depth) {
870 // _depth is checked outside this method
871 _stackTop = _stack[depth - 1];
872 // Move back the position of the namespace index
873 _namespaceAIIsEnd = _stack[depth].namespaceAIIsStart;
874 }
876 private final class ElementStackEntry {
877 /**
878 * Prefix.
879 * Just like everywhere else in StAX, this can be null but can't be empty.
880 */
881 String prefix;
882 /**
883 * Namespace URI.
884 * Just like everywhere else in StAX, this can be null but can't be empty.
885 */
886 String uri;
887 String localName;
888 QName qname;
890 // Start and end of namespace declarations
891 // in namespace declaration arrays
892 int namespaceAIIsStart;
893 int namespaceAIIsEnd;
895 public void set(String prefix, String uri, String localName) {
896 this.prefix = prefix;
897 this.uri = uri;
898 this.localName = localName;
899 this.qname = null;
901 this.namespaceAIIsStart = this.namespaceAIIsEnd = StreamReaderBufferProcessor.this._namespaceAIIsEnd;
902 }
904 public QName getQName() {
905 if (qname == null) {
906 qname = new QName(fixNull(uri), localName, fixNull(prefix));
907 }
908 return qname;
909 }
911 private String fixNull(String s) {
912 return (s == null) ? "" : s;
913 }
914 }
916 private final class InternalNamespaceContext implements NamespaceContextEx {
917 @SuppressWarnings({"StringEquality"})
918 public String getNamespaceURI(String prefix) {
919 if (prefix == null) {
920 throw new IllegalArgumentException("Prefix cannot be null");
921 }
923 /*
924 * If the buffer was created using string interning
925 * intern the prefix and check for reference equality
926 * rather than using String.equals();
927 */
928 if (_stringInterningFeature) {
929 prefix = prefix.intern();
931 // Find the most recently declared prefix
932 for (int i = _namespaceAIIsEnd - 1; i >=0; i--) {
933 if (prefix == _namespaceAIIsPrefix[i]) {
934 return _namespaceAIIsNamespaceName[i];
935 }
936 }
937 } else {
938 // Find the most recently declared prefix
939 for (int i = _namespaceAIIsEnd - 1; i >=0; i--) {
940 if (prefix.equals(_namespaceAIIsPrefix[i])) {
941 return _namespaceAIIsNamespaceName[i];
942 }
943 }
944 }
946 // Check for XML-based prefixes
947 if (prefix.equals(XMLConstants.XML_NS_PREFIX)) {
948 return XMLConstants.XML_NS_URI;
949 } else if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) {
950 return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
951 }
953 return null;
954 }
956 public String getPrefix(String namespaceURI) {
957 final Iterator i = getPrefixes(namespaceURI);
958 if (i.hasNext()) {
959 return (String)i.next();
960 } else {
961 return null;
962 }
963 }
965 public Iterator getPrefixes(final String namespaceURI) {
966 if (namespaceURI == null){
967 throw new IllegalArgumentException("NamespaceURI cannot be null");
968 }
970 if (namespaceURI.equals(XMLConstants.XML_NS_URI)) {
971 return Collections.singletonList(XMLConstants.XML_NS_PREFIX).iterator();
972 } else if (namespaceURI.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
973 return Collections.singletonList(XMLConstants.XMLNS_ATTRIBUTE).iterator();
974 }
976 return new Iterator() {
977 private int i = _namespaceAIIsEnd - 1;
978 private boolean requireFindNext = true;
979 private String p;
981 private String findNext() {
982 while(i >= 0) {
983 // Find the most recently declared namespace
984 if (namespaceURI.equals(_namespaceAIIsNamespaceName[i])) {
985 // Find the most recently declared prefix of the namespace
986 // and check if the prefix is in scope with that namespace
987 if (getNamespaceURI(_namespaceAIIsPrefix[i]).equals(
988 _namespaceAIIsNamespaceName[i])) {
989 return p = _namespaceAIIsPrefix[i];
990 }
991 }
992 i--;
993 }
994 return p = null;
995 }
997 public boolean hasNext() {
998 if (requireFindNext) {
999 findNext();
1000 requireFindNext = false;
1001 }
1002 return (p != null);
1003 }
1005 public Object next() {
1006 if (requireFindNext) {
1007 findNext();
1008 }
1009 requireFindNext = true;
1011 if (p == null) {
1012 throw new NoSuchElementException();
1013 }
1015 return p;
1016 }
1018 public void remove() {
1019 throw new UnsupportedOperationException();
1020 }
1021 };
1022 }
1024 private class BindingImpl implements NamespaceContextEx.Binding {
1025 final String _prefix;
1026 final String _namespaceURI;
1028 BindingImpl(String prefix, String namespaceURI) {
1029 _prefix = prefix;
1030 _namespaceURI = namespaceURI;
1031 }
1033 public String getPrefix() {
1034 return _prefix;
1035 }
1037 public String getNamespaceURI() {
1038 return _namespaceURI;
1039 }
1040 }
1042 public Iterator<NamespaceContextEx.Binding> iterator() {
1043 return new Iterator<NamespaceContextEx.Binding>() {
1044 private final int end = _namespaceAIIsEnd - 1;
1045 private int current = end;
1046 private boolean requireFindNext = true;
1047 private NamespaceContextEx.Binding namespace;
1049 private NamespaceContextEx.Binding findNext() {
1050 while(current >= 0) {
1051 final String prefix = _namespaceAIIsPrefix[current];
1053 // Find if the current prefix occurs more recently
1054 // If so then it is not in scope
1055 int i = end;
1056 for (;i > current; i--) {
1057 if (prefix.equals(_namespaceAIIsPrefix[i])) {
1058 break;
1059 }
1060 }
1061 if (i == current--) {
1062 // The current prefix is in-scope
1063 return namespace = new BindingImpl(prefix, _namespaceAIIsNamespaceName[current]);
1064 }
1065 }
1066 return namespace = null;
1067 }
1069 public boolean hasNext() {
1070 if (requireFindNext) {
1071 findNext();
1072 requireFindNext = false;
1073 }
1074 return (namespace != null);
1075 }
1077 public NamespaceContextEx.Binding next() {
1078 if (requireFindNext) {
1079 findNext();
1080 }
1081 requireFindNext = true;
1083 if (namespace == null) {
1084 throw new NoSuchElementException();
1085 }
1087 return namespace;
1088 }
1090 public void remove() {
1091 throw new UnsupportedOperationException();
1092 }
1093 };
1094 }
1095 }
1097 private class DummyLocation implements Location {
1098 public int getLineNumber() {
1099 return -1;
1100 }
1102 public int getColumnNumber() {
1103 return -1;
1104 }
1106 public int getCharacterOffset() {
1107 return -1;
1108 }
1110 public String getPublicId() {
1111 return null;
1112 }
1114 public String getSystemId() {
1115 return _buffer.getSystemId();
1116 }
1117 }
1119 private static String fixEmptyString(String s) {
1120 // s must not be null, so no need to check for that. that would be bug.
1121 if(s.length()==0) return null;
1122 else return s;
1123 }
1125 }