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