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

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 397
b99d7e355d4b
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 2005, 2012, 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         StringBuilder content = new StringBuilder();
   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         @Override
   646         public String toString() {
   647             return new String(_characters, _offset, _length);
   648         }
   649     }
   651     public final CharSequence getPCDATA() {
   652         if (_characters != null) {
   653             return new CharSequenceImpl(_textOffset, _textLen);
   654         } else if (_charSequence != null) {
   655             return _charSequence;
   656         } else {
   657             throw new IllegalStateException();
   658         }
   659     }
   661     public final String getEncoding() {
   662         return "UTF-8";
   663     }
   665     public final boolean hasText() {
   666         return (_characters != null || _charSequence != null);
   667     }
   669     public final Location getLocation() {
   670         return new DummyLocation();
   671     }
   673     public final boolean hasName() {
   674         return (_eventType == START_ELEMENT || _eventType == END_ELEMENT);
   675     }
   677     public final QName getName() {
   678         return _stackTop.getQName();
   679     }
   681     public final String getLocalName() {
   682         return _stackTop.localName;
   683     }
   685     public final String getNamespaceURI() {
   686         return _stackTop.uri;
   687     }
   689     public final String getPrefix() {
   690         return _stackTop.prefix;
   692     }
   694     public final String getVersion() {
   695         return "1.0";
   696     }
   698     public final boolean isStandalone() {
   699         return false;
   700     }
   702     public final boolean standaloneSet() {
   703         return false;
   704     }
   706     public final String getCharacterEncodingScheme() {
   707         return "UTF-8";
   708     }
   710     public final String getPITarget() {
   711         if (_eventType == PROCESSING_INSTRUCTION) {
   712             return _piTarget;
   713         }
   714         throw new IllegalStateException("");
   715     }
   717     public final String getPIData() {
   718         if (_eventType == PROCESSING_INSTRUCTION) {
   719             return _piData;
   720         }
   721         throw new IllegalStateException("");
   722     }
   724     protected void processElement(String prefix, String uri, String localName, boolean inscope) {
   725         pushElementStack();
   726         _stackTop.set(prefix, uri, localName);
   728         _attributeCache.clear();
   730         int item = peekStructure();
   731         if ((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE || inscope) {
   732             // Skip the namespace declarations on the element
   733             // they will have been added already
   734             item = processNamespaceAttributes(item, inscope);
   735         }
   736         if ((item & TYPE_MASK) == T_ATTRIBUTE) {
   737             processAttributes(item);
   738         }
   739     }
   741     private boolean isInscope(int depth) {
   742         return _buffer.getInscopeNamespaces().size() > 0 && depth ==0;
   743     }
   745     private void resizeNamespaceAttributes() {
   746         final String[] namespaceAIIsPrefix = new String[_namespaceAIIsEnd * 2];
   747         System.arraycopy(_namespaceAIIsPrefix, 0, namespaceAIIsPrefix, 0, _namespaceAIIsEnd);
   748         _namespaceAIIsPrefix = namespaceAIIsPrefix;
   750         final String[] namespaceAIIsNamespaceName = new String[_namespaceAIIsEnd * 2];
   751         System.arraycopy(_namespaceAIIsNamespaceName, 0, namespaceAIIsNamespaceName, 0, _namespaceAIIsEnd);
   752         _namespaceAIIsNamespaceName = namespaceAIIsNamespaceName;
   753     }
   755     private int processNamespaceAttributes(int item, boolean inscope){
   756         _stackTop.namespaceAIIsStart = _namespaceAIIsEnd;
   757         Set<String> prefixSet = inscope ? new HashSet<String>() : Collections.<String>emptySet();
   759         while((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE) {
   760             if (_namespaceAIIsEnd == _namespaceAIIsPrefix.length) {
   761                 resizeNamespaceAttributes();
   762             }
   764             switch(getNIIState(item)){
   765                 case STATE_NAMESPACE_ATTRIBUTE:
   766                     // Undeclaration of default namespace
   767                     _namespaceAIIsPrefix[_namespaceAIIsEnd] =
   768                     _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = "";
   769                     if (inscope) {
   770                         prefixSet.add("");
   771                     }
   772                     break;
   773                 case STATE_NAMESPACE_ATTRIBUTE_P:
   774                     // Undeclaration of namespace
   775                     _namespaceAIIsPrefix[_namespaceAIIsEnd] = readStructureString();
   776                     if (inscope) {
   777                         prefixSet.add(_namespaceAIIsPrefix[_namespaceAIIsEnd]);
   778                     }
   779                     _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = "";
   780                     break;
   781                 case STATE_NAMESPACE_ATTRIBUTE_P_U:
   782                     // Declaration with prefix
   783                     _namespaceAIIsPrefix[_namespaceAIIsEnd] = readStructureString();
   784                     if (inscope) {
   785                         prefixSet.add(_namespaceAIIsPrefix[_namespaceAIIsEnd]);
   786                     }
   787                     _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = readStructureString();
   788                     break;
   789                 case STATE_NAMESPACE_ATTRIBUTE_U:
   790                     // Default declaration
   791                     _namespaceAIIsPrefix[_namespaceAIIsEnd] = "";
   792                     if (inscope) {
   793                         prefixSet.add("");
   794                     }
   795                     _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = readStructureString();
   796                     break;
   797             }
   798             readStructure();
   800             item = peekStructure();
   801         }
   803         if (inscope) {
   804             for (Map.Entry<String, String> e : _buffer.getInscopeNamespaces().entrySet()) {
   805                 String key = fixNull(e.getKey());
   806                 // If the prefix is already written, do not write the prefix
   807                 if (!prefixSet.contains(key)) {
   808                     if (_namespaceAIIsEnd == _namespaceAIIsPrefix.length) {
   809                         resizeNamespaceAttributes();
   810                     }
   811                     _namespaceAIIsPrefix[_namespaceAIIsEnd] = key;
   812                     _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = e.getValue();
   813                 }
   814             }
   815         }
   816         _stackTop.namespaceAIIsEnd = _namespaceAIIsEnd;
   818         return item;
   819     }
   821     private static String fixNull(String s) {
   822         if (s == null) return "";
   823         else return s;
   824     }
   826     private void processAttributes(int item){
   827         do {
   828             switch(getAIIState(item)){
   829                 case STATE_ATTRIBUTE_U_LN_QN: {
   830                     final String uri = readStructureString();
   831                     final String localName = readStructureString();
   832                     final String prefix = getPrefixFromQName(readStructureString());
   833                     _attributeCache.addAttributeWithPrefix(prefix, uri, localName, readStructureString(), readContentString());
   834                     break;
   835                 }
   836                 case STATE_ATTRIBUTE_P_U_LN:
   837                     _attributeCache.addAttributeWithPrefix(readStructureString(), readStructureString(), readStructureString(), readStructureString(), readContentString());
   838                     break;
   839                 case STATE_ATTRIBUTE_U_LN:
   840                     // _attributeCache follows SAX convention
   841                     _attributeCache.addAttributeWithPrefix("", readStructureString(), readStructureString(), readStructureString(), readContentString());
   842                     break;
   843                 case STATE_ATTRIBUTE_LN: {
   844                     _attributeCache.addAttributeWithPrefix("", "", readStructureString(), readStructureString(), readContentString());
   845                     break;
   846                 }
   847                 default :
   848                     assert false : "Internal XSB Error: wrong attribute state, Item="+item;
   849             }
   850             readStructure();
   852             item = peekStructure();
   853         } while((item & TYPE_MASK) == T_ATTRIBUTE);
   854     }
   856     private void pushElementStack() {
   857         if (_depth == _stack.length) {
   858             // resize stack
   859             ElementStackEntry [] tmp = _stack;
   860             _stack = new ElementStackEntry[_stack.length * 3 /2 + 1];
   861             System.arraycopy(tmp, 0, _stack, 0, tmp.length);
   862             for (int i = tmp.length; i < _stack.length; i++){
   863                 _stack[i] = new ElementStackEntry();
   864             }
   865         }
   867         _stackTop = _stack[_depth++];
   868     }
   870     private void popElementStack(int depth) {
   871         // _depth is checked outside this method
   872         _stackTop = _stack[depth - 1];
   873         // Move back the position of the namespace index
   874         _namespaceAIIsEnd = _stack[depth].namespaceAIIsStart;
   875     }
   877     private final class ElementStackEntry {
   878         /**
   879          * Prefix.
   880          * Just like everywhere else in StAX, this can be null but can't be empty.
   881          */
   882         String prefix;
   883         /**
   884          * Namespace URI.
   885          * Just like everywhere else in StAX, this can be null but can't be empty.
   886          */
   887         String uri;
   888         String localName;
   889         QName qname;
   891         // Start and end of namespace declarations
   892         // in namespace declaration arrays
   893         int namespaceAIIsStart;
   894         int namespaceAIIsEnd;
   896         public void set(String prefix, String uri, String localName) {
   897             this.prefix = prefix;
   898             this.uri = uri;
   899             this.localName = localName;
   900             this.qname = null;
   902             this.namespaceAIIsStart = this.namespaceAIIsEnd = StreamReaderBufferProcessor.this._namespaceAIIsEnd;
   903         }
   905         public QName getQName() {
   906             if (qname == null) {
   907                 qname = new QName(fixNull(uri), localName, fixNull(prefix));
   908             }
   909             return qname;
   910         }
   912         private String fixNull(String s) {
   913             return (s == null) ? "" : s;
   914         }
   915     }
   917     private final class InternalNamespaceContext implements NamespaceContextEx {
   918         @SuppressWarnings({"StringEquality"})
   919         public String getNamespaceURI(String prefix) {
   920             if (prefix == null) {
   921                 throw new IllegalArgumentException("Prefix cannot be null");
   922             }
   924             /*
   925              * If the buffer was created using string interning
   926              * intern the prefix and check for reference equality
   927              * rather than using String.equals();
   928              */
   929             if (_stringInterningFeature) {
   930                 prefix = prefix.intern();
   932                 // Find the most recently declared prefix
   933                 for (int i = _namespaceAIIsEnd - 1; i >=0; i--) {
   934                     if (prefix == _namespaceAIIsPrefix[i]) {
   935                         return _namespaceAIIsNamespaceName[i];
   936                     }
   937                 }
   938             } else {
   939                 // Find the most recently declared prefix
   940                 for (int i = _namespaceAIIsEnd - 1; i >=0; i--) {
   941                     if (prefix.equals(_namespaceAIIsPrefix[i])) {
   942                         return _namespaceAIIsNamespaceName[i];
   943                     }
   944                 }
   945             }
   947             // Check for XML-based prefixes
   948             if (prefix.equals(XMLConstants.XML_NS_PREFIX)) {
   949                 return XMLConstants.XML_NS_URI;
   950             } else if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) {
   951                 return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
   952             }
   954             return null;
   955         }
   957         public String getPrefix(String namespaceURI) {
   958             final Iterator i = getPrefixes(namespaceURI);
   959             if (i.hasNext()) {
   960                 return (String)i.next();
   961             } else {
   962                 return null;
   963             }
   964         }
   966         public Iterator getPrefixes(final String namespaceURI) {
   967             if (namespaceURI == null){
   968                 throw new IllegalArgumentException("NamespaceURI cannot be null");
   969             }
   971             if (namespaceURI.equals(XMLConstants.XML_NS_URI)) {
   972                 return Collections.singletonList(XMLConstants.XML_NS_PREFIX).iterator();
   973             } else if (namespaceURI.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
   974                 return Collections.singletonList(XMLConstants.XMLNS_ATTRIBUTE).iterator();
   975             }
   977             return new Iterator() {
   978                 private int i = _namespaceAIIsEnd - 1;
   979                 private boolean requireFindNext = true;
   980                 private String p;
   982                 private String findNext() {
   983                     while(i >= 0) {
   984                         // Find the most recently declared namespace
   985                         if (namespaceURI.equals(_namespaceAIIsNamespaceName[i])) {
   986                             // Find the most recently declared prefix of the namespace
   987                             // and check if the prefix is in scope with that namespace
   988                             if (getNamespaceURI(_namespaceAIIsPrefix[i]).equals(
   989                                     _namespaceAIIsNamespaceName[i])) {
   990                                 return p = _namespaceAIIsPrefix[i];
   991                             }
   992                         }
   993                         i--;
   994                     }
   995                     return p = null;
   996                 }
   998                 public boolean hasNext() {
   999                     if (requireFindNext) {
  1000                         findNext();
  1001                         requireFindNext = false;
  1003                     return (p != null);
  1006                 public Object next() {
  1007                     if (requireFindNext) {
  1008                         findNext();
  1010                     requireFindNext = true;
  1012                     if (p == null) {
  1013                         throw new NoSuchElementException();
  1016                     return p;
  1019                 public void remove() {
  1020                     throw new UnsupportedOperationException();
  1022             };
  1025         private class BindingImpl implements NamespaceContextEx.Binding {
  1026             final String _prefix;
  1027             final String _namespaceURI;
  1029             BindingImpl(String prefix, String namespaceURI) {
  1030                 _prefix = prefix;
  1031                 _namespaceURI = namespaceURI;
  1034             public String getPrefix() {
  1035                 return _prefix;
  1038             public String getNamespaceURI() {
  1039                 return _namespaceURI;
  1043         public Iterator<NamespaceContextEx.Binding> iterator() {
  1044             return new Iterator<NamespaceContextEx.Binding>() {
  1045                 private final int end = _namespaceAIIsEnd - 1;
  1046                 private int current = end;
  1047                 private boolean requireFindNext = true;
  1048                 private NamespaceContextEx.Binding namespace;
  1050                 private NamespaceContextEx.Binding findNext() {
  1051                     while(current >= 0) {
  1052                         final String prefix = _namespaceAIIsPrefix[current];
  1054                         // Find if the current prefix occurs more recently
  1055                         // If so then it is not in scope
  1056                         int i = end;
  1057                         for (;i > current; i--) {
  1058                             if (prefix.equals(_namespaceAIIsPrefix[i])) {
  1059                                 break;
  1062                         if (i == current--) {
  1063                             // The current prefix is in-scope
  1064                             return namespace = new BindingImpl(prefix, _namespaceAIIsNamespaceName[current]);
  1067                     return namespace = null;
  1070                 public boolean hasNext() {
  1071                     if (requireFindNext) {
  1072                         findNext();
  1073                         requireFindNext = false;
  1075                     return (namespace != null);
  1078                 public NamespaceContextEx.Binding next() {
  1079                     if (requireFindNext) {
  1080                         findNext();
  1082                     requireFindNext = true;
  1084                     if (namespace == null) {
  1085                         throw new NoSuchElementException();
  1088                     return namespace;
  1091                 public void remove() {
  1092                     throw new UnsupportedOperationException();
  1094             };
  1098     private class DummyLocation  implements Location {
  1099         public int getLineNumber() {
  1100             return -1;
  1103         public int getColumnNumber() {
  1104             return -1;
  1107         public int getCharacterOffset() {
  1108             return -1;
  1111         public String getPublicId() {
  1112             return null;
  1115         public String getSystemId() {
  1116             return _buffer.getSystemId();
  1120     private static String fixEmptyString(String s) {
  1121         // s must not be null, so no need to check for that. that would be bug.
  1122         if(s.length()==0)   return null;
  1123         else                return s;

mercurial