src/share/jaxws_classes/com/sun/xml/internal/stream/buffer/stax/StreamReaderBufferProcessor.java

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

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;
  1002                     return (p != null);
  1005                 public Object next() {
  1006                     if (requireFindNext) {
  1007                         findNext();
  1009                     requireFindNext = true;
  1011                     if (p == null) {
  1012                         throw new NoSuchElementException();
  1015                     return p;
  1018                 public void remove() {
  1019                     throw new UnsupportedOperationException();
  1021             };
  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;
  1033             public String getPrefix() {
  1034                 return _prefix;
  1037             public String getNamespaceURI() {
  1038                 return _namespaceURI;
  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;
  1061                         if (i == current--) {
  1062                             // The current prefix is in-scope
  1063                             return namespace = new BindingImpl(prefix, _namespaceAIIsNamespaceName[current]);
  1066                     return namespace = null;
  1069                 public boolean hasNext() {
  1070                     if (requireFindNext) {
  1071                         findNext();
  1072                         requireFindNext = false;
  1074                     return (namespace != null);
  1077                 public NamespaceContextEx.Binding next() {
  1078                     if (requireFindNext) {
  1079                         findNext();
  1081                     requireFindNext = true;
  1083                     if (namespace == null) {
  1084                         throw new NoSuchElementException();
  1087                     return namespace;
  1090                 public void remove() {
  1091                     throw new UnsupportedOperationException();
  1093             };
  1097     private class DummyLocation  implements Location {
  1098         public int getLineNumber() {
  1099             return -1;
  1102         public int getColumnNumber() {
  1103             return -1;
  1106         public int getCharacterOffset() {
  1107             return -1;
  1110         public String getPublicId() {
  1111             return null;
  1114         public String getSystemId() {
  1115             return _buffer.getSystemId();
  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;

mercurial