aoqi@0: /* aoqi@0: * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.fastinfoset.stax; aoqi@0: aoqi@0: import com.sun.xml.internal.fastinfoset.Decoder; aoqi@0: import com.sun.xml.internal.fastinfoset.DecoderStateTables; aoqi@0: import com.sun.xml.internal.fastinfoset.EncodingConstants; aoqi@0: import com.sun.xml.internal.fastinfoset.OctetBufferListener; aoqi@0: import com.sun.xml.internal.fastinfoset.QualifiedName; aoqi@0: import com.sun.xml.internal.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory; aoqi@0: import com.sun.xml.internal.fastinfoset.sax.AttributesHolder; aoqi@0: import com.sun.xml.internal.fastinfoset.util.CharArray; aoqi@0: import com.sun.xml.internal.fastinfoset.util.CharArrayString; aoqi@0: import java.io.IOException; aoqi@0: import java.io.InputStream; aoqi@0: import java.util.Iterator; aoqi@0: import java.util.NoSuchElementException; aoqi@0: import javax.xml.namespace.NamespaceContext; aoqi@0: import javax.xml.namespace.QName; aoqi@0: import javax.xml.stream.Location; aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: import javax.xml.stream.XMLStreamReader; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmException; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException; aoqi@0: import com.sun.xml.internal.fastinfoset.CommonResourceBundle; aoqi@0: import com.sun.xml.internal.fastinfoset.org.apache.xerces.util.XMLChar; aoqi@0: import com.sun.xml.internal.fastinfoset.util.DuplicateAttributeVerifier; aoqi@0: import java.util.logging.Level; aoqi@0: import java.util.logging.Logger; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.stax.FastInfosetStreamReader; aoqi@0: aoqi@0: /** aoqi@0: * The Fast Infoset StAX parser. aoqi@0: *

aoqi@0: * Instantiate this parser to parse a fast infoset document in accordance aoqi@0: * with the StAX API. aoqi@0: * aoqi@0: *

aoqi@0: * More than one fast infoset document may be decoded from the aoqi@0: * {@link java.io.InputStream}. aoqi@0: */ aoqi@0: public class StAXDocumentParser extends Decoder aoqi@0: implements XMLStreamReader, FastInfosetStreamReader, OctetBufferListener { aoqi@0: private static final Logger logger = Logger.getLogger(StAXDocumentParser.class.getName()); aoqi@0: aoqi@0: protected static final int INTERNAL_STATE_START_DOCUMENT = 0; aoqi@0: protected static final int INTERNAL_STATE_START_ELEMENT_TERMINATE = 1; aoqi@0: protected static final int INTERNAL_STATE_SINGLE_TERMINATE_ELEMENT_WITH_NAMESPACES = 2; aoqi@0: protected static final int INTERNAL_STATE_DOUBLE_TERMINATE_ELEMENT = 3; aoqi@0: protected static final int INTERNAL_STATE_END_DOCUMENT = 4; aoqi@0: protected static final int INTERNAL_STATE_VOID = -1; aoqi@0: aoqi@0: protected int _internalState; aoqi@0: aoqi@0: /** aoqi@0: * Current event aoqi@0: */ aoqi@0: protected int _eventType; aoqi@0: aoqi@0: /** aoqi@0: * Stack of qualified names and namespaces aoqi@0: */ aoqi@0: protected QualifiedName[] _qNameStack = new QualifiedName[32]; aoqi@0: protected int[] _namespaceAIIsStartStack = new int[32]; aoqi@0: protected int[] _namespaceAIIsEndStack = new int[32]; aoqi@0: protected int _stackCount = -1; aoqi@0: aoqi@0: protected String[] _namespaceAIIsPrefix = new String[32]; aoqi@0: protected String[] _namespaceAIIsNamespaceName = new String[32]; aoqi@0: protected int[] _namespaceAIIsPrefixIndex = new int[32]; aoqi@0: protected int _namespaceAIIsIndex; aoqi@0: aoqi@0: /** aoqi@0: * Namespaces associated with START_ELEMENT or END_ELEMENT aoqi@0: */ aoqi@0: protected int _currentNamespaceAIIsStart; aoqi@0: protected int _currentNamespaceAIIsEnd; aoqi@0: aoqi@0: /** aoqi@0: * Qualified name associated with START_ELEMENT or END_ELEMENT. aoqi@0: */ aoqi@0: protected QualifiedName _qualifiedName; aoqi@0: aoqi@0: /** aoqi@0: * List of attributes aoqi@0: */ aoqi@0: protected AttributesHolder _attributes = new AttributesHolder(); aoqi@0: aoqi@0: protected boolean _clearAttributes = false; aoqi@0: aoqi@0: /** aoqi@0: * Characters associated with event. aoqi@0: */ aoqi@0: protected char[] _characters; aoqi@0: protected int _charactersOffset; aoqi@0: aoqi@0: protected String _algorithmURI; aoqi@0: protected int _algorithmId; aoqi@0: protected boolean _isAlgorithmDataCloned; aoqi@0: protected byte[] _algorithmData; aoqi@0: protected int _algorithmDataOffset; aoqi@0: protected int _algorithmDataLength; aoqi@0: aoqi@0: /** aoqi@0: * State for processing instruction aoqi@0: */ aoqi@0: protected String _piTarget; aoqi@0: protected String _piData; aoqi@0: aoqi@0: protected NamespaceContextImpl _nsContext = new NamespaceContextImpl(); aoqi@0: aoqi@0: protected String _characterEncodingScheme; aoqi@0: aoqi@0: protected StAXManager _manager; aoqi@0: aoqi@0: public StAXDocumentParser() { aoqi@0: reset(); aoqi@0: _manager = new StAXManager(StAXManager.CONTEXT_READER); aoqi@0: } aoqi@0: aoqi@0: public StAXDocumentParser(InputStream s) { aoqi@0: this(); aoqi@0: setInputStream(s); aoqi@0: _manager = new StAXManager(StAXManager.CONTEXT_READER); aoqi@0: } aoqi@0: aoqi@0: public StAXDocumentParser(InputStream s, StAXManager manager) { aoqi@0: this(s); aoqi@0: _manager = manager; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void setInputStream(InputStream s) { aoqi@0: super.setInputStream(s); aoqi@0: reset(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void reset() { aoqi@0: super.reset(); aoqi@0: if (_internalState != INTERNAL_STATE_START_DOCUMENT && aoqi@0: _internalState != INTERNAL_STATE_END_DOCUMENT) { aoqi@0: aoqi@0: for (int i = _namespaceAIIsIndex - 1; i >= 0; i--) { aoqi@0: _prefixTable.popScopeWithPrefixEntry(_namespaceAIIsPrefixIndex[i]); aoqi@0: } aoqi@0: aoqi@0: _stackCount = -1; aoqi@0: aoqi@0: _namespaceAIIsIndex = 0; aoqi@0: _characters = null; aoqi@0: _algorithmData = null; aoqi@0: } aoqi@0: aoqi@0: _characterEncodingScheme = "UTF-8"; aoqi@0: _eventType = START_DOCUMENT; aoqi@0: _internalState = INTERNAL_STATE_START_DOCUMENT; aoqi@0: } aoqi@0: aoqi@0: protected void resetOnError() { aoqi@0: super.reset(); aoqi@0: aoqi@0: if (_v != null) { aoqi@0: _prefixTable.clearCompletely(); aoqi@0: } aoqi@0: _duplicateAttributeVerifier.clear(); aoqi@0: aoqi@0: _stackCount = -1; aoqi@0: aoqi@0: _namespaceAIIsIndex = 0; aoqi@0: _characters = null; aoqi@0: _algorithmData = null; aoqi@0: aoqi@0: _eventType = START_DOCUMENT; aoqi@0: _internalState = INTERNAL_STATE_START_DOCUMENT; aoqi@0: } aoqi@0: aoqi@0: // -- XMLStreamReader Interface ------------------------------------------- aoqi@0: aoqi@0: public Object getProperty(java.lang.String name) aoqi@0: throws java.lang.IllegalArgumentException { aoqi@0: if (_manager != null) { aoqi@0: return _manager.getProperty(name); aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public int next() throws XMLStreamException { aoqi@0: try { aoqi@0: if (_internalState != INTERNAL_STATE_VOID) { aoqi@0: switch (_internalState) { aoqi@0: case INTERNAL_STATE_START_DOCUMENT: aoqi@0: decodeHeader(); aoqi@0: processDII(); aoqi@0: aoqi@0: _internalState = INTERNAL_STATE_VOID; aoqi@0: break; aoqi@0: case INTERNAL_STATE_START_ELEMENT_TERMINATE: aoqi@0: if (_currentNamespaceAIIsEnd > 0) { aoqi@0: for (int i = _currentNamespaceAIIsEnd - 1; i >= _currentNamespaceAIIsStart; i--) { aoqi@0: _prefixTable.popScopeWithPrefixEntry(_namespaceAIIsPrefixIndex[i]); aoqi@0: } aoqi@0: _namespaceAIIsIndex = _currentNamespaceAIIsStart; aoqi@0: } aoqi@0: aoqi@0: // Pop information off the stack aoqi@0: popStack(); aoqi@0: aoqi@0: _internalState = INTERNAL_STATE_VOID; aoqi@0: return _eventType = END_ELEMENT; aoqi@0: case INTERNAL_STATE_SINGLE_TERMINATE_ELEMENT_WITH_NAMESPACES: aoqi@0: // Undeclare namespaces aoqi@0: for (int i = _currentNamespaceAIIsEnd - 1; i >= _currentNamespaceAIIsStart; i--) { aoqi@0: _prefixTable.popScopeWithPrefixEntry(_namespaceAIIsPrefixIndex[i]); aoqi@0: } aoqi@0: _namespaceAIIsIndex = _currentNamespaceAIIsStart; aoqi@0: _internalState = INTERNAL_STATE_VOID; aoqi@0: break; aoqi@0: case INTERNAL_STATE_DOUBLE_TERMINATE_ELEMENT: aoqi@0: // Undeclare namespaces aoqi@0: if (_currentNamespaceAIIsEnd > 0) { aoqi@0: for (int i = _currentNamespaceAIIsEnd - 1; i >= _currentNamespaceAIIsStart; i--) { aoqi@0: _prefixTable.popScopeWithPrefixEntry(_namespaceAIIsPrefixIndex[i]); aoqi@0: } aoqi@0: _namespaceAIIsIndex = _currentNamespaceAIIsStart; aoqi@0: } aoqi@0: aoqi@0: if (_stackCount == -1) { aoqi@0: _internalState = INTERNAL_STATE_END_DOCUMENT; aoqi@0: return _eventType = END_DOCUMENT; aoqi@0: } aoqi@0: aoqi@0: // Pop information off the stack aoqi@0: popStack(); aoqi@0: aoqi@0: _internalState = (_currentNamespaceAIIsEnd > 0) ? aoqi@0: INTERNAL_STATE_SINGLE_TERMINATE_ELEMENT_WITH_NAMESPACES : aoqi@0: INTERNAL_STATE_VOID; aoqi@0: return _eventType = END_ELEMENT; aoqi@0: case INTERNAL_STATE_END_DOCUMENT: aoqi@0: throw new NoSuchElementException(CommonResourceBundle.getInstance().getString("message.noMoreEvents")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Reset internal state aoqi@0: _characters = null; aoqi@0: _algorithmData = null; aoqi@0: _currentNamespaceAIIsEnd = 0; aoqi@0: aoqi@0: // Process information item aoqi@0: final int b = read(); aoqi@0: switch(DecoderStateTables.EII(b)) { aoqi@0: case DecoderStateTables.EII_NO_AIIS_INDEX_SMALL: aoqi@0: processEII(_elementNameTable._array[b], false); aoqi@0: return _eventType; aoqi@0: case DecoderStateTables.EII_AIIS_INDEX_SMALL: aoqi@0: processEII(_elementNameTable._array[b & EncodingConstants.INTEGER_3RD_BIT_SMALL_MASK], true); aoqi@0: return _eventType; aoqi@0: case DecoderStateTables.EII_INDEX_MEDIUM: aoqi@0: processEII(processEIIIndexMedium(b), (b & EncodingConstants.ELEMENT_ATTRIBUTE_FLAG) > 0); aoqi@0: return _eventType; aoqi@0: case DecoderStateTables.EII_INDEX_LARGE: aoqi@0: processEII(processEIIIndexLarge(b), (b & EncodingConstants.ELEMENT_ATTRIBUTE_FLAG) > 0); aoqi@0: return _eventType; aoqi@0: case DecoderStateTables.EII_LITERAL: aoqi@0: { aoqi@0: final QualifiedName qn = processLiteralQualifiedName( aoqi@0: b & EncodingConstants.LITERAL_QNAME_PREFIX_NAMESPACE_NAME_MASK, aoqi@0: _elementNameTable.getNext()); aoqi@0: _elementNameTable.add(qn); aoqi@0: processEII(qn, (b & EncodingConstants.ELEMENT_ATTRIBUTE_FLAG) > 0); aoqi@0: return _eventType; aoqi@0: } aoqi@0: case DecoderStateTables.EII_NAMESPACES: aoqi@0: processEIIWithNamespaces((b & EncodingConstants.ELEMENT_ATTRIBUTE_FLAG) > 0); aoqi@0: return _eventType; aoqi@0: case DecoderStateTables.CII_UTF8_SMALL_LENGTH: aoqi@0: _octetBufferLength = (b & EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_MASK) aoqi@0: + 1; aoqi@0: processUtf8CharacterString(b); aoqi@0: return _eventType = CHARACTERS; aoqi@0: case DecoderStateTables.CII_UTF8_MEDIUM_LENGTH: aoqi@0: _octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT; aoqi@0: processUtf8CharacterString(b); aoqi@0: return _eventType = CHARACTERS; aoqi@0: case DecoderStateTables.CII_UTF8_LARGE_LENGTH: aoqi@0: _octetBufferLength = ((read() << 24) | aoqi@0: (read() << 16) | aoqi@0: (read() << 8) | aoqi@0: read()) aoqi@0: + EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT; aoqi@0: processUtf8CharacterString(b); aoqi@0: return _eventType = CHARACTERS; aoqi@0: case DecoderStateTables.CII_UTF16_SMALL_LENGTH: aoqi@0: _octetBufferLength = (b & EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_MASK) aoqi@0: + 1; aoqi@0: processUtf16CharacterString(b); aoqi@0: return _eventType = CHARACTERS; aoqi@0: case DecoderStateTables.CII_UTF16_MEDIUM_LENGTH: aoqi@0: _octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT; aoqi@0: processUtf16CharacterString(b); aoqi@0: return _eventType = CHARACTERS; aoqi@0: case DecoderStateTables.CII_UTF16_LARGE_LENGTH: aoqi@0: _octetBufferLength = ((read() << 24) | aoqi@0: (read() << 16) | aoqi@0: (read() << 8) | aoqi@0: read()) aoqi@0: + EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT; aoqi@0: processUtf16CharacterString(b); aoqi@0: return _eventType = CHARACTERS; aoqi@0: case DecoderStateTables.CII_RA: aoqi@0: { aoqi@0: final boolean addToTable = (b & EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG) > 0; aoqi@0: aoqi@0: _identifier = (b & 0x02) << 6; aoqi@0: final int b2 = read(); aoqi@0: _identifier |= (b2 & 0xFC) >> 2; aoqi@0: aoqi@0: decodeOctetsOnSeventhBitOfNonIdentifyingStringOnThirdBit(b2); aoqi@0: aoqi@0: decodeRestrictedAlphabetAsCharBuffer(); aoqi@0: aoqi@0: if (addToTable) { aoqi@0: _charactersOffset = _characterContentChunkTable.add(_charBuffer, _charBufferLength); aoqi@0: _characters = _characterContentChunkTable._array; aoqi@0: } else { aoqi@0: _characters = _charBuffer; aoqi@0: _charactersOffset = 0; aoqi@0: } aoqi@0: return _eventType = CHARACTERS; aoqi@0: } aoqi@0: case DecoderStateTables.CII_EA: aoqi@0: { aoqi@0: final boolean addToTable = (b & EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG) > 0; aoqi@0: // Decode encoding algorithm integer aoqi@0: _algorithmId = (b & 0x02) << 6; aoqi@0: final int b2 = read(); aoqi@0: _algorithmId |= (b2 & 0xFC) >> 2; aoqi@0: aoqi@0: decodeOctetsOnSeventhBitOfNonIdentifyingStringOnThirdBit(b2); aoqi@0: processCIIEncodingAlgorithm(addToTable); aoqi@0: aoqi@0: if (_algorithmId == EncodingAlgorithmIndexes.CDATA) { aoqi@0: return _eventType = CDATA; aoqi@0: } aoqi@0: aoqi@0: return _eventType = CHARACTERS; aoqi@0: } aoqi@0: case DecoderStateTables.CII_INDEX_SMALL: aoqi@0: { aoqi@0: final int index = b & EncodingConstants.INTEGER_4TH_BIT_SMALL_MASK; aoqi@0: _characterContentChunkTable._cachedIndex = index; aoqi@0: aoqi@0: _characters = _characterContentChunkTable._array; aoqi@0: _charactersOffset = _characterContentChunkTable._offset[index]; aoqi@0: _charBufferLength = _characterContentChunkTable._length[index]; aoqi@0: return _eventType = CHARACTERS; aoqi@0: } aoqi@0: case DecoderStateTables.CII_INDEX_MEDIUM: aoqi@0: { aoqi@0: final int index = (((b & EncodingConstants.INTEGER_4TH_BIT_MEDIUM_MASK) << 8) | read()) aoqi@0: + EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT; aoqi@0: _characterContentChunkTable._cachedIndex = index; aoqi@0: aoqi@0: _characters = _characterContentChunkTable._array; aoqi@0: _charactersOffset = _characterContentChunkTable._offset[index]; aoqi@0: _charBufferLength = _characterContentChunkTable._length[index]; aoqi@0: return _eventType = CHARACTERS; aoqi@0: } aoqi@0: case DecoderStateTables.CII_INDEX_LARGE: aoqi@0: { aoqi@0: final int index = (((b & EncodingConstants.INTEGER_4TH_BIT_LARGE_MASK) << 16) | aoqi@0: (read() << 8) | aoqi@0: read()) aoqi@0: + EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT; aoqi@0: _characterContentChunkTable._cachedIndex = index; aoqi@0: aoqi@0: _characters = _characterContentChunkTable._array; aoqi@0: _charactersOffset = _characterContentChunkTable._offset[index]; aoqi@0: _charBufferLength = _characterContentChunkTable._length[index]; aoqi@0: return _eventType = CHARACTERS; aoqi@0: } aoqi@0: case DecoderStateTables.CII_INDEX_LARGE_LARGE: aoqi@0: { aoqi@0: final int index = ((read() << 16) | aoqi@0: (read() << 8) | aoqi@0: read()) aoqi@0: + EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT; aoqi@0: _characterContentChunkTable._cachedIndex = index; aoqi@0: aoqi@0: _characters = _characterContentChunkTable._array; aoqi@0: _charactersOffset = _characterContentChunkTable._offset[index]; aoqi@0: _charBufferLength = _characterContentChunkTable._length[index]; aoqi@0: return _eventType = CHARACTERS; aoqi@0: } aoqi@0: case DecoderStateTables.COMMENT_II: aoqi@0: processCommentII(); aoqi@0: return _eventType; aoqi@0: case DecoderStateTables.PROCESSING_INSTRUCTION_II: aoqi@0: processProcessingII(); aoqi@0: return _eventType; aoqi@0: case DecoderStateTables.UNEXPANDED_ENTITY_REFERENCE_II: aoqi@0: { aoqi@0: processUnexpandedEntityReference(b); aoqi@0: // Skip the reference aoqi@0: return next(); aoqi@0: } aoqi@0: case DecoderStateTables.TERMINATOR_DOUBLE: aoqi@0: if (_stackCount != -1) { aoqi@0: // Pop information off the stack aoqi@0: popStack(); aoqi@0: aoqi@0: _internalState = INTERNAL_STATE_DOUBLE_TERMINATE_ELEMENT; aoqi@0: return _eventType = END_ELEMENT; aoqi@0: } aoqi@0: aoqi@0: _internalState = INTERNAL_STATE_END_DOCUMENT; aoqi@0: return _eventType = END_DOCUMENT; aoqi@0: case DecoderStateTables.TERMINATOR_SINGLE: aoqi@0: if (_stackCount != -1) { aoqi@0: // Pop information off the stack aoqi@0: popStack(); aoqi@0: aoqi@0: if (_currentNamespaceAIIsEnd > 0) { aoqi@0: _internalState = INTERNAL_STATE_SINGLE_TERMINATE_ELEMENT_WITH_NAMESPACES; aoqi@0: } aoqi@0: return _eventType = END_ELEMENT; aoqi@0: } aoqi@0: aoqi@0: _internalState = INTERNAL_STATE_END_DOCUMENT; aoqi@0: return _eventType = END_DOCUMENT; aoqi@0: default: aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.IllegalStateDecodingEII")); aoqi@0: } aoqi@0: } catch (IOException e) { aoqi@0: resetOnError(); aoqi@0: logger.log(Level.FINE, "next() exception", e); aoqi@0: throw new XMLStreamException(e); aoqi@0: } catch (FastInfosetException e) { aoqi@0: resetOnError(); aoqi@0: logger.log(Level.FINE, "next() exception", e); aoqi@0: throw new XMLStreamException(e); aoqi@0: } catch (RuntimeException e) { aoqi@0: resetOnError(); aoqi@0: logger.log(Level.FINE, "next() exception", e); aoqi@0: throw e; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private final void processUtf8CharacterString(final int b) throws IOException { aoqi@0: if ((b & EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG) > 0) { aoqi@0: _characterContentChunkTable.ensureSize(_octetBufferLength); aoqi@0: _characters = _characterContentChunkTable._array; aoqi@0: _charactersOffset = _characterContentChunkTable._arrayIndex; aoqi@0: decodeUtf8StringAsCharBuffer(_characterContentChunkTable._array, _charactersOffset); aoqi@0: _characterContentChunkTable.add(_charBufferLength); aoqi@0: } else { aoqi@0: decodeUtf8StringAsCharBuffer(); aoqi@0: _characters = _charBuffer; aoqi@0: _charactersOffset = 0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private final void processUtf16CharacterString(final int b) throws IOException { aoqi@0: decodeUtf16StringAsCharBuffer(); aoqi@0: if ((b & EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG) > 0) { aoqi@0: _charactersOffset = _characterContentChunkTable.add(_charBuffer, _charBufferLength); aoqi@0: _characters = _characterContentChunkTable._array; aoqi@0: } else { aoqi@0: _characters = _charBuffer; aoqi@0: _charactersOffset = 0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void popStack() { aoqi@0: // Pop information off the stack aoqi@0: _qualifiedName = _qNameStack[_stackCount]; aoqi@0: _currentNamespaceAIIsStart = _namespaceAIIsStartStack[_stackCount]; aoqi@0: _currentNamespaceAIIsEnd = _namespaceAIIsEndStack[_stackCount]; aoqi@0: _qNameStack[_stackCount--] = null; aoqi@0: } aoqi@0: aoqi@0: /** Test if the current event is of the given type and if the namespace and name match the current namespace and name of the current event. aoqi@0: * If the namespaceURI is null it is not checked for equality, if the localName is null it is not checked for equality. aoqi@0: * @param type the event type aoqi@0: * @param namespaceURI the uri of the event, may be null aoqi@0: * @param localName the localName of the event, may be null aoqi@0: * @throws XMLStreamException if the required values are not matched. aoqi@0: */ aoqi@0: public final void require(int type, String namespaceURI, String localName) aoqi@0: throws XMLStreamException { aoqi@0: if( type != _eventType) aoqi@0: throw new XMLStreamException(CommonResourceBundle.getInstance().getString("message.eventTypeNotMatch", new Object[]{getEventTypeString(type)})); aoqi@0: if( namespaceURI != null && !namespaceURI.equals(getNamespaceURI()) ) aoqi@0: throw new XMLStreamException(CommonResourceBundle.getInstance().getString("message.namespaceURINotMatch", new Object[]{namespaceURI})); aoqi@0: if(localName != null && !localName.equals(getLocalName())) aoqi@0: throw new XMLStreamException(CommonResourceBundle.getInstance().getString("message.localNameNotMatch", new Object[]{localName})); aoqi@0: } aoqi@0: aoqi@0: /** Reads the content of a text-only element. Precondition: aoqi@0: * the current event is START_ELEMENT. Postcondition: aoqi@0: * The current event is the corresponding END_ELEMENT. aoqi@0: * @throws XMLStreamException if the current event is not a START_ELEMENT or if aoqi@0: * a non text element is encountered aoqi@0: */ aoqi@0: public final String getElementText() throws XMLStreamException { aoqi@0: aoqi@0: if(getEventType() != START_ELEMENT) { aoqi@0: throw new XMLStreamException( aoqi@0: CommonResourceBundle.getInstance().getString("message.mustBeOnSTARTELEMENT"), getLocation()); aoqi@0: } aoqi@0: //current is StartElement, move to the next aoqi@0: next(); aoqi@0: return getElementText(true); aoqi@0: } aoqi@0: /** aoqi@0: * @param startElementRead flag if start element has already been read aoqi@0: */ aoqi@0: public final String getElementText(boolean startElementRead) throws XMLStreamException { aoqi@0: if (!startElementRead) { aoqi@0: throw new XMLStreamException( aoqi@0: CommonResourceBundle.getInstance().getString("message.mustBeOnSTARTELEMENT"), getLocation()); aoqi@0: } aoqi@0: int eventType = getEventType(); aoqi@0: StringBuilder content = new StringBuilder(); aoqi@0: while(eventType != END_ELEMENT ) { aoqi@0: if(eventType == CHARACTERS aoqi@0: || eventType == CDATA aoqi@0: || eventType == SPACE aoqi@0: || eventType == ENTITY_REFERENCE) { aoqi@0: content.append(getText()); aoqi@0: } else if(eventType == PROCESSING_INSTRUCTION aoqi@0: || eventType == COMMENT) { aoqi@0: // skipping aoqi@0: } else if(eventType == END_DOCUMENT) { aoqi@0: throw new XMLStreamException(CommonResourceBundle.getInstance().getString("message.unexpectedEOF")); aoqi@0: } else if(eventType == START_ELEMENT) { aoqi@0: throw new XMLStreamException( aoqi@0: CommonResourceBundle.getInstance().getString("message.getElementTextExpectTextOnly"), getLocation()); aoqi@0: } else { aoqi@0: throw new XMLStreamException( aoqi@0: CommonResourceBundle.getInstance().getString("message.unexpectedEventType")+ getEventTypeString(eventType), getLocation()); aoqi@0: } aoqi@0: eventType = next(); aoqi@0: } aoqi@0: return content.toString(); aoqi@0: } aoqi@0: aoqi@0: /** Skips any white space (isWhiteSpace() returns true), COMMENT, aoqi@0: * or PROCESSING_INSTRUCTION, aoqi@0: * until a START_ELEMENT or END_ELEMENT is reached. aoqi@0: * If other than white space characters, COMMENT, PROCESSING_INSTRUCTION, START_ELEMENT, END_ELEMENT aoqi@0: * are encountered, an exception is thrown. This method should aoqi@0: * be used when processing element-only content seperated by white space. aoqi@0: * This method should aoqi@0: * be used when processing element-only content because aoqi@0: * the parser is not able to recognize ignorable whitespace if aoqi@0: * then DTD is missing or not interpreted. aoqi@0: * @return the event type of the element read aoqi@0: * @throws XMLStreamException if the current event is not white space aoqi@0: */ aoqi@0: public final int nextTag() throws XMLStreamException { aoqi@0: next(); aoqi@0: return nextTag(true); aoqi@0: } aoqi@0: /** if the current tag has already read, such as in the case EventReader's aoqi@0: * peek() has been called, the current cursor should not move before the loop aoqi@0: */ aoqi@0: public final int nextTag(boolean currentTagRead) throws XMLStreamException { aoqi@0: int eventType = getEventType(); aoqi@0: if (!currentTagRead) { aoqi@0: eventType = next(); aoqi@0: } aoqi@0: while((eventType == CHARACTERS && isWhiteSpace()) // skip whitespace aoqi@0: || (eventType == CDATA && isWhiteSpace()) aoqi@0: || eventType == SPACE aoqi@0: || eventType == PROCESSING_INSTRUCTION aoqi@0: || eventType == COMMENT) { aoqi@0: eventType = next(); aoqi@0: } aoqi@0: if (eventType != START_ELEMENT && eventType != END_ELEMENT) { aoqi@0: throw new XMLStreamException(CommonResourceBundle.getInstance().getString("message.expectedStartOrEnd"), getLocation()); aoqi@0: } aoqi@0: return eventType; aoqi@0: } aoqi@0: aoqi@0: public final boolean hasNext() throws XMLStreamException { aoqi@0: return (_eventType != END_DOCUMENT); aoqi@0: } aoqi@0: aoqi@0: public void close() throws XMLStreamException { aoqi@0: try { aoqi@0: super.closeIfRequired(); aoqi@0: } catch (IOException ex) { aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final String getNamespaceURI(String prefix) { aoqi@0: String namespace = getNamespaceDecl(prefix); aoqi@0: if (namespace == null) { aoqi@0: if (prefix == null) { aoqi@0: throw new IllegalArgumentException(CommonResourceBundle.getInstance().getString("message.nullPrefix")); aoqi@0: } aoqi@0: return null; // unbound aoqi@0: } aoqi@0: return namespace; aoqi@0: } aoqi@0: aoqi@0: public final boolean isStartElement() { aoqi@0: return (_eventType == START_ELEMENT); aoqi@0: } aoqi@0: aoqi@0: public final boolean isEndElement() { aoqi@0: return (_eventType == END_ELEMENT); aoqi@0: } aoqi@0: aoqi@0: public final boolean isCharacters() { aoqi@0: return (_eventType == CHARACTERS); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Returns true if the cursor points to a character data event that consists of all whitespace aoqi@0: * Application calling this method needs to cache the value and avoid calling this method again aoqi@0: * for the same event. aoqi@0: * @return true if the cursor points to all whitespace, false otherwise aoqi@0: */ aoqi@0: public final boolean isWhiteSpace() { aoqi@0: if(isCharacters() || (_eventType == CDATA)){ aoqi@0: char [] ch = this.getTextCharacters(); aoqi@0: int start = this.getTextStart(); aoqi@0: int length = this.getTextLength(); aoqi@0: for (int i = start; i < start + length; i++){ aoqi@0: if(!XMLChar.isSpace(ch[i])){ aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: public final String getAttributeValue(String namespaceURI, String localName) { aoqi@0: if (_eventType != START_ELEMENT) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); aoqi@0: } aoqi@0: aoqi@0: if (localName == null) aoqi@0: throw new IllegalArgumentException(); aoqi@0: aoqi@0: // Search for the attributes in _attributes aoqi@0: if (namespaceURI != null) { aoqi@0: for (int i = 0; i < _attributes.getLength(); i++) { aoqi@0: if (_attributes.getLocalName(i).equals(localName) && aoqi@0: _attributes.getURI(i).equals(namespaceURI)) { aoqi@0: return _attributes.getValue(i); aoqi@0: } aoqi@0: } aoqi@0: } else { aoqi@0: for (int i = 0; i < _attributes.getLength(); i++) { aoqi@0: if (_attributes.getLocalName(i).equals(localName)) { aoqi@0: return _attributes.getValue(i); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public final int getAttributeCount() { aoqi@0: if (_eventType != START_ELEMENT) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); aoqi@0: } aoqi@0: aoqi@0: return _attributes.getLength(); aoqi@0: } aoqi@0: aoqi@0: public final javax.xml.namespace.QName getAttributeName(int index) { aoqi@0: if (_eventType != START_ELEMENT) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); aoqi@0: } aoqi@0: return _attributes.getQualifiedName(index).getQName(); aoqi@0: } aoqi@0: aoqi@0: public final String getAttributeNamespace(int index) { aoqi@0: if (_eventType != START_ELEMENT) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); aoqi@0: } aoqi@0: aoqi@0: return _attributes.getURI(index); aoqi@0: } aoqi@0: aoqi@0: public final String getAttributeLocalName(int index) { aoqi@0: if (_eventType != START_ELEMENT) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); aoqi@0: } aoqi@0: return _attributes.getLocalName(index); aoqi@0: } aoqi@0: aoqi@0: public final String getAttributePrefix(int index) { aoqi@0: if (_eventType != START_ELEMENT) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); aoqi@0: } aoqi@0: return _attributes.getPrefix(index); aoqi@0: } aoqi@0: aoqi@0: public final String getAttributeType(int index) { aoqi@0: if (_eventType != START_ELEMENT) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); aoqi@0: } aoqi@0: return _attributes.getType(index); aoqi@0: } aoqi@0: aoqi@0: public final String getAttributeValue(int index) { aoqi@0: if (_eventType != START_ELEMENT) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); aoqi@0: } aoqi@0: return _attributes.getValue(index); aoqi@0: } aoqi@0: aoqi@0: public final boolean isAttributeSpecified(int index) { aoqi@0: return false; // non-validating parser aoqi@0: } aoqi@0: aoqi@0: public final int getNamespaceCount() { aoqi@0: if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { aoqi@0: return (_currentNamespaceAIIsEnd > 0) ? (_currentNamespaceAIIsEnd - _currentNamespaceAIIsStart) : 0; aoqi@0: } else { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetNamespaceCount")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final String getNamespacePrefix(int index) { aoqi@0: if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { aoqi@0: return _namespaceAIIsPrefix[_currentNamespaceAIIsStart + index]; aoqi@0: } else { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetNamespacePrefix")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final String getNamespaceURI(int index) { aoqi@0: if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { aoqi@0: return _namespaceAIIsNamespaceName[_currentNamespaceAIIsStart + index]; aoqi@0: } else { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetNamespacePrefix")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final NamespaceContext getNamespaceContext() { aoqi@0: return _nsContext; aoqi@0: } aoqi@0: aoqi@0: public final int getEventType() { aoqi@0: return _eventType; aoqi@0: } aoqi@0: aoqi@0: public final String getText() { aoqi@0: if (_characters == null) { aoqi@0: checkTextState(); aoqi@0: } aoqi@0: aoqi@0: if (_characters == _characterContentChunkTable._array) { aoqi@0: return _characterContentChunkTable.getString(_characterContentChunkTable._cachedIndex); aoqi@0: } else { aoqi@0: return new String(_characters, _charactersOffset, _charBufferLength); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final char[] getTextCharacters() { aoqi@0: if (_characters == null) { aoqi@0: checkTextState(); aoqi@0: } aoqi@0: aoqi@0: return _characters; aoqi@0: } aoqi@0: aoqi@0: public final int getTextStart() { aoqi@0: if (_characters == null) { aoqi@0: checkTextState(); aoqi@0: } aoqi@0: aoqi@0: return _charactersOffset; aoqi@0: } aoqi@0: aoqi@0: public final int getTextLength() { aoqi@0: if (_characters == null) { aoqi@0: checkTextState(); aoqi@0: } aoqi@0: aoqi@0: return _charBufferLength; aoqi@0: } aoqi@0: aoqi@0: public final int getTextCharacters(int sourceStart, char[] target, aoqi@0: int targetStart, int length) throws XMLStreamException { aoqi@0: if (_characters == null) { aoqi@0: checkTextState(); aoqi@0: } aoqi@0: aoqi@0: try { aoqi@0: int bytesToCopy = Math.min(_charBufferLength, length); aoqi@0: System.arraycopy(_characters, _charactersOffset + sourceStart, aoqi@0: target, targetStart, bytesToCopy); aoqi@0: return bytesToCopy; aoqi@0: } catch (IndexOutOfBoundsException e) { aoqi@0: throw new XMLStreamException(e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void checkTextState() { aoqi@0: if (_algorithmData == null) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.InvalidStateForText")); aoqi@0: } aoqi@0: aoqi@0: try { aoqi@0: convertEncodingAlgorithmDataToCharacters(); aoqi@0: } catch (Exception e) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.InvalidStateForText")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final String getEncoding() { aoqi@0: return _characterEncodingScheme; aoqi@0: } aoqi@0: aoqi@0: public final boolean hasText() { aoqi@0: return (_characters != null); aoqi@0: } aoqi@0: aoqi@0: public final Location getLocation() { aoqi@0: //location should be created in next() aoqi@0: //returns a nil location for now aoqi@0: return EventLocation.getNilLocation(); aoqi@0: } aoqi@0: aoqi@0: public final QName getName() { aoqi@0: if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { aoqi@0: return _qualifiedName.getQName(); aoqi@0: } else { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetName")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final String getLocalName() { aoqi@0: if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { aoqi@0: return _qualifiedName.localName; aoqi@0: } else { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetLocalName")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final boolean hasName() { aoqi@0: return (_eventType == START_ELEMENT || _eventType == END_ELEMENT); aoqi@0: } aoqi@0: aoqi@0: public final String getNamespaceURI() { aoqi@0: if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { aoqi@0: return _qualifiedName.namespaceName; aoqi@0: } else { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetNamespaceURI")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final String getPrefix() { aoqi@0: if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { aoqi@0: return _qualifiedName.prefix; aoqi@0: } else { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetPrefix")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final String getVersion() { aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public final boolean isStandalone() { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: public final boolean standaloneSet() { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: public final String getCharacterEncodingScheme() { aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public final String getPITarget() { aoqi@0: if (_eventType != PROCESSING_INSTRUCTION) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetPITarget")); aoqi@0: } aoqi@0: aoqi@0: return _piTarget; aoqi@0: } aoqi@0: aoqi@0: public final String getPIData() { aoqi@0: if (_eventType != PROCESSING_INSTRUCTION) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetPIData")); aoqi@0: } aoqi@0: aoqi@0: return _piData; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: public final String getNameString() { aoqi@0: if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { aoqi@0: return _qualifiedName.getQNameString(); aoqi@0: } else { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetName")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final String getAttributeNameString(int index) { aoqi@0: if (_eventType != START_ELEMENT) { aoqi@0: throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); aoqi@0: } aoqi@0: return _attributes.getQualifiedName(index).getQNameString(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: public final String getTextAlgorithmURI() { aoqi@0: return _algorithmURI; aoqi@0: } aoqi@0: aoqi@0: public final int getTextAlgorithmIndex() { aoqi@0: return _algorithmId; aoqi@0: } aoqi@0: aoqi@0: public final boolean hasTextAlgorithmBytes() { aoqi@0: return _algorithmData != null; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * Returns the byte[], which represents text algorithms. aoqi@0: * @deprecated was deprecated due to security reasons. Now the method return cloned byte[]. aoqi@0: * aoqi@0: * @return aoqi@0: */ aoqi@0: public final byte[] getTextAlgorithmBytes() { aoqi@0: // Do not return the actual _algorithmData due to security reasons aoqi@0: // return _algorithmData; aoqi@0: if (_algorithmData == null) { aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: final byte[] algorithmData = new byte[_algorithmData.length]; aoqi@0: System.arraycopy(_algorithmData, 0, algorithmData, 0, _algorithmData.length); aoqi@0: return algorithmData; aoqi@0: } aoqi@0: aoqi@0: public final byte[] getTextAlgorithmBytesClone() { aoqi@0: if (_algorithmData == null) { aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: byte[] algorithmData = new byte[_algorithmDataLength]; aoqi@0: System.arraycopy(_algorithmData, _algorithmDataOffset, algorithmData, 0, _algorithmDataLength); aoqi@0: return algorithmData; aoqi@0: } aoqi@0: aoqi@0: public final int getTextAlgorithmStart() { aoqi@0: return _algorithmDataOffset; aoqi@0: } aoqi@0: aoqi@0: public final int getTextAlgorithmLength() { aoqi@0: return _algorithmDataLength; aoqi@0: } aoqi@0: aoqi@0: public final int getTextAlgorithmBytes(int sourceStart, byte[] target, aoqi@0: int targetStart, int length) throws XMLStreamException { aoqi@0: try { aoqi@0: System.arraycopy(_algorithmData, sourceStart, target, aoqi@0: targetStart, length); aoqi@0: return length; aoqi@0: } catch (IndexOutOfBoundsException e) { aoqi@0: throw new XMLStreamException(e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // FastInfosetStreamReader impl aoqi@0: aoqi@0: public final int peekNext() throws XMLStreamException { aoqi@0: try { aoqi@0: switch(DecoderStateTables.EII(peek(this))) { aoqi@0: case DecoderStateTables.EII_NO_AIIS_INDEX_SMALL: aoqi@0: case DecoderStateTables.EII_AIIS_INDEX_SMALL: aoqi@0: case DecoderStateTables.EII_INDEX_MEDIUM: aoqi@0: case DecoderStateTables.EII_INDEX_LARGE: aoqi@0: case DecoderStateTables.EII_LITERAL: aoqi@0: case DecoderStateTables.EII_NAMESPACES: aoqi@0: return START_ELEMENT; aoqi@0: case DecoderStateTables.CII_UTF8_SMALL_LENGTH: aoqi@0: case DecoderStateTables.CII_UTF8_MEDIUM_LENGTH: aoqi@0: case DecoderStateTables.CII_UTF8_LARGE_LENGTH: aoqi@0: case DecoderStateTables.CII_UTF16_SMALL_LENGTH: aoqi@0: case DecoderStateTables.CII_UTF16_MEDIUM_LENGTH: aoqi@0: case DecoderStateTables.CII_UTF16_LARGE_LENGTH: aoqi@0: case DecoderStateTables.CII_RA: aoqi@0: case DecoderStateTables.CII_EA: aoqi@0: case DecoderStateTables.CII_INDEX_SMALL: aoqi@0: case DecoderStateTables.CII_INDEX_MEDIUM: aoqi@0: case DecoderStateTables.CII_INDEX_LARGE: aoqi@0: case DecoderStateTables.CII_INDEX_LARGE_LARGE: aoqi@0: return CHARACTERS; aoqi@0: case DecoderStateTables.COMMENT_II: aoqi@0: return COMMENT; aoqi@0: case DecoderStateTables.PROCESSING_INSTRUCTION_II: aoqi@0: return PROCESSING_INSTRUCTION; aoqi@0: case DecoderStateTables.UNEXPANDED_ENTITY_REFERENCE_II: aoqi@0: return ENTITY_REFERENCE; aoqi@0: case DecoderStateTables.TERMINATOR_DOUBLE: aoqi@0: case DecoderStateTables.TERMINATOR_SINGLE: aoqi@0: return (_stackCount != -1) ? END_ELEMENT : END_DOCUMENT; aoqi@0: default: aoqi@0: throw new FastInfosetException( aoqi@0: CommonResourceBundle.getInstance().getString("message.IllegalStateDecodingEII")); aoqi@0: } aoqi@0: } catch (IOException e) { aoqi@0: throw new XMLStreamException(e); aoqi@0: } catch (FastInfosetException e) { aoqi@0: throw new XMLStreamException(e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void onBeforeOctetBufferOverwrite() { aoqi@0: if (_algorithmData != null) { aoqi@0: _algorithmData = getTextAlgorithmBytesClone(); aoqi@0: _algorithmDataOffset = 0; aoqi@0: _isAlgorithmDataCloned = true; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Faster access methods without checks aoqi@0: aoqi@0: public final int accessNamespaceCount() { aoqi@0: return (_currentNamespaceAIIsEnd > 0) ? (_currentNamespaceAIIsEnd - _currentNamespaceAIIsStart) : 0; aoqi@0: } aoqi@0: aoqi@0: public final String accessLocalName() { aoqi@0: return _qualifiedName.localName; aoqi@0: } aoqi@0: aoqi@0: public final String accessNamespaceURI() { aoqi@0: return _qualifiedName.namespaceName; aoqi@0: } aoqi@0: aoqi@0: public final String accessPrefix() { aoqi@0: return _qualifiedName.prefix; aoqi@0: } aoqi@0: aoqi@0: public final char[] accessTextCharacters() { aoqi@0: if (_characters == null) return null; aoqi@0: aoqi@0: // we return a cloned version of _characters aoqi@0: final char[] clonedCharacters = new char[_characters.length]; aoqi@0: System.arraycopy(_characters, 0, clonedCharacters, 0, _characters.length); aoqi@0: return clonedCharacters; aoqi@0: } aoqi@0: aoqi@0: public final int accessTextStart() { aoqi@0: return _charactersOffset; aoqi@0: } aoqi@0: aoqi@0: public final int accessTextLength() { aoqi@0: return _charBufferLength; aoqi@0: } aoqi@0: aoqi@0: // aoqi@0: aoqi@0: protected final void processDII() throws FastInfosetException, IOException { aoqi@0: final int b = read(); aoqi@0: if (b > 0) { aoqi@0: processDIIOptionalProperties(b); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void processDIIOptionalProperties(int b) throws FastInfosetException, IOException { aoqi@0: // Optimize for the most common case aoqi@0: if (b == EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG) { aoqi@0: decodeInitialVocabulary(); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: if ((b & EncodingConstants.DOCUMENT_ADDITIONAL_DATA_FLAG) > 0) { aoqi@0: decodeAdditionalData(); aoqi@0: /* aoqi@0: * TODO aoqi@0: * how to report the additional data? aoqi@0: */ aoqi@0: } aoqi@0: aoqi@0: if ((b & EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG) > 0) { aoqi@0: decodeInitialVocabulary(); aoqi@0: } aoqi@0: aoqi@0: if ((b & EncodingConstants.DOCUMENT_NOTATIONS_FLAG) > 0) { aoqi@0: decodeNotations(); aoqi@0: /* aoqi@0: try { aoqi@0: _dtdHandler.notationDecl(name, public_identifier, system_identifier); aoqi@0: } catch (SAXException e) { aoqi@0: throw new IOException("NotationsDeclarationII"); aoqi@0: } aoqi@0: */ aoqi@0: } aoqi@0: aoqi@0: if ((b & EncodingConstants.DOCUMENT_UNPARSED_ENTITIES_FLAG) > 0) { aoqi@0: decodeUnparsedEntities(); aoqi@0: /* aoqi@0: try { aoqi@0: _dtdHandler.unparsedEntityDecl(name, public_identifier, system_identifier, notation_name); aoqi@0: } catch (SAXException e) { aoqi@0: throw new IOException("UnparsedEntitiesII"); aoqi@0: } aoqi@0: */ aoqi@0: } aoqi@0: aoqi@0: if ((b & EncodingConstants.DOCUMENT_CHARACTER_ENCODING_SCHEME) > 0) { aoqi@0: _characterEncodingScheme = decodeCharacterEncodingScheme(); aoqi@0: } aoqi@0: aoqi@0: if ((b & EncodingConstants.DOCUMENT_STANDALONE_FLAG) > 0) { aoqi@0: boolean standalone = (read() > 0) ? true : false ; aoqi@0: /* aoqi@0: * TODO aoqi@0: * how to report the standalone flag? aoqi@0: */ aoqi@0: } aoqi@0: aoqi@0: if ((b & EncodingConstants.DOCUMENT_VERSION_FLAG) > 0) { aoqi@0: decodeVersion(); aoqi@0: /* aoqi@0: * TODO aoqi@0: * how to report the standalone flag? aoqi@0: */ aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: protected final void resizeNamespaceAIIs() { aoqi@0: final String[] namespaceAIIsPrefix = new String[_namespaceAIIsIndex * 2]; aoqi@0: System.arraycopy(_namespaceAIIsPrefix, 0, namespaceAIIsPrefix, 0, _namespaceAIIsIndex); aoqi@0: _namespaceAIIsPrefix = namespaceAIIsPrefix; aoqi@0: aoqi@0: final String[] namespaceAIIsNamespaceName = new String[_namespaceAIIsIndex * 2]; aoqi@0: System.arraycopy(_namespaceAIIsNamespaceName, 0, namespaceAIIsNamespaceName, 0, _namespaceAIIsIndex); aoqi@0: _namespaceAIIsNamespaceName = namespaceAIIsNamespaceName; aoqi@0: aoqi@0: final int[] namespaceAIIsPrefixIndex = new int[_namespaceAIIsIndex * 2]; aoqi@0: System.arraycopy(_namespaceAIIsPrefixIndex, 0, namespaceAIIsPrefixIndex, 0, _namespaceAIIsIndex); aoqi@0: _namespaceAIIsPrefixIndex = namespaceAIIsPrefixIndex; aoqi@0: } aoqi@0: aoqi@0: protected final void processEIIWithNamespaces(boolean hasAttributes) throws FastInfosetException, IOException { aoqi@0: if (++_prefixTable._declarationId == Integer.MAX_VALUE) { aoqi@0: _prefixTable.clearDeclarationIds(); aoqi@0: } aoqi@0: aoqi@0: _currentNamespaceAIIsStart = _namespaceAIIsIndex; aoqi@0: String prefix = "", namespaceName = ""; aoqi@0: int b = read(); aoqi@0: while ((b & EncodingConstants.NAMESPACE_ATTRIBUTE_MASK) == EncodingConstants.NAMESPACE_ATTRIBUTE) { aoqi@0: if (_namespaceAIIsIndex == _namespaceAIIsPrefix.length) { aoqi@0: resizeNamespaceAIIs(); aoqi@0: } aoqi@0: aoqi@0: switch (b & EncodingConstants.NAMESPACE_ATTRIBUTE_PREFIX_NAME_MASK) { aoqi@0: // no prefix, no namespace aoqi@0: // Undeclaration of default namespace aoqi@0: case 0: aoqi@0: prefix = namespaceName = aoqi@0: _namespaceAIIsPrefix[_namespaceAIIsIndex] = aoqi@0: _namespaceAIIsNamespaceName[_namespaceAIIsIndex] = ""; aoqi@0: aoqi@0: _namespaceNameIndex = _prefixIndex = _namespaceAIIsPrefixIndex[_namespaceAIIsIndex++] = -1; aoqi@0: break; aoqi@0: // no prefix, namespace aoqi@0: // Declaration of default namespace aoqi@0: case 1: aoqi@0: prefix = _namespaceAIIsPrefix[_namespaceAIIsIndex] = ""; aoqi@0: namespaceName = _namespaceAIIsNamespaceName[_namespaceAIIsIndex] = aoqi@0: decodeIdentifyingNonEmptyStringOnFirstBitAsNamespaceName(false); aoqi@0: aoqi@0: _prefixIndex = _namespaceAIIsPrefixIndex[_namespaceAIIsIndex++] = -1; aoqi@0: break; aoqi@0: // prefix, no namespace aoqi@0: // Undeclaration of namespace aoqi@0: case 2: aoqi@0: prefix = _namespaceAIIsPrefix[_namespaceAIIsIndex] = aoqi@0: decodeIdentifyingNonEmptyStringOnFirstBitAsPrefix(false); aoqi@0: namespaceName = _namespaceAIIsNamespaceName[_namespaceAIIsIndex] = ""; aoqi@0: aoqi@0: _namespaceNameIndex = -1; aoqi@0: _namespaceAIIsPrefixIndex[_namespaceAIIsIndex++] = _prefixIndex; aoqi@0: break; aoqi@0: // prefix, namespace aoqi@0: // Declaration of prefixed namespace aoqi@0: case 3: aoqi@0: prefix = _namespaceAIIsPrefix[_namespaceAIIsIndex] = aoqi@0: decodeIdentifyingNonEmptyStringOnFirstBitAsPrefix(true); aoqi@0: namespaceName = _namespaceAIIsNamespaceName[_namespaceAIIsIndex] = aoqi@0: decodeIdentifyingNonEmptyStringOnFirstBitAsNamespaceName(true); aoqi@0: aoqi@0: _namespaceAIIsPrefixIndex[_namespaceAIIsIndex++] = _prefixIndex; aoqi@0: break; aoqi@0: } aoqi@0: aoqi@0: // Push namespace declarations onto the stack aoqi@0: _prefixTable.pushScopeWithPrefixEntry(prefix, namespaceName, _prefixIndex, _namespaceNameIndex); aoqi@0: aoqi@0: b = read(); aoqi@0: } aoqi@0: if (b != EncodingConstants.TERMINATOR) { aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.EIInamespaceNameNotTerminatedCorrectly")); aoqi@0: } aoqi@0: _currentNamespaceAIIsEnd = _namespaceAIIsIndex; aoqi@0: aoqi@0: b = read(); aoqi@0: switch(DecoderStateTables.EII(b)) { aoqi@0: case DecoderStateTables.EII_NO_AIIS_INDEX_SMALL: aoqi@0: processEII(_elementNameTable._array[b], hasAttributes); aoqi@0: break; aoqi@0: case DecoderStateTables.EII_INDEX_MEDIUM: aoqi@0: processEII(processEIIIndexMedium(b), hasAttributes); aoqi@0: break; aoqi@0: case DecoderStateTables.EII_INDEX_LARGE: aoqi@0: processEII(processEIIIndexLarge(b), hasAttributes); aoqi@0: break; aoqi@0: case DecoderStateTables.EII_LITERAL: aoqi@0: { aoqi@0: final QualifiedName qn = processLiteralQualifiedName( aoqi@0: b & EncodingConstants.LITERAL_QNAME_PREFIX_NAMESPACE_NAME_MASK, aoqi@0: _elementNameTable.getNext()); aoqi@0: _elementNameTable.add(qn); aoqi@0: processEII(qn, hasAttributes); aoqi@0: break; aoqi@0: } aoqi@0: default: aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.IllegalStateDecodingEIIAfterAIIs")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void processEII(QualifiedName name, boolean hasAttributes) throws FastInfosetException, IOException { aoqi@0: if (_prefixTable._currentInScope[name.prefixIndex] != name.namespaceNameIndex) { aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.qnameOfEIINotInScope")); aoqi@0: } aoqi@0: aoqi@0: _eventType = START_ELEMENT; aoqi@0: _qualifiedName = name; aoqi@0: aoqi@0: if (_clearAttributes) { aoqi@0: _attributes.clear(); aoqi@0: _clearAttributes = false; aoqi@0: } aoqi@0: aoqi@0: if (hasAttributes) { aoqi@0: processAIIs(); aoqi@0: } aoqi@0: aoqi@0: // Push element holder onto the stack aoqi@0: _stackCount++; aoqi@0: if (_stackCount == _qNameStack.length) { aoqi@0: QualifiedName[] qNameStack = new QualifiedName[_qNameStack.length * 2]; aoqi@0: System.arraycopy(_qNameStack, 0, qNameStack, 0, _qNameStack.length); aoqi@0: _qNameStack = qNameStack; aoqi@0: aoqi@0: int[] namespaceAIIsStartStack = new int[_namespaceAIIsStartStack.length * 2]; aoqi@0: System.arraycopy(_namespaceAIIsStartStack, 0, namespaceAIIsStartStack, 0, _namespaceAIIsStartStack.length); aoqi@0: _namespaceAIIsStartStack = namespaceAIIsStartStack; aoqi@0: aoqi@0: int[] namespaceAIIsEndStack = new int[_namespaceAIIsEndStack.length * 2]; aoqi@0: System.arraycopy(_namespaceAIIsEndStack, 0, namespaceAIIsEndStack, 0, _namespaceAIIsEndStack.length); aoqi@0: _namespaceAIIsEndStack = namespaceAIIsEndStack; aoqi@0: } aoqi@0: _qNameStack[_stackCount] = _qualifiedName; aoqi@0: _namespaceAIIsStartStack[_stackCount] = _currentNamespaceAIIsStart; aoqi@0: _namespaceAIIsEndStack[_stackCount] = _currentNamespaceAIIsEnd; aoqi@0: } aoqi@0: aoqi@0: protected final void processAIIs() throws FastInfosetException, IOException { aoqi@0: QualifiedName name; aoqi@0: int b; aoqi@0: String value; aoqi@0: aoqi@0: if (++_duplicateAttributeVerifier._currentIteration == Integer.MAX_VALUE) { aoqi@0: _duplicateAttributeVerifier.clear(); aoqi@0: } aoqi@0: aoqi@0: _clearAttributes = true; aoqi@0: boolean terminate = false; aoqi@0: do { aoqi@0: // AII qualified name aoqi@0: b = read(); aoqi@0: switch (DecoderStateTables.AII(b)) { aoqi@0: case DecoderStateTables.AII_INDEX_SMALL: aoqi@0: name = _attributeNameTable._array[b]; aoqi@0: break; aoqi@0: case DecoderStateTables.AII_INDEX_MEDIUM: aoqi@0: { aoqi@0: final int i = (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read()) aoqi@0: + EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT; aoqi@0: name = _attributeNameTable._array[i]; aoqi@0: break; aoqi@0: } aoqi@0: case DecoderStateTables.AII_INDEX_LARGE: aoqi@0: { aoqi@0: final int i = (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read()) aoqi@0: + EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT; aoqi@0: name = _attributeNameTable._array[i]; aoqi@0: break; aoqi@0: } aoqi@0: case DecoderStateTables.AII_LITERAL: aoqi@0: name = processLiteralQualifiedName( aoqi@0: b & EncodingConstants.LITERAL_QNAME_PREFIX_NAMESPACE_NAME_MASK, aoqi@0: _attributeNameTable.getNext()); aoqi@0: name.createAttributeValues(DuplicateAttributeVerifier.MAP_SIZE); aoqi@0: _attributeNameTable.add(name); aoqi@0: break; aoqi@0: case DecoderStateTables.AII_TERMINATOR_DOUBLE: aoqi@0: _internalState = INTERNAL_STATE_START_ELEMENT_TERMINATE; aoqi@0: case DecoderStateTables.AII_TERMINATOR_SINGLE: aoqi@0: terminate = true; aoqi@0: // AIIs have finished break out of loop aoqi@0: continue; aoqi@0: default: aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingAIIs")); aoqi@0: } aoqi@0: aoqi@0: // [normalized value] of AII aoqi@0: aoqi@0: if (name.prefixIndex > 0 && _prefixTable._currentInScope[name.prefixIndex] != name.namespaceNameIndex) { aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.AIIqNameNotInScope")); aoqi@0: } aoqi@0: aoqi@0: _duplicateAttributeVerifier.checkForDuplicateAttribute(name.attributeHash, name.attributeId); aoqi@0: aoqi@0: b = read(); aoqi@0: switch(DecoderStateTables.NISTRING(b)) { aoqi@0: case DecoderStateTables.NISTRING_UTF8_SMALL_LENGTH: aoqi@0: _octetBufferLength = (b & EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_MASK) + 1; aoqi@0: value = decodeUtf8StringAsString(); aoqi@0: if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { aoqi@0: _attributeValueTable.add(value); aoqi@0: } aoqi@0: aoqi@0: _attributes.addAttribute(name, value); aoqi@0: break; aoqi@0: case DecoderStateTables.NISTRING_UTF8_MEDIUM_LENGTH: aoqi@0: _octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT; aoqi@0: value = decodeUtf8StringAsString(); aoqi@0: if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { aoqi@0: _attributeValueTable.add(value); aoqi@0: } aoqi@0: aoqi@0: _attributes.addAttribute(name, value); aoqi@0: break; aoqi@0: case DecoderStateTables.NISTRING_UTF8_LARGE_LENGTH: aoqi@0: _octetBufferLength = ((read() << 24) | aoqi@0: (read() << 16) | aoqi@0: (read() << 8) | aoqi@0: read()) aoqi@0: + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT; aoqi@0: value = decodeUtf8StringAsString(); aoqi@0: if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { aoqi@0: _attributeValueTable.add(value); aoqi@0: } aoqi@0: aoqi@0: _attributes.addAttribute(name, value); aoqi@0: break; aoqi@0: case DecoderStateTables.NISTRING_UTF16_SMALL_LENGTH: aoqi@0: _octetBufferLength = (b & EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_MASK) + 1; aoqi@0: value = decodeUtf16StringAsString(); aoqi@0: if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { aoqi@0: _attributeValueTable.add(value); aoqi@0: } aoqi@0: aoqi@0: _attributes.addAttribute(name, value); aoqi@0: break; aoqi@0: case DecoderStateTables.NISTRING_UTF16_MEDIUM_LENGTH: aoqi@0: _octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT; aoqi@0: value = decodeUtf16StringAsString(); aoqi@0: if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { aoqi@0: _attributeValueTable.add(value); aoqi@0: } aoqi@0: aoqi@0: _attributes.addAttribute(name, value); aoqi@0: break; aoqi@0: case DecoderStateTables.NISTRING_UTF16_LARGE_LENGTH: aoqi@0: _octetBufferLength = ((read() << 24) | aoqi@0: (read() << 16) | aoqi@0: (read() << 8) | aoqi@0: read()) aoqi@0: + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT; aoqi@0: value = decodeUtf16StringAsString(); aoqi@0: if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { aoqi@0: _attributeValueTable.add(value); aoqi@0: } aoqi@0: aoqi@0: _attributes.addAttribute(name, value); aoqi@0: break; aoqi@0: case DecoderStateTables.NISTRING_RA: aoqi@0: { aoqi@0: final boolean addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0; aoqi@0: // Decode resitricted alphabet integer aoqi@0: _identifier = (b & 0x0F) << 4; aoqi@0: b = read(); aoqi@0: _identifier |= (b & 0xF0) >> 4; aoqi@0: aoqi@0: decodeOctetsOnFifthBitOfNonIdentifyingStringOnFirstBit(b); aoqi@0: aoqi@0: value = decodeRestrictedAlphabetAsString(); aoqi@0: if (addToTable) { aoqi@0: _attributeValueTable.add(value); aoqi@0: } aoqi@0: aoqi@0: _attributes.addAttribute(name, value); aoqi@0: break; aoqi@0: } aoqi@0: case DecoderStateTables.NISTRING_EA: aoqi@0: { aoqi@0: final boolean addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0; aoqi@0: // Decode encoding algorithm integer aoqi@0: _identifier = (b & 0x0F) << 4; aoqi@0: b = read(); aoqi@0: _identifier |= (b & 0xF0) >> 4; aoqi@0: aoqi@0: decodeOctetsOnFifthBitOfNonIdentifyingStringOnFirstBit(b); aoqi@0: processAIIEncodingAlgorithm(name, addToTable); aoqi@0: break; aoqi@0: } aoqi@0: case DecoderStateTables.NISTRING_INDEX_SMALL: aoqi@0: _attributes.addAttribute(name, aoqi@0: _attributeValueTable._array[b & EncodingConstants.INTEGER_2ND_BIT_SMALL_MASK]); aoqi@0: break; aoqi@0: case DecoderStateTables.NISTRING_INDEX_MEDIUM: aoqi@0: { aoqi@0: final int index = (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read()) aoqi@0: + EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT; aoqi@0: aoqi@0: _attributes.addAttribute(name, aoqi@0: _attributeValueTable._array[index]); aoqi@0: break; aoqi@0: } aoqi@0: case DecoderStateTables.NISTRING_INDEX_LARGE: aoqi@0: { aoqi@0: final int index = (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read()) aoqi@0: + EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT; aoqi@0: aoqi@0: _attributes.addAttribute(name, aoqi@0: _attributeValueTable._array[index]); aoqi@0: break; aoqi@0: } aoqi@0: case DecoderStateTables.NISTRING_EMPTY: aoqi@0: _attributes.addAttribute(name, ""); aoqi@0: break; aoqi@0: default: aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingAIIValue")); aoqi@0: } aoqi@0: aoqi@0: } while (!terminate); aoqi@0: aoqi@0: // Reset duplication attribute verfifier aoqi@0: _duplicateAttributeVerifier._poolCurrent = _duplicateAttributeVerifier._poolHead; aoqi@0: } aoqi@0: aoqi@0: protected final QualifiedName processEIIIndexMedium(int b) throws FastInfosetException, IOException { aoqi@0: final int i = (((b & EncodingConstants.INTEGER_3RD_BIT_MEDIUM_MASK) << 8) | read()) aoqi@0: + EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT; aoqi@0: return _elementNameTable._array[i]; aoqi@0: } aoqi@0: aoqi@0: protected final QualifiedName processEIIIndexLarge(int b) throws FastInfosetException, IOException { aoqi@0: int i; aoqi@0: if ((b & EncodingConstants.INTEGER_3RD_BIT_LARGE_LARGE_FLAG) == 0x20) { aoqi@0: // EII large index aoqi@0: i = (((b & EncodingConstants.INTEGER_3RD_BIT_LARGE_MASK) << 16) | (read() << 8) | read()) aoqi@0: + EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT; aoqi@0: } else { aoqi@0: // EII large large index aoqi@0: i = (((read() & EncodingConstants.INTEGER_3RD_BIT_LARGE_LARGE_MASK) << 16) | (read() << 8) | read()) aoqi@0: + EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT; aoqi@0: } aoqi@0: return _elementNameTable._array[i]; aoqi@0: } aoqi@0: aoqi@0: protected final QualifiedName processLiteralQualifiedName(int state, QualifiedName q) aoqi@0: throws FastInfosetException, IOException { aoqi@0: if (q == null) q = new QualifiedName(); aoqi@0: aoqi@0: switch (state) { aoqi@0: // no prefix, no namespace aoqi@0: case 0: aoqi@0: return q.set( aoqi@0: "", aoqi@0: "", aoqi@0: decodeIdentifyingNonEmptyStringOnFirstBit(_v.localName), aoqi@0: "", aoqi@0: 0, aoqi@0: -1, aoqi@0: -1, aoqi@0: _identifier); aoqi@0: // no prefix, namespace aoqi@0: case 1: aoqi@0: return q.set( aoqi@0: "", aoqi@0: decodeIdentifyingNonEmptyStringIndexOnFirstBitAsNamespaceName(false), aoqi@0: decodeIdentifyingNonEmptyStringOnFirstBit(_v.localName), aoqi@0: "", aoqi@0: 0, aoqi@0: -1, aoqi@0: _namespaceNameIndex, aoqi@0: _identifier); aoqi@0: // prefix, no namespace aoqi@0: case 2: aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.qNameMissingNamespaceName")); aoqi@0: // prefix, namespace aoqi@0: case 3: aoqi@0: return q.set( aoqi@0: decodeIdentifyingNonEmptyStringIndexOnFirstBitAsPrefix(true), aoqi@0: decodeIdentifyingNonEmptyStringIndexOnFirstBitAsNamespaceName(true), aoqi@0: decodeIdentifyingNonEmptyStringOnFirstBit(_v.localName), aoqi@0: "", aoqi@0: 0, aoqi@0: _prefixIndex, aoqi@0: _namespaceNameIndex, aoqi@0: _identifier); aoqi@0: default: aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingEII")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void processCommentII() throws FastInfosetException, IOException { aoqi@0: _eventType = COMMENT; aoqi@0: aoqi@0: switch(decodeNonIdentifyingStringOnFirstBit()) { aoqi@0: case NISTRING_STRING: aoqi@0: if (_addToTable) { aoqi@0: _v.otherString.add(new CharArray(_charBuffer, 0, _charBufferLength, true)); aoqi@0: } aoqi@0: aoqi@0: _characters = _charBuffer; aoqi@0: _charactersOffset = 0; aoqi@0: break; aoqi@0: case NISTRING_ENCODING_ALGORITHM: aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.commentIIAlgorithmNotSupported")); aoqi@0: case NISTRING_INDEX: aoqi@0: final CharArray ca = _v.otherString.get(_integer); aoqi@0: aoqi@0: _characters = ca.ch; aoqi@0: _charactersOffset = ca.start; aoqi@0: _charBufferLength = ca.length; aoqi@0: break; aoqi@0: case NISTRING_EMPTY_STRING: aoqi@0: _characters = _charBuffer; aoqi@0: _charactersOffset = 0; aoqi@0: _charBufferLength = 0; aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void processProcessingII() throws FastInfosetException, IOException { aoqi@0: _eventType = PROCESSING_INSTRUCTION; aoqi@0: aoqi@0: _piTarget = decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherNCName); aoqi@0: aoqi@0: switch(decodeNonIdentifyingStringOnFirstBit()) { aoqi@0: case NISTRING_STRING: aoqi@0: _piData = new String(_charBuffer, 0, _charBufferLength); aoqi@0: if (_addToTable) { aoqi@0: _v.otherString.add(new CharArrayString(_piData)); aoqi@0: } aoqi@0: break; aoqi@0: case NISTRING_ENCODING_ALGORITHM: aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.processingIIWithEncodingAlgorithm")); aoqi@0: case NISTRING_INDEX: aoqi@0: _piData = _v.otherString.get(_integer).toString(); aoqi@0: break; aoqi@0: case NISTRING_EMPTY_STRING: aoqi@0: _piData = ""; aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void processUnexpandedEntityReference(final int b) throws FastInfosetException, IOException { aoqi@0: _eventType = ENTITY_REFERENCE; aoqi@0: aoqi@0: /* aoqi@0: * TODO aoqi@0: * How does StAX report such events? aoqi@0: */ aoqi@0: String entity_reference_name = decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherNCName); aoqi@0: aoqi@0: String system_identifier = ((b & EncodingConstants.UNEXPANDED_ENTITY_SYSTEM_IDENTIFIER_FLAG) > 0) aoqi@0: ? decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherURI) : ""; aoqi@0: String public_identifier = ((b & EncodingConstants.UNEXPANDED_ENTITY_PUBLIC_IDENTIFIER_FLAG) > 0) aoqi@0: ? decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherURI) : ""; aoqi@0: aoqi@0: if (logger.isLoggable(Level.FINEST)) { aoqi@0: logger.log(Level.FINEST, "processUnexpandedEntityReference: entity_reference_name={0} system_identifier={1}public_identifier={2}", aoqi@0: new Object[]{entity_reference_name, system_identifier, public_identifier}); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void processCIIEncodingAlgorithm(boolean addToTable) throws FastInfosetException, IOException { aoqi@0: _algorithmData = _octetBuffer; aoqi@0: _algorithmDataOffset = _octetBufferStart; aoqi@0: _algorithmDataLength = _octetBufferLength; aoqi@0: _isAlgorithmDataCloned = false; aoqi@0: aoqi@0: if (_algorithmId >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { aoqi@0: _algorithmURI = _v.encodingAlgorithm.get(_algorithmId - EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START); aoqi@0: if (_algorithmURI == null) { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.URINotPresent", new Object[]{Integer.valueOf(_identifier)})); aoqi@0: } aoqi@0: } else if (_algorithmId > EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { aoqi@0: // Reserved built-in algorithms for future use aoqi@0: // TODO should use sax property to decide if event will be aoqi@0: // reported, allows for support through handler if required. aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved")); aoqi@0: } aoqi@0: aoqi@0: if (addToTable) { aoqi@0: convertEncodingAlgorithmDataToCharacters(); aoqi@0: _characterContentChunkTable.add(_characters, _characters.length); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void processAIIEncodingAlgorithm(QualifiedName name, boolean addToTable) throws FastInfosetException, IOException { aoqi@0: EncodingAlgorithm ea = null; aoqi@0: String URI = null; aoqi@0: if (_identifier >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { aoqi@0: URI = _v.encodingAlgorithm.get(_identifier - EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START); aoqi@0: if (URI == null) { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.URINotPresent", new Object[]{Integer.valueOf(_identifier)})); aoqi@0: } else if (_registeredEncodingAlgorithms != null) { aoqi@0: ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI); aoqi@0: } aoqi@0: } else if (_identifier >= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { aoqi@0: if (_identifier == EncodingAlgorithmIndexes.CDATA) { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.CDATAAlgorithmNotSupported")); aoqi@0: } aoqi@0: aoqi@0: // Reserved built-in algorithms for future use aoqi@0: // TODO should use sax property to decide if event will be aoqi@0: // reported, allows for support through handler if required. aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved")); aoqi@0: } else { aoqi@0: ea = BuiltInEncodingAlgorithmFactory.getAlgorithm(_identifier); aoqi@0: } aoqi@0: aoqi@0: Object algorithmData; aoqi@0: aoqi@0: if (ea != null) { aoqi@0: algorithmData = ea.decodeFromBytes(_octetBuffer, _octetBufferStart, aoqi@0: _octetBufferLength); aoqi@0: } else { aoqi@0: final byte[] data = new byte[_octetBufferLength]; aoqi@0: System.arraycopy(_octetBuffer, _octetBufferStart, data, 0, aoqi@0: _octetBufferLength); aoqi@0: algorithmData = data; aoqi@0: } aoqi@0: aoqi@0: _attributes.addAttributeWithAlgorithmData(name, URI, _identifier, aoqi@0: algorithmData); aoqi@0: if (addToTable) { aoqi@0: _attributeValueTable.add(_attributes.getValue(_attributes.getIndex(name.qName))); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void convertEncodingAlgorithmDataToCharacters() throws FastInfosetException, IOException { aoqi@0: StringBuffer buffer = new StringBuffer(); aoqi@0: if (_algorithmId == EncodingAlgorithmIndexes.BASE64) { aoqi@0: convertBase64AlorithmDataToCharacters(buffer); aoqi@0: } else if (_algorithmId < EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { aoqi@0: Object array = BuiltInEncodingAlgorithmFactory.getAlgorithm(_algorithmId). aoqi@0: decodeFromBytes(_algorithmData, _algorithmDataOffset, _algorithmDataLength); aoqi@0: BuiltInEncodingAlgorithmFactory.getAlgorithm(_algorithmId).convertToCharacters(array, buffer); aoqi@0: } else if (_algorithmId == EncodingAlgorithmIndexes.CDATA) { aoqi@0: _octetBufferOffset -= _octetBufferLength; aoqi@0: decodeUtf8StringIntoCharBuffer(); aoqi@0: aoqi@0: _characters = _charBuffer; aoqi@0: _charactersOffset = 0; aoqi@0: return; aoqi@0: } else if (_algorithmId >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { aoqi@0: final EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(_algorithmURI); aoqi@0: if (ea != null) { aoqi@0: final Object data = ea.decodeFromBytes(_octetBuffer, _octetBufferStart, _octetBufferLength); aoqi@0: ea.convertToCharacters(data, buffer); aoqi@0: } else { aoqi@0: throw new EncodingAlgorithmException( aoqi@0: CommonResourceBundle.getInstance().getString("message.algorithmDataCannotBeReported")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: _characters = new char[buffer.length()]; aoqi@0: buffer.getChars(0, buffer.length(), _characters, 0); aoqi@0: _charactersOffset = 0; aoqi@0: _charBufferLength = _characters.length; aoqi@0: } aoqi@0: aoqi@0: /* If base64 data comes is chunks, bytes, which were cut to align 3, aoqi@0: * from prev. base64 chunk are stored in this buffer */ aoqi@0: private byte[] base64TaleBytes = new byte[3]; aoqi@0: private int base64TaleLength; aoqi@0: /* aoqi@0: * Method converts _algorithmData to base64 encoded String aoqi@0: * Counts with base64 data coming in chunks, aligning input chunks by 3, aoqi@0: * avoiding double cloning, happening after possible peek, peek2 cloning by Base64 algorithm aoqi@0: */ aoqi@0: protected void convertBase64AlorithmDataToCharacters(StringBuffer buffer) throws EncodingAlgorithmException, IOException { aoqi@0: // How much new came data was serialized with prev. tale aoqi@0: int afterTaleOffset = 0; aoqi@0: aoqi@0: if (base64TaleLength > 0) { aoqi@0: // Serialize tale left from prev. chunk aoqi@0: int bytesToCopy = Math.min(3 - base64TaleLength, _algorithmDataLength); aoqi@0: System.arraycopy(_algorithmData, _algorithmDataOffset, base64TaleBytes, base64TaleLength, bytesToCopy); aoqi@0: if (base64TaleLength + bytesToCopy == 3) { aoqi@0: base64DecodeWithCloning(buffer, base64TaleBytes, 0, 3); aoqi@0: } else if (!isBase64Follows()) { aoqi@0: // End of text was read to temp array aoqi@0: base64DecodeWithCloning(buffer, base64TaleBytes, 0, base64TaleLength + bytesToCopy); aoqi@0: return; aoqi@0: } else { aoqi@0: // If the end of chunk fit to tmp array, but next chunk is expected aoqi@0: base64TaleLength += bytesToCopy; aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: afterTaleOffset = bytesToCopy; aoqi@0: base64TaleLength = 0; aoqi@0: } aoqi@0: aoqi@0: int taleBytesRemaining = isBase64Follows() ? (_algorithmDataLength - afterTaleOffset) % 3 : 0; aoqi@0: aoqi@0: if (_isAlgorithmDataCloned) { aoqi@0: base64DecodeWithoutCloning(buffer, _algorithmData, _algorithmDataOffset + afterTaleOffset, aoqi@0: _algorithmDataLength - afterTaleOffset - taleBytesRemaining); aoqi@0: } else { aoqi@0: base64DecodeWithCloning(buffer, _algorithmData, _algorithmDataOffset + afterTaleOffset, aoqi@0: _algorithmDataLength - afterTaleOffset - taleBytesRemaining); aoqi@0: } aoqi@0: aoqi@0: if (taleBytesRemaining > 0) { aoqi@0: System.arraycopy(_algorithmData, _algorithmDataOffset + _algorithmDataLength - taleBytesRemaining, aoqi@0: base64TaleBytes, 0, taleBytesRemaining); aoqi@0: base64TaleLength = taleBytesRemaining; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * Encodes incoming data to Base64 string. aoqi@0: * Method performs additional input data cloning aoqi@0: */ aoqi@0: private void base64DecodeWithCloning(StringBuffer dstBuffer, byte[] data, int offset, int length) throws EncodingAlgorithmException { aoqi@0: Object array = BuiltInEncodingAlgorithmFactory.base64EncodingAlgorithm. aoqi@0: decodeFromBytes(data, offset, length); aoqi@0: BuiltInEncodingAlgorithmFactory.base64EncodingAlgorithm.convertToCharacters(array, dstBuffer); aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * Encodes incoming data to Base64 string. aoqi@0: * Avoids input data cloning aoqi@0: */ aoqi@0: private void base64DecodeWithoutCloning(StringBuffer dstBuffer, byte[] data, int offset, int length) throws EncodingAlgorithmException { aoqi@0: BuiltInEncodingAlgorithmFactory.base64EncodingAlgorithm.convertToCharacters(data, offset, length, dstBuffer); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /* aoqi@0: * Looks ahead in InputStream, whether next data is Base64 chunk aoqi@0: */ aoqi@0: public boolean isBase64Follows() throws IOException { aoqi@0: // Process information item aoqi@0: int b = peek(this); aoqi@0: switch (DecoderStateTables.EII(b)) { aoqi@0: case DecoderStateTables.CII_EA: aoqi@0: int algorithmId = (b & 0x02) << 6; aoqi@0: int b2 = peek2(this); aoqi@0: algorithmId |= (b2 & 0xFC) >> 2; aoqi@0: aoqi@0: return algorithmId == EncodingAlgorithmIndexes.BASE64; aoqi@0: default: aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected class NamespaceContextImpl implements NamespaceContext { aoqi@0: public final String getNamespaceURI(String prefix) { aoqi@0: return _prefixTable.getNamespaceFromPrefix(prefix); aoqi@0: } aoqi@0: aoqi@0: public final String getPrefix(String namespaceURI) { aoqi@0: return _prefixTable.getPrefixFromNamespace(namespaceURI); aoqi@0: } aoqi@0: aoqi@0: public final Iterator getPrefixes(String namespaceURI) { aoqi@0: return _prefixTable.getPrefixesFromNamespace(namespaceURI); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public final String getNamespaceDecl(String prefix) { aoqi@0: return _prefixTable.getNamespaceFromPrefix(prefix); aoqi@0: } aoqi@0: aoqi@0: public final String getURI(String prefix) { aoqi@0: return getNamespaceDecl(prefix); aoqi@0: } aoqi@0: aoqi@0: public final Iterator getPrefixes() { aoqi@0: return _prefixTable.getPrefixes(); aoqi@0: } aoqi@0: aoqi@0: public final AttributesHolder getAttributesHolder() { aoqi@0: return _attributes; aoqi@0: } aoqi@0: aoqi@0: public final void setManager(StAXManager manager) { aoqi@0: _manager = manager; aoqi@0: } aoqi@0: aoqi@0: final static String getEventTypeString(int eventType) { aoqi@0: switch (eventType){ aoqi@0: case START_ELEMENT: aoqi@0: return "START_ELEMENT"; aoqi@0: case END_ELEMENT: aoqi@0: return "END_ELEMENT"; aoqi@0: case PROCESSING_INSTRUCTION: aoqi@0: return "PROCESSING_INSTRUCTION"; aoqi@0: case CHARACTERS: aoqi@0: return "CHARACTERS"; aoqi@0: case COMMENT: aoqi@0: return "COMMENT"; aoqi@0: case START_DOCUMENT: aoqi@0: return "START_DOCUMENT"; aoqi@0: case END_DOCUMENT: aoqi@0: return "END_DOCUMENT"; aoqi@0: case ENTITY_REFERENCE: aoqi@0: return "ENTITY_REFERENCE"; aoqi@0: case ATTRIBUTE: aoqi@0: return "ATTRIBUTE"; aoqi@0: case DTD: aoqi@0: return "DTD"; aoqi@0: case CDATA: aoqi@0: return "CDATA"; aoqi@0: } aoqi@0: return "UNKNOWN_EVENT_TYPE"; aoqi@0: } aoqi@0: }