1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/stream/buffer/stax/StreamReaderBufferProcessor.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,1126 @@ 1.4 +/* 1.5 + * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.xml.internal.stream.buffer.stax; 1.30 + 1.31 +import com.sun.xml.internal.stream.buffer.AbstractProcessor; 1.32 +import com.sun.xml.internal.stream.buffer.AttributesHolder; 1.33 +import com.sun.xml.internal.stream.buffer.XMLStreamBuffer; 1.34 +import com.sun.xml.internal.stream.buffer.XMLStreamBufferMark; 1.35 +import com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx; 1.36 +import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx; 1.37 + 1.38 +import javax.xml.XMLConstants; 1.39 +import javax.xml.namespace.QName; 1.40 +import javax.xml.stream.Location; 1.41 +import javax.xml.stream.XMLStreamException; 1.42 +import javax.xml.stream.XMLStreamReader; 1.43 +import java.util.*; 1.44 + 1.45 +/** 1.46 + * A processor of a {@link XMLStreamBuffer} that reads the XML infoset as 1.47 + * {@link XMLStreamReader}. 1.48 + * 1.49 + * <p> 1.50 + * Because of {@link XMLStreamReader} design, this processor always produce 1.51 + * a full document infoset, even if the buffer just contains a fragment. 1.52 + * 1.53 + * <p> 1.54 + * When {@link XMLStreamBuffer} contains a multiple tree (AKA "forest"), 1.55 + * {@link XMLStreamReader} will behave as if there are multiple root elements 1.56 + * (so you'll see {@link #START_ELEMENT} event where you'd normally expect 1.57 + * {@link #END_DOCUMENT}.) 1.58 + * 1.59 + * @author Paul.Sandoz@Sun.Com 1.60 + * @author K.Venugopal@sun.com 1.61 + */ 1.62 +public class StreamReaderBufferProcessor extends AbstractProcessor implements XMLStreamReaderEx { 1.63 + private static final int CACHE_SIZE = 16; 1.64 + 1.65 + // Stack to hold element and namespace declaration information 1.66 + protected ElementStackEntry[] _stack = new ElementStackEntry[CACHE_SIZE]; 1.67 + /** The top-most active entry of the {@link #_stack}. */ 1.68 + protected ElementStackEntry _stackTop; 1.69 + /** The element depth that we are in. Used to determine when we are done with a tree. */ 1.70 + protected int _depth; 1.71 + 1.72 + // Arrays to hold all namespace declarations 1.73 + /** 1.74 + * Namespace prefixes. Can be empty but not null. 1.75 + */ 1.76 + protected String[] _namespaceAIIsPrefix = new String[CACHE_SIZE]; 1.77 + protected String[] _namespaceAIIsNamespaceName = new String[CACHE_SIZE]; 1.78 + protected int _namespaceAIIsEnd; 1.79 + 1.80 + // Internal namespace context implementation 1.81 + protected InternalNamespaceContext _nsCtx = new InternalNamespaceContext(); 1.82 + 1.83 + // The current event type 1.84 + protected int _eventType; 1.85 + 1.86 + /** 1.87 + * Holder of the attributes. 1.88 + * 1.89 + * Be careful that this follows the SAX convention of using "" instead of null. 1.90 + */ 1.91 + protected AttributesHolder _attributeCache; 1.92 + 1.93 + // Characters as a CharSequence 1.94 + protected CharSequence _charSequence; 1.95 + 1.96 + // Characters as a char array with offset and length 1.97 + protected char[] _characters; 1.98 + protected int _textOffset; 1.99 + protected int _textLen; 1.100 + 1.101 + protected String _piTarget; 1.102 + protected String _piData; 1.103 + 1.104 + // 1.105 + // Represents the parser state wrt the end of parsing. 1.106 + // 1.107 + /** 1.108 + * The parser is in the middle of parsing a document, 1.109 + * with no end in sight. 1.110 + */ 1.111 + private static final int PARSING = 1; 1.112 + /** 1.113 + * The parser has already reported the {@link #END_ELEMENT}, 1.114 + * and we are parsing a fragment. We'll report {@link #END_DOCUMENT} 1.115 + * next and be done. 1.116 + */ 1.117 + private static final int PENDING_END_DOCUMENT = 2; 1.118 + /** 1.119 + * The parser has reported the {@link #END_DOCUMENT} event, 1.120 + * so we are really done parsing. 1.121 + */ 1.122 + private static final int COMPLETED = 3; 1.123 + 1.124 + /** 1.125 + * True if processing is complete. 1.126 + */ 1.127 + private int _completionState; 1.128 + 1.129 + public StreamReaderBufferProcessor() { 1.130 + for (int i=0; i < _stack.length; i++){ 1.131 + _stack[i] = new ElementStackEntry(); 1.132 + } 1.133 + 1.134 + _attributeCache = new AttributesHolder(); 1.135 + } 1.136 + 1.137 + public StreamReaderBufferProcessor(XMLStreamBuffer buffer) throws XMLStreamException { 1.138 + this(); 1.139 + setXMLStreamBuffer(buffer); 1.140 + } 1.141 + 1.142 + public void setXMLStreamBuffer(XMLStreamBuffer buffer) throws XMLStreamException { 1.143 + setBuffer(buffer,buffer.isFragment()); 1.144 + 1.145 + _completionState = PARSING; 1.146 + _namespaceAIIsEnd = 0; 1.147 + _characters = null; 1.148 + _charSequence = null; 1.149 + _eventType = START_DOCUMENT; 1.150 + } 1.151 + 1.152 + /** 1.153 + * Does {@link #nextTag()} and if the parser moved to a new start tag, 1.154 + * returns a {@link XMLStreamBufferMark} that captures the infoset starting 1.155 + * from the newly discovered element. 1.156 + * 1.157 + * <p> 1.158 + * (Ideally we should have a method that works against the current position, 1.159 + * but the way the data structure is read makes this somewhat difficult.) 1.160 + * 1.161 + * This creates a new {@link XMLStreamBufferMark} that shares the underlying 1.162 + * data storage, thus it's fairly efficient. 1.163 + */ 1.164 + public XMLStreamBuffer nextTagAndMark() throws XMLStreamException { 1.165 + while (true) { 1.166 + int s = peekStructure(); 1.167 + if((s &TYPE_MASK)==T_ELEMENT) { 1.168 + // next is start element. 1.169 + Map<String,String> inscope = new HashMap<String, String>(_namespaceAIIsEnd); 1.170 + 1.171 + for (int i=0 ; i<_namespaceAIIsEnd; i++) 1.172 + inscope.put(_namespaceAIIsPrefix[i],_namespaceAIIsNamespaceName[i]); 1.173 + 1.174 + XMLStreamBufferMark mark = new XMLStreamBufferMark(inscope, this); 1.175 + next(); 1.176 + return mark; 1.177 + } else if((s &TYPE_MASK)==T_DOCUMENT) { 1.178 + //move the pointer to next structure. 1.179 + readStructure(); 1.180 + //mark the next start element 1.181 + XMLStreamBufferMark mark = new XMLStreamBufferMark(new HashMap<String, String>(_namespaceAIIsEnd), this); 1.182 + next(); 1.183 + return mark; 1.184 + } 1.185 + 1.186 + if(next()==END_ELEMENT) 1.187 + return null; 1.188 + } 1.189 + } 1.190 + 1.191 + public Object getProperty(String name) { 1.192 + return null; 1.193 + } 1.194 + 1.195 + public int next() throws XMLStreamException { 1.196 + switch(_completionState) { 1.197 + case COMPLETED: 1.198 + throw new XMLStreamException("Invalid State"); 1.199 + case PENDING_END_DOCUMENT: 1.200 + _namespaceAIIsEnd = 0; 1.201 + _completionState = COMPLETED; 1.202 + return _eventType = END_DOCUMENT; 1.203 + } 1.204 + 1.205 + // Pop the stack of elements 1.206 + // This is a post-processing operation 1.207 + // The stack of the element should be poppoed after 1.208 + // the END_ELEMENT event is returned so that the correct element name 1.209 + // and namespace scope is returned 1.210 + switch(_eventType) { 1.211 + case END_ELEMENT: 1.212 + if (_depth > 1) { 1.213 + _depth--; 1.214 + // _depth index is always set to the next free stack entry 1.215 + // to push 1.216 + popElementStack(_depth); 1.217 + } else if (_depth == 1) { 1.218 + _depth--; 1.219 + } 1.220 + } 1.221 + 1.222 + _characters = null; 1.223 + _charSequence = null; 1.224 + while(true) {// loop only if we read STATE_DOCUMENT 1.225 + int eiiState = readEiiState(); 1.226 + switch(eiiState) { 1.227 + case STATE_DOCUMENT: 1.228 + // we'll always produce a full document, and we've already report START_DOCUMENT event. 1.229 + // so simply skil this 1.230 + continue; 1.231 + case STATE_ELEMENT_U_LN_QN: { 1.232 + final String uri = readStructureString(); 1.233 + final String localName = readStructureString(); 1.234 + final String prefix = getPrefixFromQName(readStructureString()); 1.235 + 1.236 + processElement(prefix, uri, localName, isInscope(_depth)); 1.237 + return _eventType = START_ELEMENT; 1.238 + } 1.239 + case STATE_ELEMENT_P_U_LN: 1.240 + processElement(readStructureString(), readStructureString(), readStructureString(),isInscope(_depth)); 1.241 + return _eventType = START_ELEMENT; 1.242 + case STATE_ELEMENT_U_LN: 1.243 + processElement(null, readStructureString(), readStructureString(),isInscope(_depth)); 1.244 + return _eventType = START_ELEMENT; 1.245 + case STATE_ELEMENT_LN: 1.246 + processElement(null, null, readStructureString(),isInscope(_depth)); 1.247 + return _eventType = START_ELEMENT; 1.248 + case STATE_TEXT_AS_CHAR_ARRAY_SMALL: 1.249 + _textLen = readStructure(); 1.250 + _textOffset = readContentCharactersBuffer(_textLen); 1.251 + _characters = _contentCharactersBuffer; 1.252 + 1.253 + return _eventType = CHARACTERS; 1.254 + case STATE_TEXT_AS_CHAR_ARRAY_MEDIUM: 1.255 + _textLen = readStructure16(); 1.256 + _textOffset = readContentCharactersBuffer(_textLen); 1.257 + _characters = _contentCharactersBuffer; 1.258 + 1.259 + return _eventType = CHARACTERS; 1.260 + case STATE_TEXT_AS_CHAR_ARRAY_COPY: 1.261 + _characters = readContentCharactersCopy(); 1.262 + _textLen = _characters.length; 1.263 + _textOffset = 0; 1.264 + 1.265 + return _eventType = CHARACTERS; 1.266 + case STATE_TEXT_AS_STRING: 1.267 + _eventType = CHARACTERS; 1.268 + _charSequence = readContentString(); 1.269 + 1.270 + return _eventType = CHARACTERS; 1.271 + case STATE_TEXT_AS_OBJECT: 1.272 + _eventType = CHARACTERS; 1.273 + _charSequence = (CharSequence)readContentObject(); 1.274 + 1.275 + return _eventType = CHARACTERS; 1.276 + case STATE_COMMENT_AS_CHAR_ARRAY_SMALL: 1.277 + _textLen = readStructure(); 1.278 + _textOffset = readContentCharactersBuffer(_textLen); 1.279 + _characters = _contentCharactersBuffer; 1.280 + 1.281 + return _eventType = COMMENT; 1.282 + case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM: 1.283 + _textLen = readStructure16(); 1.284 + _textOffset = readContentCharactersBuffer(_textLen); 1.285 + _characters = _contentCharactersBuffer; 1.286 + 1.287 + return _eventType = COMMENT; 1.288 + case STATE_COMMENT_AS_CHAR_ARRAY_COPY: 1.289 + _characters = readContentCharactersCopy(); 1.290 + _textLen = _characters.length; 1.291 + _textOffset = 0; 1.292 + 1.293 + return _eventType = COMMENT; 1.294 + case STATE_COMMENT_AS_STRING: 1.295 + _charSequence = readContentString(); 1.296 + 1.297 + return _eventType = COMMENT; 1.298 + case STATE_PROCESSING_INSTRUCTION: 1.299 + _piTarget = readStructureString(); 1.300 + _piData = readStructureString(); 1.301 + 1.302 + return _eventType = PROCESSING_INSTRUCTION; 1.303 + case STATE_END: 1.304 + if (_depth > 1) { 1.305 + // normal case 1.306 + return _eventType = END_ELEMENT; 1.307 + } else if (_depth == 1) { 1.308 + // this is the last end element for the current tree. 1.309 + if (_fragmentMode) { 1.310 + if(--_treeCount==0) // is this the last tree in the forest? 1.311 + _completionState = PENDING_END_DOCUMENT; 1.312 + } 1.313 + return _eventType = END_ELEMENT; 1.314 + } else { 1.315 + // this only happens when we are processing a full document 1.316 + // and we hit the "end of document" marker 1.317 + _namespaceAIIsEnd = 0; 1.318 + _completionState = COMPLETED; 1.319 + return _eventType = END_DOCUMENT; 1.320 + } 1.321 + default: 1.322 + throw new XMLStreamException("Internal XSB error: Invalid State="+eiiState); 1.323 + } 1.324 + // this should be unreachable 1.325 + } 1.326 + } 1.327 + 1.328 + public final void require(int type, String namespaceURI, String localName) throws XMLStreamException { 1.329 + if( type != _eventType) { 1.330 + throw new XMLStreamException(""); 1.331 + } 1.332 + if( namespaceURI != null && !namespaceURI.equals(getNamespaceURI())) { 1.333 + throw new XMLStreamException(""); 1.334 + } 1.335 + if(localName != null && !localName.equals(getLocalName())) { 1.336 + throw new XMLStreamException(""); 1.337 + } 1.338 + } 1.339 + 1.340 + public final String getElementTextTrim() throws XMLStreamException { 1.341 + // TODO getElementText* methods more efficiently 1.342 + return getElementText().trim(); 1.343 + } 1.344 + 1.345 + public final String getElementText() throws XMLStreamException { 1.346 + if(_eventType != START_ELEMENT) { 1.347 + throw new XMLStreamException(""); 1.348 + } 1.349 + 1.350 + next(); 1.351 + return getElementText(true); 1.352 + } 1.353 + 1.354 + public final String getElementText(boolean startElementRead) throws XMLStreamException { 1.355 + if (!startElementRead) { 1.356 + throw new XMLStreamException(""); 1.357 + } 1.358 + 1.359 + int eventType = getEventType(); 1.360 + StringBuilder content = new StringBuilder(); 1.361 + while(eventType != END_ELEMENT ) { 1.362 + if(eventType == CHARACTERS 1.363 + || eventType == CDATA 1.364 + || eventType == SPACE 1.365 + || eventType == ENTITY_REFERENCE) { 1.366 + content.append(getText()); 1.367 + } else if(eventType == PROCESSING_INSTRUCTION 1.368 + || eventType == COMMENT) { 1.369 + // skipping 1.370 + } else if(eventType == END_DOCUMENT) { 1.371 + throw new XMLStreamException(""); 1.372 + } else if(eventType == START_ELEMENT) { 1.373 + throw new XMLStreamException(""); 1.374 + } else { 1.375 + throw new XMLStreamException(""); 1.376 + } 1.377 + eventType = next(); 1.378 + } 1.379 + return content.toString(); 1.380 + } 1.381 + 1.382 + public final int nextTag() throws XMLStreamException { 1.383 + next(); 1.384 + return nextTag(true); 1.385 + } 1.386 + 1.387 + public final int nextTag(boolean currentTagRead) throws XMLStreamException { 1.388 + int eventType = getEventType(); 1.389 + if (!currentTagRead) { 1.390 + eventType = next(); 1.391 + } 1.392 + while((eventType == CHARACTERS && isWhiteSpace()) // skip whitespace 1.393 + || (eventType == CDATA && isWhiteSpace()) 1.394 + || eventType == SPACE 1.395 + || eventType == PROCESSING_INSTRUCTION 1.396 + || eventType == COMMENT) { 1.397 + eventType = next(); 1.398 + } 1.399 + if (eventType != START_ELEMENT && eventType != END_ELEMENT) { 1.400 + throw new XMLStreamException(""); 1.401 + } 1.402 + return eventType; 1.403 + } 1.404 + 1.405 + public final boolean hasNext() { 1.406 + return (_eventType != END_DOCUMENT); 1.407 + } 1.408 + 1.409 + public void close() throws XMLStreamException { 1.410 + } 1.411 + 1.412 + public final boolean isStartElement() { 1.413 + return (_eventType == START_ELEMENT); 1.414 + } 1.415 + 1.416 + public final boolean isEndElement() { 1.417 + return (_eventType == END_ELEMENT); 1.418 + } 1.419 + 1.420 + public final boolean isCharacters() { 1.421 + return (_eventType == CHARACTERS); 1.422 + } 1.423 + 1.424 + public final boolean isWhiteSpace() { 1.425 + if(isCharacters() || (_eventType == CDATA)){ 1.426 + char [] ch = this.getTextCharacters(); 1.427 + int start = this.getTextStart(); 1.428 + int length = this.getTextLength(); 1.429 + for (int i = start; i < length; i++){ 1.430 + final char c = ch[i]; 1.431 + if (!(c == 0x20 || c == 0x9 || c == 0xD || c == 0xA)) 1.432 + return false; 1.433 + } 1.434 + return true; 1.435 + } 1.436 + return false; 1.437 + } 1.438 + 1.439 + public final String getAttributeValue(String namespaceURI, String localName) { 1.440 + if (_eventType != START_ELEMENT) { 1.441 + throw new IllegalStateException(""); 1.442 + } 1.443 + 1.444 + if (namespaceURI == null) { 1.445 + // Set to the empty string to be compatible with the 1.446 + // org.xml.sax.Attributes interface 1.447 + namespaceURI = ""; 1.448 + } 1.449 + 1.450 + return _attributeCache.getValue(namespaceURI, localName); 1.451 + } 1.452 + 1.453 + public final int getAttributeCount() { 1.454 + if (_eventType != START_ELEMENT) { 1.455 + throw new IllegalStateException(""); 1.456 + } 1.457 + 1.458 + return _attributeCache.getLength(); 1.459 + } 1.460 + 1.461 + public final javax.xml.namespace.QName getAttributeName(int index) { 1.462 + if (_eventType != START_ELEMENT) { 1.463 + throw new IllegalStateException(""); 1.464 + } 1.465 + 1.466 + final String prefix = _attributeCache.getPrefix(index); 1.467 + final String localName = _attributeCache.getLocalName(index); 1.468 + final String uri = _attributeCache.getURI(index); 1.469 + return new QName(uri,localName,prefix); 1.470 + } 1.471 + 1.472 + 1.473 + public final String getAttributeNamespace(int index) { 1.474 + if (_eventType != START_ELEMENT) { 1.475 + throw new IllegalStateException(""); 1.476 + } 1.477 + return fixEmptyString(_attributeCache.getURI(index)); 1.478 + } 1.479 + 1.480 + public final String getAttributeLocalName(int index) { 1.481 + if (_eventType != START_ELEMENT) { 1.482 + throw new IllegalStateException(""); 1.483 + } 1.484 + return _attributeCache.getLocalName(index); 1.485 + } 1.486 + 1.487 + public final String getAttributePrefix(int index) { 1.488 + if (_eventType != START_ELEMENT) { 1.489 + throw new IllegalStateException(""); 1.490 + } 1.491 + return fixEmptyString(_attributeCache.getPrefix(index)); 1.492 + } 1.493 + 1.494 + public final String getAttributeType(int index) { 1.495 + if (_eventType != START_ELEMENT) { 1.496 + throw new IllegalStateException(""); 1.497 + } 1.498 + return _attributeCache.getType(index); 1.499 + } 1.500 + 1.501 + public final String getAttributeValue(int index) { 1.502 + if (_eventType != START_ELEMENT) { 1.503 + throw new IllegalStateException(""); 1.504 + } 1.505 + 1.506 + return _attributeCache.getValue(index); 1.507 + } 1.508 + 1.509 + public final boolean isAttributeSpecified(int index) { 1.510 + return false; 1.511 + } 1.512 + 1.513 + public final int getNamespaceCount() { 1.514 + if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { 1.515 + return _stackTop.namespaceAIIsEnd - _stackTop.namespaceAIIsStart; 1.516 + } 1.517 + 1.518 + throw new IllegalStateException(""); 1.519 + } 1.520 + 1.521 + public final String getNamespacePrefix(int index) { 1.522 + if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { 1.523 + return _namespaceAIIsPrefix[_stackTop.namespaceAIIsStart + index]; 1.524 + } 1.525 + 1.526 + throw new IllegalStateException(""); 1.527 + } 1.528 + 1.529 + public final String getNamespaceURI(int index) { 1.530 + if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { 1.531 + return _namespaceAIIsNamespaceName[_stackTop.namespaceAIIsStart + index]; 1.532 + } 1.533 + 1.534 + throw new IllegalStateException(""); 1.535 + } 1.536 + 1.537 + public final String getNamespaceURI(String prefix) { 1.538 + return _nsCtx.getNamespaceURI(prefix); 1.539 + } 1.540 + 1.541 + public final NamespaceContextEx getNamespaceContext() { 1.542 + return _nsCtx; 1.543 + } 1.544 + 1.545 + public final int getEventType() { 1.546 + return _eventType; 1.547 + } 1.548 + 1.549 + public final String getText() { 1.550 + if (_characters != null) { 1.551 + String s = new String(_characters, _textOffset, _textLen); 1.552 + _charSequence = s; 1.553 + return s; 1.554 + } else if (_charSequence != null) { 1.555 + return _charSequence.toString(); 1.556 + } else { 1.557 + throw new IllegalStateException(); 1.558 + } 1.559 + } 1.560 + 1.561 + public final char[] getTextCharacters() { 1.562 + if (_characters != null) { 1.563 + return _characters; 1.564 + } else if (_charSequence != null) { 1.565 + // TODO try to avoid creation of a temporary String for some 1.566 + // CharSequence implementations 1.567 + _characters = _charSequence.toString().toCharArray(); 1.568 + _textLen = _characters.length; 1.569 + _textOffset = 0; 1.570 + return _characters; 1.571 + } else { 1.572 + throw new IllegalStateException(); 1.573 + } 1.574 + } 1.575 + 1.576 + public final int getTextStart() { 1.577 + if (_characters != null) { 1.578 + return _textOffset; 1.579 + } else if (_charSequence != null) { 1.580 + return 0; 1.581 + } else { 1.582 + throw new IllegalStateException(); 1.583 + } 1.584 + } 1.585 + 1.586 + public final int getTextLength() { 1.587 + if (_characters != null) { 1.588 + return _textLen; 1.589 + } else if (_charSequence != null) { 1.590 + return _charSequence.length(); 1.591 + } else { 1.592 + throw new IllegalStateException(); 1.593 + } 1.594 + } 1.595 + 1.596 + public final int getTextCharacters(int sourceStart, char[] target, 1.597 + int targetStart, int length) throws XMLStreamException { 1.598 + if (_characters != null) { 1.599 + } else if (_charSequence != null) { 1.600 + _characters = _charSequence.toString().toCharArray(); 1.601 + _textLen = _characters.length; 1.602 + _textOffset = 0; 1.603 + } else { 1.604 + throw new IllegalStateException(""); 1.605 + } 1.606 + 1.607 + try { 1.608 + int remaining = _textLen - sourceStart; 1.609 + int len = remaining > length ? length : remaining; 1.610 + sourceStart += _textOffset; 1.611 + System.arraycopy(_characters, sourceStart, target, targetStart, len); 1.612 + return len; 1.613 + } catch (IndexOutOfBoundsException e) { 1.614 + throw new XMLStreamException(e); 1.615 + } 1.616 + } 1.617 + 1.618 + private class CharSequenceImpl implements CharSequence { 1.619 + private final int _offset; 1.620 + private final int _length; 1.621 + 1.622 + CharSequenceImpl(int offset, int length) { 1.623 + _offset = offset; 1.624 + _length = length; 1.625 + } 1.626 + 1.627 + public int length() { 1.628 + return _length; 1.629 + } 1.630 + 1.631 + public char charAt(int index) { 1.632 + if (index >= 0 && index < _textLen) { 1.633 + return _characters[_textOffset + index]; 1.634 + } else { 1.635 + throw new IndexOutOfBoundsException(); 1.636 + } 1.637 + } 1.638 + 1.639 + public CharSequence subSequence(int start, int end) { 1.640 + final int length = end - start; 1.641 + if (end < 0 || start < 0 || end > length || start > end) { 1.642 + throw new IndexOutOfBoundsException(); 1.643 + } 1.644 + 1.645 + return new CharSequenceImpl(_offset + start, length); 1.646 + } 1.647 + 1.648 + @Override 1.649 + public String toString() { 1.650 + return new String(_characters, _offset, _length); 1.651 + } 1.652 + } 1.653 + 1.654 + public final CharSequence getPCDATA() { 1.655 + if (_characters != null) { 1.656 + return new CharSequenceImpl(_textOffset, _textLen); 1.657 + } else if (_charSequence != null) { 1.658 + return _charSequence; 1.659 + } else { 1.660 + throw new IllegalStateException(); 1.661 + } 1.662 + } 1.663 + 1.664 + public final String getEncoding() { 1.665 + return "UTF-8"; 1.666 + } 1.667 + 1.668 + public final boolean hasText() { 1.669 + return (_characters != null || _charSequence != null); 1.670 + } 1.671 + 1.672 + public final Location getLocation() { 1.673 + return new DummyLocation(); 1.674 + } 1.675 + 1.676 + public final boolean hasName() { 1.677 + return (_eventType == START_ELEMENT || _eventType == END_ELEMENT); 1.678 + } 1.679 + 1.680 + public final QName getName() { 1.681 + return _stackTop.getQName(); 1.682 + } 1.683 + 1.684 + public final String getLocalName() { 1.685 + return _stackTop.localName; 1.686 + } 1.687 + 1.688 + public final String getNamespaceURI() { 1.689 + return _stackTop.uri; 1.690 + } 1.691 + 1.692 + public final String getPrefix() { 1.693 + return _stackTop.prefix; 1.694 + 1.695 + } 1.696 + 1.697 + public final String getVersion() { 1.698 + return "1.0"; 1.699 + } 1.700 + 1.701 + public final boolean isStandalone() { 1.702 + return false; 1.703 + } 1.704 + 1.705 + public final boolean standaloneSet() { 1.706 + return false; 1.707 + } 1.708 + 1.709 + public final String getCharacterEncodingScheme() { 1.710 + return "UTF-8"; 1.711 + } 1.712 + 1.713 + public final String getPITarget() { 1.714 + if (_eventType == PROCESSING_INSTRUCTION) { 1.715 + return _piTarget; 1.716 + } 1.717 + throw new IllegalStateException(""); 1.718 + } 1.719 + 1.720 + public final String getPIData() { 1.721 + if (_eventType == PROCESSING_INSTRUCTION) { 1.722 + return _piData; 1.723 + } 1.724 + throw new IllegalStateException(""); 1.725 + } 1.726 + 1.727 + protected void processElement(String prefix, String uri, String localName, boolean inscope) { 1.728 + pushElementStack(); 1.729 + _stackTop.set(prefix, uri, localName); 1.730 + 1.731 + _attributeCache.clear(); 1.732 + 1.733 + int item = peekStructure(); 1.734 + if ((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE || inscope) { 1.735 + // Skip the namespace declarations on the element 1.736 + // they will have been added already 1.737 + item = processNamespaceAttributes(item, inscope); 1.738 + } 1.739 + if ((item & TYPE_MASK) == T_ATTRIBUTE) { 1.740 + processAttributes(item); 1.741 + } 1.742 + } 1.743 + 1.744 + private boolean isInscope(int depth) { 1.745 + return _buffer.getInscopeNamespaces().size() > 0 && depth ==0; 1.746 + } 1.747 + 1.748 + private void resizeNamespaceAttributes() { 1.749 + final String[] namespaceAIIsPrefix = new String[_namespaceAIIsEnd * 2]; 1.750 + System.arraycopy(_namespaceAIIsPrefix, 0, namespaceAIIsPrefix, 0, _namespaceAIIsEnd); 1.751 + _namespaceAIIsPrefix = namespaceAIIsPrefix; 1.752 + 1.753 + final String[] namespaceAIIsNamespaceName = new String[_namespaceAIIsEnd * 2]; 1.754 + System.arraycopy(_namespaceAIIsNamespaceName, 0, namespaceAIIsNamespaceName, 0, _namespaceAIIsEnd); 1.755 + _namespaceAIIsNamespaceName = namespaceAIIsNamespaceName; 1.756 + } 1.757 + 1.758 + private int processNamespaceAttributes(int item, boolean inscope){ 1.759 + _stackTop.namespaceAIIsStart = _namespaceAIIsEnd; 1.760 + Set<String> prefixSet = inscope ? new HashSet<String>() : Collections.<String>emptySet(); 1.761 + 1.762 + while((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE) { 1.763 + if (_namespaceAIIsEnd == _namespaceAIIsPrefix.length) { 1.764 + resizeNamespaceAttributes(); 1.765 + } 1.766 + 1.767 + switch(getNIIState(item)){ 1.768 + case STATE_NAMESPACE_ATTRIBUTE: 1.769 + // Undeclaration of default namespace 1.770 + _namespaceAIIsPrefix[_namespaceAIIsEnd] = 1.771 + _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = ""; 1.772 + if (inscope) { 1.773 + prefixSet.add(""); 1.774 + } 1.775 + break; 1.776 + case STATE_NAMESPACE_ATTRIBUTE_P: 1.777 + // Undeclaration of namespace 1.778 + _namespaceAIIsPrefix[_namespaceAIIsEnd] = readStructureString(); 1.779 + if (inscope) { 1.780 + prefixSet.add(_namespaceAIIsPrefix[_namespaceAIIsEnd]); 1.781 + } 1.782 + _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = ""; 1.783 + break; 1.784 + case STATE_NAMESPACE_ATTRIBUTE_P_U: 1.785 + // Declaration with prefix 1.786 + _namespaceAIIsPrefix[_namespaceAIIsEnd] = readStructureString(); 1.787 + if (inscope) { 1.788 + prefixSet.add(_namespaceAIIsPrefix[_namespaceAIIsEnd]); 1.789 + } 1.790 + _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = readStructureString(); 1.791 + break; 1.792 + case STATE_NAMESPACE_ATTRIBUTE_U: 1.793 + // Default declaration 1.794 + _namespaceAIIsPrefix[_namespaceAIIsEnd] = ""; 1.795 + if (inscope) { 1.796 + prefixSet.add(""); 1.797 + } 1.798 + _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = readStructureString(); 1.799 + break; 1.800 + } 1.801 + readStructure(); 1.802 + 1.803 + item = peekStructure(); 1.804 + } 1.805 + 1.806 + if (inscope) { 1.807 + for (Map.Entry<String, String> e : _buffer.getInscopeNamespaces().entrySet()) { 1.808 + String key = fixNull(e.getKey()); 1.809 + // If the prefix is already written, do not write the prefix 1.810 + if (!prefixSet.contains(key)) { 1.811 + if (_namespaceAIIsEnd == _namespaceAIIsPrefix.length) { 1.812 + resizeNamespaceAttributes(); 1.813 + } 1.814 + _namespaceAIIsPrefix[_namespaceAIIsEnd] = key; 1.815 + _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = e.getValue(); 1.816 + } 1.817 + } 1.818 + } 1.819 + _stackTop.namespaceAIIsEnd = _namespaceAIIsEnd; 1.820 + 1.821 + return item; 1.822 + } 1.823 + 1.824 + private static String fixNull(String s) { 1.825 + if (s == null) return ""; 1.826 + else return s; 1.827 + } 1.828 + 1.829 + private void processAttributes(int item){ 1.830 + do { 1.831 + switch(getAIIState(item)){ 1.832 + case STATE_ATTRIBUTE_U_LN_QN: { 1.833 + final String uri = readStructureString(); 1.834 + final String localName = readStructureString(); 1.835 + final String prefix = getPrefixFromQName(readStructureString()); 1.836 + _attributeCache.addAttributeWithPrefix(prefix, uri, localName, readStructureString(), readContentString()); 1.837 + break; 1.838 + } 1.839 + case STATE_ATTRIBUTE_P_U_LN: 1.840 + _attributeCache.addAttributeWithPrefix(readStructureString(), readStructureString(), readStructureString(), readStructureString(), readContentString()); 1.841 + break; 1.842 + case STATE_ATTRIBUTE_U_LN: 1.843 + // _attributeCache follows SAX convention 1.844 + _attributeCache.addAttributeWithPrefix("", readStructureString(), readStructureString(), readStructureString(), readContentString()); 1.845 + break; 1.846 + case STATE_ATTRIBUTE_LN: { 1.847 + _attributeCache.addAttributeWithPrefix("", "", readStructureString(), readStructureString(), readContentString()); 1.848 + break; 1.849 + } 1.850 + default : 1.851 + assert false : "Internal XSB Error: wrong attribute state, Item="+item; 1.852 + } 1.853 + readStructure(); 1.854 + 1.855 + item = peekStructure(); 1.856 + } while((item & TYPE_MASK) == T_ATTRIBUTE); 1.857 + } 1.858 + 1.859 + private void pushElementStack() { 1.860 + if (_depth == _stack.length) { 1.861 + // resize stack 1.862 + ElementStackEntry [] tmp = _stack; 1.863 + _stack = new ElementStackEntry[_stack.length * 3 /2 + 1]; 1.864 + System.arraycopy(tmp, 0, _stack, 0, tmp.length); 1.865 + for (int i = tmp.length; i < _stack.length; i++){ 1.866 + _stack[i] = new ElementStackEntry(); 1.867 + } 1.868 + } 1.869 + 1.870 + _stackTop = _stack[_depth++]; 1.871 + } 1.872 + 1.873 + private void popElementStack(int depth) { 1.874 + // _depth is checked outside this method 1.875 + _stackTop = _stack[depth - 1]; 1.876 + // Move back the position of the namespace index 1.877 + _namespaceAIIsEnd = _stack[depth].namespaceAIIsStart; 1.878 + } 1.879 + 1.880 + private final class ElementStackEntry { 1.881 + /** 1.882 + * Prefix. 1.883 + * Just like everywhere else in StAX, this can be null but can't be empty. 1.884 + */ 1.885 + String prefix; 1.886 + /** 1.887 + * Namespace URI. 1.888 + * Just like everywhere else in StAX, this can be null but can't be empty. 1.889 + */ 1.890 + String uri; 1.891 + String localName; 1.892 + QName qname; 1.893 + 1.894 + // Start and end of namespace declarations 1.895 + // in namespace declaration arrays 1.896 + int namespaceAIIsStart; 1.897 + int namespaceAIIsEnd; 1.898 + 1.899 + public void set(String prefix, String uri, String localName) { 1.900 + this.prefix = prefix; 1.901 + this.uri = uri; 1.902 + this.localName = localName; 1.903 + this.qname = null; 1.904 + 1.905 + this.namespaceAIIsStart = this.namespaceAIIsEnd = StreamReaderBufferProcessor.this._namespaceAIIsEnd; 1.906 + } 1.907 + 1.908 + public QName getQName() { 1.909 + if (qname == null) { 1.910 + qname = new QName(fixNull(uri), localName, fixNull(prefix)); 1.911 + } 1.912 + return qname; 1.913 + } 1.914 + 1.915 + private String fixNull(String s) { 1.916 + return (s == null) ? "" : s; 1.917 + } 1.918 + } 1.919 + 1.920 + private final class InternalNamespaceContext implements NamespaceContextEx { 1.921 + @SuppressWarnings({"StringEquality"}) 1.922 + public String getNamespaceURI(String prefix) { 1.923 + if (prefix == null) { 1.924 + throw new IllegalArgumentException("Prefix cannot be null"); 1.925 + } 1.926 + 1.927 + /* 1.928 + * If the buffer was created using string interning 1.929 + * intern the prefix and check for reference equality 1.930 + * rather than using String.equals(); 1.931 + */ 1.932 + if (_stringInterningFeature) { 1.933 + prefix = prefix.intern(); 1.934 + 1.935 + // Find the most recently declared prefix 1.936 + for (int i = _namespaceAIIsEnd - 1; i >=0; i--) { 1.937 + if (prefix == _namespaceAIIsPrefix[i]) { 1.938 + return _namespaceAIIsNamespaceName[i]; 1.939 + } 1.940 + } 1.941 + } else { 1.942 + // Find the most recently declared prefix 1.943 + for (int i = _namespaceAIIsEnd - 1; i >=0; i--) { 1.944 + if (prefix.equals(_namespaceAIIsPrefix[i])) { 1.945 + return _namespaceAIIsNamespaceName[i]; 1.946 + } 1.947 + } 1.948 + } 1.949 + 1.950 + // Check for XML-based prefixes 1.951 + if (prefix.equals(XMLConstants.XML_NS_PREFIX)) { 1.952 + return XMLConstants.XML_NS_URI; 1.953 + } else if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) { 1.954 + return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; 1.955 + } 1.956 + 1.957 + return null; 1.958 + } 1.959 + 1.960 + public String getPrefix(String namespaceURI) { 1.961 + final Iterator i = getPrefixes(namespaceURI); 1.962 + if (i.hasNext()) { 1.963 + return (String)i.next(); 1.964 + } else { 1.965 + return null; 1.966 + } 1.967 + } 1.968 + 1.969 + public Iterator getPrefixes(final String namespaceURI) { 1.970 + if (namespaceURI == null){ 1.971 + throw new IllegalArgumentException("NamespaceURI cannot be null"); 1.972 + } 1.973 + 1.974 + if (namespaceURI.equals(XMLConstants.XML_NS_URI)) { 1.975 + return Collections.singletonList(XMLConstants.XML_NS_PREFIX).iterator(); 1.976 + } else if (namespaceURI.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) { 1.977 + return Collections.singletonList(XMLConstants.XMLNS_ATTRIBUTE).iterator(); 1.978 + } 1.979 + 1.980 + return new Iterator() { 1.981 + private int i = _namespaceAIIsEnd - 1; 1.982 + private boolean requireFindNext = true; 1.983 + private String p; 1.984 + 1.985 + private String findNext() { 1.986 + while(i >= 0) { 1.987 + // Find the most recently declared namespace 1.988 + if (namespaceURI.equals(_namespaceAIIsNamespaceName[i])) { 1.989 + // Find the most recently declared prefix of the namespace 1.990 + // and check if the prefix is in scope with that namespace 1.991 + if (getNamespaceURI(_namespaceAIIsPrefix[i]).equals( 1.992 + _namespaceAIIsNamespaceName[i])) { 1.993 + return p = _namespaceAIIsPrefix[i]; 1.994 + } 1.995 + } 1.996 + i--; 1.997 + } 1.998 + return p = null; 1.999 + } 1.1000 + 1.1001 + public boolean hasNext() { 1.1002 + if (requireFindNext) { 1.1003 + findNext(); 1.1004 + requireFindNext = false; 1.1005 + } 1.1006 + return (p != null); 1.1007 + } 1.1008 + 1.1009 + public Object next() { 1.1010 + if (requireFindNext) { 1.1011 + findNext(); 1.1012 + } 1.1013 + requireFindNext = true; 1.1014 + 1.1015 + if (p == null) { 1.1016 + throw new NoSuchElementException(); 1.1017 + } 1.1018 + 1.1019 + return p; 1.1020 + } 1.1021 + 1.1022 + public void remove() { 1.1023 + throw new UnsupportedOperationException(); 1.1024 + } 1.1025 + }; 1.1026 + } 1.1027 + 1.1028 + private class BindingImpl implements NamespaceContextEx.Binding { 1.1029 + final String _prefix; 1.1030 + final String _namespaceURI; 1.1031 + 1.1032 + BindingImpl(String prefix, String namespaceURI) { 1.1033 + _prefix = prefix; 1.1034 + _namespaceURI = namespaceURI; 1.1035 + } 1.1036 + 1.1037 + public String getPrefix() { 1.1038 + return _prefix; 1.1039 + } 1.1040 + 1.1041 + public String getNamespaceURI() { 1.1042 + return _namespaceURI; 1.1043 + } 1.1044 + } 1.1045 + 1.1046 + public Iterator<NamespaceContextEx.Binding> iterator() { 1.1047 + return new Iterator<NamespaceContextEx.Binding>() { 1.1048 + private final int end = _namespaceAIIsEnd - 1; 1.1049 + private int current = end; 1.1050 + private boolean requireFindNext = true; 1.1051 + private NamespaceContextEx.Binding namespace; 1.1052 + 1.1053 + private NamespaceContextEx.Binding findNext() { 1.1054 + while(current >= 0) { 1.1055 + final String prefix = _namespaceAIIsPrefix[current]; 1.1056 + 1.1057 + // Find if the current prefix occurs more recently 1.1058 + // If so then it is not in scope 1.1059 + int i = end; 1.1060 + for (;i > current; i--) { 1.1061 + if (prefix.equals(_namespaceAIIsPrefix[i])) { 1.1062 + break; 1.1063 + } 1.1064 + } 1.1065 + if (i == current--) { 1.1066 + // The current prefix is in-scope 1.1067 + return namespace = new BindingImpl(prefix, _namespaceAIIsNamespaceName[current]); 1.1068 + } 1.1069 + } 1.1070 + return namespace = null; 1.1071 + } 1.1072 + 1.1073 + public boolean hasNext() { 1.1074 + if (requireFindNext) { 1.1075 + findNext(); 1.1076 + requireFindNext = false; 1.1077 + } 1.1078 + return (namespace != null); 1.1079 + } 1.1080 + 1.1081 + public NamespaceContextEx.Binding next() { 1.1082 + if (requireFindNext) { 1.1083 + findNext(); 1.1084 + } 1.1085 + requireFindNext = true; 1.1086 + 1.1087 + if (namespace == null) { 1.1088 + throw new NoSuchElementException(); 1.1089 + } 1.1090 + 1.1091 + return namespace; 1.1092 + } 1.1093 + 1.1094 + public void remove() { 1.1095 + throw new UnsupportedOperationException(); 1.1096 + } 1.1097 + }; 1.1098 + } 1.1099 + } 1.1100 + 1.1101 + private class DummyLocation implements Location { 1.1102 + public int getLineNumber() { 1.1103 + return -1; 1.1104 + } 1.1105 + 1.1106 + public int getColumnNumber() { 1.1107 + return -1; 1.1108 + } 1.1109 + 1.1110 + public int getCharacterOffset() { 1.1111 + return -1; 1.1112 + } 1.1113 + 1.1114 + public String getPublicId() { 1.1115 + return null; 1.1116 + } 1.1117 + 1.1118 + public String getSystemId() { 1.1119 + return _buffer.getSystemId(); 1.1120 + } 1.1121 + } 1.1122 + 1.1123 + private static String fixEmptyString(String s) { 1.1124 + // s must not be null, so no need to check for that. that would be bug. 1.1125 + if(s.length()==0) return null; 1.1126 + else return s; 1.1127 + } 1.1128 + 1.1129 +}