com.sun.xml.fastinfoset.Decoder 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;
import com.sun.xml.fastinfoset.alphabet.BuiltInRestrictedAlphabets;
import com.sun.xml.fastinfoset.org.apache.xerces.util.XMLChar;
import com.sun.xml.fastinfoset.util.CharArray;
import com.sun.xml.fastinfoset.util.CharArrayArray;
import com.sun.xml.fastinfoset.util.CharArrayString;
import com.sun.xml.fastinfoset.util.ContiguousCharArrayArray;
import com.sun.xml.fastinfoset.util.DuplicateAttributeVerifier;
import com.sun.xml.fastinfoset.util.PrefixArray;
import com.sun.xml.fastinfoset.util.QualifiedNameArray;
import com.sun.xml.fastinfoset.util.StringArray;
import com.sun.xml.fastinfoset.vocab.ParserVocabulary;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jvnet.fastinfoset.EncodingAlgorithm;
import org.jvnet.fastinfoset.ExternalVocabulary;
import org.jvnet.fastinfoset.FastInfosetException;
import org.jvnet.fastinfoset.FastInfosetParser;
/**
* Abstract decoder for developing concrete encoders.
*
* Concrete implementations extending Decoder will utilize methods on Decoder
* to decode XML infoset according to the Fast Infoset standard. It is the
* responsibility of the concrete implementation to ensure that methods are
* invoked in the correct order to correctly decode a valid fast infoset
* document.
*
*
* This class extends org.sax.xml.DefaultHandler so that concrete SAX
* implementations can be used with javax.xml.parsers.SAXParser and the parse
* methods that take org.sax.xml.DefaultHandler as a parameter.
*
*
* Buffering of octets that are read from an {@link java.io.InputStream} is
* supported in a similar manner to a {@link java.io.BufferedInputStream}.
* Combining buffering with decoding enables better performance.
*
*
* More than one fast infoset document may be decoded from the
* {@link java.io.InputStream}.
*/
public abstract class Decoder implements FastInfosetParser {
private static final char[] XML_NAMESPACE_NAME_CHARS =
EncodingConstants.XML_NAMESPACE_NAME.toCharArray();
private static final char[] XMLNS_NAMESPACE_PREFIX_CHARS =
EncodingConstants.XMLNS_NAMESPACE_PREFIX.toCharArray();
private static final char[] XMLNS_NAMESPACE_NAME_CHARS =
EncodingConstants.XMLNS_NAMESPACE_NAME.toCharArray();
/**
* String interning system property.
*/
public static final String STRING_INTERNING_SYSTEM_PROPERTY =
"com.sun.xml.fastinfoset.parser.string-interning";
/**
* Internal buffer size interning system property.
*/
public static final String BUFFER_SIZE_SYSTEM_PROPERTY =
"com.sun.xml.fastinfoset.parser.buffer-size";
private static boolean _stringInterningSystemDefault = false;
private static int _bufferSizeSystemDefault = 1024;
static {
String p = System.getProperty(STRING_INTERNING_SYSTEM_PROPERTY,
Boolean.toString(_stringInterningSystemDefault));
_stringInterningSystemDefault = Boolean.parseBoolean(p);
p = System.getProperty(BUFFER_SIZE_SYSTEM_PROPERTY,
Integer.toString(_bufferSizeSystemDefault));
try {
int i = Integer.parseInt(p);
if (i > 0) {
_bufferSizeSystemDefault = i;
}
} catch (NumberFormatException e) {
}
}
/**
* True if string interning is performed by the decoder.
*/
private boolean _stringInterning = _stringInterningSystemDefault;
/**
* The input stream from which the fast infoset document is being read.
*/
private InputStream _s;
/**
* The map of URIs to referenced vocabularies.
*/
private Map _externalVocabularies;
/**
* True if can parse fragments.
*/
protected boolean _parseFragments;
/**
* True if needs to close underlying input stream.
*/
protected boolean _needForceStreamClose;
/**
* True if the vocabulary is internally created by decoder.
*/
private boolean _vIsInternal;
/**
* The list of Notation Information Items that are part of the
* Document Information Item.
*/
protected List _notations;
/**
* The list of Unparsed Entity Information Items that are part of the
* Document Information Item.
*/
protected List _unparsedEntities;
/**
* The map of URIs to registered encoding algorithms.
*/
protected Map _registeredEncodingAlgorithms = new HashMap<>();
/**
* The vocabulary used for decoding.
*/
protected ParserVocabulary _v;
/**
* The prefix table of the vocabulary.
*/
protected PrefixArray _prefixTable;
/**
* The element name table of the vocabulary.
*/
protected QualifiedNameArray _elementNameTable;
/**
* The attribute name table of the vocabulary.
*/
protected QualifiedNameArray _attributeNameTable;
/**
* The character content chunk table of the vocabulary.
*/
protected ContiguousCharArrayArray _characterContentChunkTable;
/**
* The attribute value table of the vocabulary.
*/
protected StringArray _attributeValueTable;
/**
* The current octet that is being read
*/
protected int _b;
/**
* True if an information item is terminated.
*/
protected boolean _terminate;
/**
* True if two information item are terminated in direct sequence.
*/
protected boolean _doubleTerminate;
/**
* True if an entry is required to be added to a table
*/
protected boolean _addToTable;
/**
* The vocabulary table index to an indexed non identifying string.
*/
protected int _integer;
/**
* The vocabulary table index of identifying string or the identifier of
* an encoding algorithm or restricted alphabet.
*/
protected int _identifier;
/**
* The size of the internal buffer.
*/
protected int _bufferSize = _bufferSizeSystemDefault;
/**
* The internal buffer used for decoding.
*/
protected byte[] _octetBuffer = new byte[_bufferSizeSystemDefault];
/**
* A mark into the internal buffer used for decoding encoded algorithm
* or restricted alphabet data.
*/
protected int _octetBufferStart;
/**
* The offset into the buffer to read the next byte.
*/
protected int _octetBufferOffset;
/**
* The end of the buffer.
*/
protected int _octetBufferEnd;
/**
* The length of some octets in the buffer that are to be read.
*/
protected int _octetBufferLength;
/**
* The internal buffer of characters.
*/
protected char[] _charBuffer = new char[512];
/**
* The length of characters in the buffer of characters.
*/
protected int _charBufferLength;
/**
* Helper class that checks for duplicate attribute information items.
*/
protected DuplicateAttributeVerifier _duplicateAttributeVerifier = new DuplicateAttributeVerifier();
/**
* Default constructor for the Decoder.
*/
protected Decoder() {
_v = new ParserVocabulary();
_prefixTable = _v.prefix;
_elementNameTable = _v.elementName;
_attributeNameTable = _v.attributeName;
_characterContentChunkTable = _v.characterContentChunk;
_attributeValueTable = _v.attributeValue;
_vIsInternal = true;
}
// FastInfosetParser interface
@Override
public void setStringInterning(boolean stringInterning) {
_stringInterning = stringInterning;
}
@Override
public boolean getStringInterning() {
return _stringInterning;
}
@Override
public void setBufferSize(int bufferSize) {
if (_bufferSize > _octetBuffer.length) {
_bufferSize = bufferSize;
}
}
@Override
public int getBufferSize() {
return _bufferSize;
}
@Override
public void setRegisteredEncodingAlgorithms(Map algorithms) {
_registeredEncodingAlgorithms = algorithms;
if (_registeredEncodingAlgorithms == null) {
_registeredEncodingAlgorithms = new HashMap<>();
}
}
@Override
public Map getRegisteredEncodingAlgorithms() {
return _registeredEncodingAlgorithms;
}
@Override
public void setExternalVocabularies(Map referencedVocabualries) {
if (referencedVocabualries != null) {
// Clone the input map
_externalVocabularies = new HashMap<>();
_externalVocabularies.putAll(referencedVocabualries);
} else {
_externalVocabularies = null;
}
}
@Override
@SuppressWarnings({"deprecation"})
public Map getExternalVocabularies() {
return _externalVocabularies;
}
@Override
public void setParseFragments(boolean parseFragments) {
_parseFragments = parseFragments;
}
@Override
public boolean getParseFragments() {
return _parseFragments;
}
@Override
public void setForceStreamClose(boolean needForceStreamClose) {
_needForceStreamClose = needForceStreamClose;
}
@Override
public boolean getForceStreamClose() {
return _needForceStreamClose;
}
// End FastInfosetParser interface
/**
* Reset the decoder for reuse decoding another XML infoset.
*/
public void reset() {
_terminate = _doubleTerminate = false;
}
/**
* Set the ParserVocabulary to be used for decoding.
*
* @param v the vocabulary to be used for decoding.
*/
public void setVocabulary(ParserVocabulary v) {
_v = v;
_prefixTable = _v.prefix;
_elementNameTable = _v.elementName;
_attributeNameTable = _v.attributeName;
_characterContentChunkTable = _v.characterContentChunk;
_attributeValueTable = _v.attributeValue;
_vIsInternal = false;
}
/**
* Set the InputStream to decode the fast infoset document.
*
* @param s the InputStream where the fast infoset document is decoded from.
*/
public void setInputStream(InputStream s) {
_s = s;
_octetBufferOffset = 0;
_octetBufferEnd = 0;
if (_vIsInternal) {
_v.clear();
}
}
protected final void decodeDII() throws FastInfosetException, IOException {
final int b = read();
if (b == EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG) {
decodeInitialVocabulary();
} else if (b != 0) {
throw new IOException(CommonResourceBundle.getInstance().
getString("message.optinalValues"));
}
}
protected final void decodeAdditionalData() throws FastInfosetException, IOException {
final int noOfItems = decodeNumberOfItemsOfSequence();
for (int i = 0; i < noOfItems; i++) {
/*String URI = */decodeNonEmptyOctetStringOnSecondBitAsUtf8String();
decodeNonEmptyOctetStringLengthOnSecondBit();
ensureOctetBufferSize();
_octetBufferStart = _octetBufferOffset;
_octetBufferOffset += _octetBufferLength;
}
}
protected final void decodeInitialVocabulary() throws FastInfosetException, IOException {
// First 5 optionals of 13 bit optional field
int b = read();
// Next 8 optionals of 13 bit optional field
int b2 = read();
// Optimize for the most common case
if (b == EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG && b2 == 0) {
decodeExternalVocabularyURI();
return;
}
if ((b & EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG) > 0) {
decodeExternalVocabularyURI();
}
if ((b & EncodingConstants.INITIAL_VOCABULARY_RESTRICTED_ALPHABETS_FLAG) > 0) {
decodeTableItems(_v.restrictedAlphabet);
}
if ((b & EncodingConstants.INITIAL_VOCABULARY_ENCODING_ALGORITHMS_FLAG) > 0) {
decodeTableItems(_v.encodingAlgorithm);
}
if ((b & EncodingConstants.INITIAL_VOCABULARY_PREFIXES_FLAG) > 0) {
decodeTableItems(_v.prefix);
}
if ((b & EncodingConstants.INITIAL_VOCABULARY_NAMESPACE_NAMES_FLAG) > 0) {
decodeTableItems(_v.namespaceName);
}
if ((b2 & EncodingConstants.INITIAL_VOCABULARY_LOCAL_NAMES_FLAG) > 0) {
decodeTableItems(_v.localName);
}
if ((b2 & EncodingConstants.INITIAL_VOCABULARY_OTHER_NCNAMES_FLAG) > 0) {
decodeTableItems(_v.otherNCName);
}
if ((b2 & EncodingConstants.INITIAL_VOCABULARY_OTHER_URIS_FLAG) > 0) {
decodeTableItems(_v.otherURI);
}
if ((b2 & EncodingConstants.INITIAL_VOCABULARY_ATTRIBUTE_VALUES_FLAG) > 0) {
decodeTableItems(_v.attributeValue);
}
if ((b2 & EncodingConstants.INITIAL_VOCABULARY_CONTENT_CHARACTER_CHUNKS_FLAG) > 0) {
decodeTableItems(_v.characterContentChunk);
}
if ((b2 & EncodingConstants.INITIAL_VOCABULARY_OTHER_STRINGS_FLAG) > 0) {
decodeTableItems(_v.otherString);
}
if ((b2 & EncodingConstants.INITIAL_VOCABULARY_ELEMENT_NAME_SURROGATES_FLAG) > 0) {
decodeTableItems(_v.elementName, false);
}
if ((b2 & EncodingConstants.INITIAL_VOCABULARY_ATTRIBUTE_NAME_SURROGATES_FLAG) > 0) {
decodeTableItems(_v.attributeName, true);
}
}
private void decodeExternalVocabularyURI() throws FastInfosetException, IOException {
if (_externalVocabularies == null) {
throw new IOException(CommonResourceBundle.
getInstance().getString("message.noExternalVocabularies"));
}
String externalVocabularyURI =
decodeNonEmptyOctetStringOnSecondBitAsUtf8String();
Object o = _externalVocabularies.get(externalVocabularyURI);
if (o instanceof ParserVocabulary) {
_v.setReferencedVocabulary(externalVocabularyURI,
(ParserVocabulary)o, false);
} else if (o instanceof ExternalVocabulary) {
ExternalVocabulary v = (org.jvnet.fastinfoset.ExternalVocabulary)o;
ParserVocabulary pv = new ParserVocabulary(v.vocabulary);
_externalVocabularies.put(externalVocabularyURI, pv);
_v.setReferencedVocabulary(externalVocabularyURI,
pv, false);
} else {
throw new FastInfosetException(CommonResourceBundle.getInstance().
getString("message.externalVocabularyNotRegistered",
new Object[]{externalVocabularyURI}));
}
}
private void decodeTableItems(StringArray array) throws FastInfosetException, IOException {
final int noOfItems = decodeNumberOfItemsOfSequence();
for (int i = 0; i < noOfItems; i++) {
array.add(decodeNonEmptyOctetStringOnSecondBitAsUtf8String());
}
}
private void decodeTableItems(PrefixArray array) throws FastInfosetException, IOException {
final int noOfItems = decodeNumberOfItemsOfSequence();
for (int i = 0; i < noOfItems; i++) {
array.add(decodeNonEmptyOctetStringOnSecondBitAsUtf8String());
}
}
private void decodeTableItems(ContiguousCharArrayArray array) throws FastInfosetException, IOException {
final int noOfItems = decodeNumberOfItemsOfSequence();
for (int i = 0; i < noOfItems; i++) {
if (decodeNonIdentifyingStringOnFirstBit() == NISTRING_STRING) {
array.add(_charBuffer, _charBufferLength);
} else {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.illegalState"));
}
}
}
private void decodeTableItems(CharArrayArray array) throws FastInfosetException, IOException {
final int noOfItems = decodeNumberOfItemsOfSequence();
for (int i = 0; i < noOfItems; i++) {
if (decodeNonIdentifyingStringOnFirstBit() == NISTRING_STRING) {
array.add(new CharArray(_charBuffer, 0, _charBufferLength, true));
} else {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.illegalState"));
}
}
}
private void decodeTableItems(QualifiedNameArray array, boolean isAttribute) throws FastInfosetException, IOException {
final int noOfItems = decodeNumberOfItemsOfSequence();
for (int i = 0; i < noOfItems; i++) {
final int b = read();
String prefix = "";
int prefixIndex = -1;
if ((b & EncodingConstants.NAME_SURROGATE_PREFIX_FLAG) > 0) {
prefixIndex = decodeIntegerIndexOnSecondBit();
prefix = _v.prefix.get(prefixIndex);
}
String namespaceName = "";
int namespaceNameIndex = -1;
if ((b & EncodingConstants.NAME_SURROGATE_NAME_FLAG) > 0) {
namespaceNameIndex = decodeIntegerIndexOnSecondBit();
namespaceName = _v.namespaceName.get(namespaceNameIndex);
}
if (namespaceName.isEmpty() && !prefix.isEmpty()) {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.missingNamespace"));
}
final int localNameIndex = decodeIntegerIndexOnSecondBit();
final String localName = _v.localName.get(localNameIndex);
QualifiedName qualifiedName = new QualifiedName(prefix, namespaceName, localName,
prefixIndex, namespaceNameIndex, localNameIndex,
_charBuffer);
if (isAttribute) {
qualifiedName.createAttributeValues(DuplicateAttributeVerifier.MAP_SIZE);
}
array.add(qualifiedName);
}
}
private int decodeNumberOfItemsOfSequence() throws IOException {
final int b = read();
if (b < 128) {
return b + 1;
} else {
return (((b & 0x0F) << 16) | (read() << 8) | read()) + 129;
}
}
protected final void decodeNotations() throws FastInfosetException, IOException {
if (_notations == null) {
_notations = new ArrayList<>();
} else {
_notations.clear();
}
int b = read();
while ((b & EncodingConstants.NOTATIONS_MASK) == EncodingConstants.NOTATIONS) {
String name = decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherNCName);
String system_identifier = ((_b & EncodingConstants.NOTATIONS_SYSTEM_IDENTIFIER_FLAG) > 0)
? decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherURI) : "";
String public_identifier = ((_b & EncodingConstants.NOTATIONS_PUBLIC_IDENTIFIER_FLAG) > 0)
? decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherURI) : "";
Notation notation = new Notation(name, system_identifier, public_identifier);
_notations.add(notation);
b = read();
}
if (b != EncodingConstants.TERMINATOR) {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.IIsNotTerminatedCorrectly"));
}
}
protected final void decodeUnparsedEntities() throws FastInfosetException, IOException {
if (_unparsedEntities == null) {
_unparsedEntities = new ArrayList<>();
} else {
_unparsedEntities.clear();
}
int b = read();
while ((b & EncodingConstants.UNPARSED_ENTITIES_MASK) == EncodingConstants.UNPARSED_ENTITIES) {
String name = decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherNCName);
String system_identifier = decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherURI);
String public_identifier = ((_b & EncodingConstants.UNPARSED_ENTITIES_PUBLIC_IDENTIFIER_FLAG) > 0)
? decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherURI) : "";
String notation_name = decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherNCName);
UnparsedEntity unparsedEntity = new UnparsedEntity(name, system_identifier, public_identifier, notation_name);
_unparsedEntities.add(unparsedEntity);
b = read();
}
if (b != EncodingConstants.TERMINATOR) {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.unparsedEntities"));
}
}
protected final String decodeCharacterEncodingScheme() throws FastInfosetException, IOException {
return decodeNonEmptyOctetStringOnSecondBitAsUtf8String();
}
protected final String decodeVersion() throws FastInfosetException, IOException {
switch(decodeNonIdentifyingStringOnFirstBit()) {
case NISTRING_STRING:
final String data = new String(_charBuffer, 0, _charBufferLength);
if (_addToTable) {
_v.otherString.add(new CharArrayString(data));
}
return data;
case NISTRING_ENCODING_ALGORITHM:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingNotSupported"));
case NISTRING_INDEX:
return _v.otherString.get(_integer).toString();
case NISTRING_EMPTY_STRING:
default:
return "";
}
}
protected final QualifiedName decodeEIIIndexMedium() throws FastInfosetException, IOException {
final int i = (((_b & EncodingConstants.INTEGER_3RD_BIT_MEDIUM_MASK) << 8) | read())
+ EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT;
return _v.elementName._array[i];
}
protected final QualifiedName decodeEIIIndexLarge() 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 _v.elementName._array[i];
}
protected final QualifiedName decodeLiteralQualifiedName(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),
-1,
-1,
_identifier,
null);
// no prefix, namespace
case 1:
return q.set(
"",
decodeIdentifyingNonEmptyStringIndexOnFirstBitAsNamespaceName(false),
decodeIdentifyingNonEmptyStringOnFirstBit(_v.localName),
-1,
_namespaceNameIndex,
_identifier,
null);
// 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),
_prefixIndex,
_namespaceNameIndex,
_identifier,
_charBuffer);
default:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingEII"));
}
}
protected static final int NISTRING_STRING = 0;
protected static final int NISTRING_INDEX = 1;
protected static final int NISTRING_ENCODING_ALGORITHM = 2;
protected static final int NISTRING_EMPTY_STRING = 3;
/*
* C.14
* decodeNonIdentifyingStringOnFirstBit
*/
protected final int decodeNonIdentifyingStringOnFirstBit() throws FastInfosetException, IOException {
final int b = read();
switch(DecoderStateTables.NISTRING(b)) {
case DecoderStateTables.NISTRING_UTF8_SMALL_LENGTH:
_addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0;
_octetBufferLength = (b & EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_MASK) + 1;
decodeUtf8StringAsCharBuffer();
return NISTRING_STRING;
case DecoderStateTables.NISTRING_UTF8_MEDIUM_LENGTH:
_addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0;
_octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT;
decodeUtf8StringAsCharBuffer();
return NISTRING_STRING;
case DecoderStateTables.NISTRING_UTF8_LARGE_LENGTH:
{
_addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0;
final int length = (read() << 24) |
(read() << 16) |
(read() << 8) |
read();
_octetBufferLength = length + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT;
decodeUtf8StringAsCharBuffer();
return NISTRING_STRING;
}
case DecoderStateTables.NISTRING_UTF16_SMALL_LENGTH:
_addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0;
_octetBufferLength = (b & EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_MASK) + 1;
decodeUtf16StringAsCharBuffer();
return NISTRING_STRING;
case DecoderStateTables.NISTRING_UTF16_MEDIUM_LENGTH:
_addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0;
_octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT;
decodeUtf16StringAsCharBuffer();
return NISTRING_STRING;
case DecoderStateTables.NISTRING_UTF16_LARGE_LENGTH:
{
_addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0;
final int length = (read() << 24) |
(read() << 16) |
(read() << 8) |
read();
_octetBufferLength = length + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT;
decodeUtf16StringAsCharBuffer();
return NISTRING_STRING;
}
case DecoderStateTables.NISTRING_RA:
{
_addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0;
// Decode resitricted alphabet integer
_identifier = (b & 0x0F) << 4;
final int b2 = read();
_identifier |= (b2 & 0xF0) >> 4;
decodeOctetsOnFifthBitOfNonIdentifyingStringOnFirstBit(b2);
decodeRestrictedAlphabetAsCharBuffer();
return NISTRING_STRING;
}
case DecoderStateTables.NISTRING_EA:
{
_addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0;
// Decode encoding algorithm integer
_identifier = (b & 0x0F) << 4;
final int b2 = read();
_identifier |= (b2 & 0xF0) >> 4;
decodeOctetsOnFifthBitOfNonIdentifyingStringOnFirstBit(b2);
return NISTRING_ENCODING_ALGORITHM;
}
case DecoderStateTables.NISTRING_INDEX_SMALL:
_integer = b & EncodingConstants.INTEGER_2ND_BIT_SMALL_MASK;
return NISTRING_INDEX;
case DecoderStateTables.NISTRING_INDEX_MEDIUM:
_integer = (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
return NISTRING_INDEX;
case DecoderStateTables.NISTRING_INDEX_LARGE:
_integer = (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
return NISTRING_INDEX;
case DecoderStateTables.NISTRING_EMPTY:
return NISTRING_EMPTY_STRING;
default:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingNonIdentifyingString"));
}
}
protected final void decodeOctetsOnFifthBitOfNonIdentifyingStringOnFirstBit(int b) throws FastInfosetException, IOException {
// Remove top 4 bits of restricted alphabet or encoding algorithm integer
b &= 0x0F;
// Reuse UTF8 length states
switch(DecoderStateTables.NISTRING(b)) {
case DecoderStateTables.NISTRING_UTF8_SMALL_LENGTH:
_octetBufferLength = b + 1;
break;
case DecoderStateTables.NISTRING_UTF8_MEDIUM_LENGTH:
_octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT;
break;
case DecoderStateTables.NISTRING_UTF8_LARGE_LENGTH:
final int length = (read() << 24) |
(read() << 16) |
(read() << 8) |
read();
_octetBufferLength = length + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT;
break;
default:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingOctets"));
}
ensureOctetBufferSize();
_octetBufferStart = _octetBufferOffset;
_octetBufferOffset += _octetBufferLength;
}
protected final void decodeOctetsOnSeventhBitOfNonIdentifyingStringOnThirdBit(int b) throws FastInfosetException, IOException {
// Remove top 6 bits of restricted alphabet or encoding algorithm integer
switch (b & 0x03) {
// Small length
case 0:
_octetBufferLength = 1;
break;
// Small length
case 1:
_octetBufferLength = 2;
break;
// Medium length
case 2:
_octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT;
break;
// Large length
case 3:
_octetBufferLength = (read() << 24) |
(read() << 16) |
(read() << 8) |
read();
_octetBufferLength += EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT;
break;
}
ensureOctetBufferSize();
_octetBufferStart = _octetBufferOffset;
_octetBufferOffset += _octetBufferLength;
}
/*
* C.13
*/
protected final String decodeIdentifyingNonEmptyStringOnFirstBit(StringArray table) throws FastInfosetException, IOException {
final int b = read();
switch(DecoderStateTables.ISTRING(b)) {
case DecoderStateTables.ISTRING_SMALL_LENGTH:
{
_octetBufferLength = b + 1;
final String s = (_stringInterning) ? decodeUtf8StringAsString().intern() : decodeUtf8StringAsString();
_identifier = table.add(s) - 1;
return s;
}
case DecoderStateTables.ISTRING_MEDIUM_LENGTH:
{
_octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT;
final String s = (_stringInterning) ? decodeUtf8StringAsString().intern() : decodeUtf8StringAsString();
_identifier = table.add(s) - 1;
return s;
}
case DecoderStateTables.ISTRING_LARGE_LENGTH:
{
final int length = (read() << 24) |
(read() << 16) |
(read() << 8) |
read();
_octetBufferLength = length + EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT;
final String s = (_stringInterning) ? decodeUtf8StringAsString().intern() : decodeUtf8StringAsString();
_identifier = table.add(s) - 1;
return s;
}
case DecoderStateTables.ISTRING_INDEX_SMALL:
_identifier = b & EncodingConstants.INTEGER_2ND_BIT_SMALL_MASK;
return table._array[_identifier];
case DecoderStateTables.ISTRING_INDEX_MEDIUM:
_identifier = (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
return table._array[_identifier];
case DecoderStateTables.ISTRING_INDEX_LARGE:
_identifier = (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
return table._array[_identifier];
default:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingIdentifyingString"));
}
}
protected int _prefixIndex;
/*
* C.13
*/
protected final String decodeIdentifyingNonEmptyStringOnFirstBitAsPrefix(boolean namespaceNamePresent) throws FastInfosetException, IOException {
final int b = read();
switch(DecoderStateTables.ISTRING_PREFIX_NAMESPACE(b)) {
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_LENGTH_3:
{
_octetBufferLength = EncodingConstants.XML_NAMESPACE_PREFIX_LENGTH;
decodeUtf8StringAsCharBuffer();
if (_charBuffer[0] == 'x' &&
_charBuffer[1] == 'm' &&
_charBuffer[2] == 'l') {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.prefixIllegal"));
}
final String s = (_stringInterning) ? new String(_charBuffer, 0, _charBufferLength).intern() :
new String(_charBuffer, 0, _charBufferLength);
_prefixIndex = _v.prefix.add(s);
return s;
}
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_LENGTH_5:
{
_octetBufferLength = EncodingConstants.XMLNS_NAMESPACE_PREFIX_LENGTH;
decodeUtf8StringAsCharBuffer();
if (_charBuffer[0] == 'x' &&
_charBuffer[1] == 'm' &&
_charBuffer[2] == 'l' &&
_charBuffer[3] == 'n' &&
_charBuffer[4] == 's') {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.xmlns"));
}
final String s = (_stringInterning) ? new String(_charBuffer, 0, _charBufferLength).intern() :
new String(_charBuffer, 0, _charBufferLength);
_prefixIndex = _v.prefix.add(s);
return s;
}
case DecoderStateTables.ISTRING_SMALL_LENGTH:
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_LENGTH_29:
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_LENGTH_36:
{
_octetBufferLength = b + 1;
final String s = (_stringInterning) ? decodeUtf8StringAsString().intern() : decodeUtf8StringAsString();
_prefixIndex = _v.prefix.add(s);
return s;
}
case DecoderStateTables.ISTRING_MEDIUM_LENGTH:
{
_octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT;
final String s = (_stringInterning) ? decodeUtf8StringAsString().intern() : decodeUtf8StringAsString();
_prefixIndex = _v.prefix.add(s);
return s;
}
case DecoderStateTables.ISTRING_LARGE_LENGTH:
{
final int length = (read() << 24) |
(read() << 16) |
(read() << 8) |
read();
_octetBufferLength = length + EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT;
final String s = (_stringInterning) ? decodeUtf8StringAsString().intern() : decodeUtf8StringAsString();
_prefixIndex = _v.prefix.add(s);
return s;
}
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_INDEX_ZERO:
if (namespaceNamePresent) {
_prefixIndex = 0;
// Peak at next byte and check the index of the XML namespace name
if (DecoderStateTables.ISTRING_PREFIX_NAMESPACE(peek())
!= DecoderStateTables.ISTRING_PREFIX_NAMESPACE_INDEX_ZERO) {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.wrongNamespaceName"));
}
return EncodingConstants.XML_NAMESPACE_PREFIX;
} else {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.missingNamespaceName"));
}
case DecoderStateTables.ISTRING_INDEX_SMALL:
_prefixIndex = b & EncodingConstants.INTEGER_2ND_BIT_SMALL_MASK;
return _v.prefix._array[_prefixIndex - 1];
case DecoderStateTables.ISTRING_INDEX_MEDIUM:
_prefixIndex = (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
return _v.prefix._array[_prefixIndex - 1];
case DecoderStateTables.ISTRING_INDEX_LARGE:
_prefixIndex = (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
return _v.prefix._array[_prefixIndex - 1];
default:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingIdentifyingStringForPrefix"));
}
}
/*
* C.13
*/
protected final String decodeIdentifyingNonEmptyStringIndexOnFirstBitAsPrefix(boolean namespaceNamePresent) throws FastInfosetException, IOException {
final int b = read();
switch(DecoderStateTables.ISTRING_PREFIX_NAMESPACE(b)) {
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_INDEX_ZERO:
if (namespaceNamePresent) {
_prefixIndex = 0;
// Peak at next byte and check the index of the XML namespace name
if (DecoderStateTables.ISTRING_PREFIX_NAMESPACE(peek())
!= DecoderStateTables.ISTRING_PREFIX_NAMESPACE_INDEX_ZERO) {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.wrongNamespaceName"));
}
return EncodingConstants.XML_NAMESPACE_PREFIX;
} else {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.missingNamespaceName"));
}
case DecoderStateTables.ISTRING_INDEX_SMALL:
_prefixIndex = b & EncodingConstants.INTEGER_2ND_BIT_SMALL_MASK;
return _v.prefix._array[_prefixIndex - 1];
case DecoderStateTables.ISTRING_INDEX_MEDIUM:
_prefixIndex = (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
return _v.prefix._array[_prefixIndex - 1];
case DecoderStateTables.ISTRING_INDEX_LARGE:
_prefixIndex = (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
return _v.prefix._array[_prefixIndex - 1];
default:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingIdentifyingStringForPrefix"));
}
}
protected int _namespaceNameIndex;
/*
* C.13
*/
protected final String decodeIdentifyingNonEmptyStringOnFirstBitAsNamespaceName(boolean prefixPresent) throws FastInfosetException, IOException {
final int b = read();
switch(DecoderStateTables.ISTRING_PREFIX_NAMESPACE(b)) {
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_LENGTH_3:
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_LENGTH_5:
case DecoderStateTables.ISTRING_SMALL_LENGTH:
{
_octetBufferLength = b + 1;
final String s = (_stringInterning) ? decodeUtf8StringAsString().intern() : decodeUtf8StringAsString();
_namespaceNameIndex = _v.namespaceName.add(s);
return s;
}
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_LENGTH_29:
{
_octetBufferLength = EncodingConstants.XMLNS_NAMESPACE_NAME_LENGTH;
decodeUtf8StringAsCharBuffer();
if (compareCharsWithCharBufferFromEndToStart(XMLNS_NAMESPACE_NAME_CHARS)) {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.xmlnsConnotBeBoundToPrefix"));
}
final String s = (_stringInterning) ? new String(_charBuffer, 0, _charBufferLength).intern() :
new String(_charBuffer, 0, _charBufferLength);
_namespaceNameIndex = _v.namespaceName.add(s);
return s;
}
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_LENGTH_36:
{
_octetBufferLength = EncodingConstants.XML_NAMESPACE_NAME_LENGTH;
decodeUtf8StringAsCharBuffer();
if (compareCharsWithCharBufferFromEndToStart(XML_NAMESPACE_NAME_CHARS)) {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.illegalNamespaceName"));
}
final String s = (_stringInterning) ? new String(_charBuffer, 0, _charBufferLength).intern() :
new String(_charBuffer, 0, _charBufferLength);
_namespaceNameIndex = _v.namespaceName.add(s);
return s;
}
case DecoderStateTables.ISTRING_MEDIUM_LENGTH:
{
_octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT;
final String s = (_stringInterning) ? decodeUtf8StringAsString().intern() : decodeUtf8StringAsString();
_namespaceNameIndex = _v.namespaceName.add(s);
return s;
}
case DecoderStateTables.ISTRING_LARGE_LENGTH:
{
final int length = (read() << 24) |
(read() << 16) |
(read() << 8) |
read();
_octetBufferLength = length + EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT;
final String s = (_stringInterning) ? decodeUtf8StringAsString().intern() : decodeUtf8StringAsString();
_namespaceNameIndex = _v.namespaceName.add(s);
return s;
}
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_INDEX_ZERO:
if (prefixPresent) {
_namespaceNameIndex = 0;
return EncodingConstants.XML_NAMESPACE_NAME;
} else {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.namespaceWithoutPrefix"));
}
case DecoderStateTables.ISTRING_INDEX_SMALL:
_namespaceNameIndex = b & EncodingConstants.INTEGER_2ND_BIT_SMALL_MASK;
return _v.namespaceName._array[_namespaceNameIndex - 1];
case DecoderStateTables.ISTRING_INDEX_MEDIUM:
_namespaceNameIndex = (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
return _v.namespaceName._array[_namespaceNameIndex - 1];
case DecoderStateTables.ISTRING_INDEX_LARGE:
_namespaceNameIndex = (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
return _v.namespaceName._array[_namespaceNameIndex - 1];
default:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingForNamespaceName"));
}
}
/*
* C.13
*/
protected final String decodeIdentifyingNonEmptyStringIndexOnFirstBitAsNamespaceName(boolean prefixPresent) throws FastInfosetException, IOException {
final int b = read();
switch(DecoderStateTables.ISTRING_PREFIX_NAMESPACE(b)) {
case DecoderStateTables.ISTRING_PREFIX_NAMESPACE_INDEX_ZERO:
if (prefixPresent) {
_namespaceNameIndex = 0;
return EncodingConstants.XML_NAMESPACE_NAME;
} else {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.namespaceWithoutPrefix"));
}
case DecoderStateTables.ISTRING_INDEX_SMALL:
_namespaceNameIndex = b & EncodingConstants.INTEGER_2ND_BIT_SMALL_MASK;
return _v.namespaceName._array[_namespaceNameIndex - 1];
case DecoderStateTables.ISTRING_INDEX_MEDIUM:
_namespaceNameIndex = (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
return _v.namespaceName._array[_namespaceNameIndex - 1];
case DecoderStateTables.ISTRING_INDEX_LARGE:
_namespaceNameIndex = (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
return _v.namespaceName._array[_namespaceNameIndex - 1];
default:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingForNamespaceName"));
}
}
private boolean compareCharsWithCharBufferFromEndToStart(char[] c) {
int i = _charBufferLength ;
while (--i >= 0) {
if (c[i] != _charBuffer[i]) {
return false;
}
}
return true;
}
/*
* C.22
*/
protected final String decodeNonEmptyOctetStringOnSecondBitAsUtf8String() throws FastInfosetException, IOException {
decodeNonEmptyOctetStringOnSecondBitAsUtf8CharArray();
return new String(_charBuffer, 0, _charBufferLength);
}
/*
* C.22
*/
protected final void decodeNonEmptyOctetStringOnSecondBitAsUtf8CharArray() throws FastInfosetException, IOException {
decodeNonEmptyOctetStringLengthOnSecondBit();
decodeUtf8StringAsCharBuffer();
}
/*
* C.22
*/
protected final void decodeNonEmptyOctetStringLengthOnSecondBit() throws FastInfosetException, IOException {
final int b = read();
switch(DecoderStateTables.ISTRING(b)) {
case DecoderStateTables.ISTRING_SMALL_LENGTH:
_octetBufferLength = b + 1;
break;
case DecoderStateTables.ISTRING_MEDIUM_LENGTH:
_octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT;
break;
case DecoderStateTables.ISTRING_LARGE_LENGTH:
{
final int length = (read() << 24) |
(read() << 16) |
(read() << 8) |
read();
_octetBufferLength = length + EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT;
break;
}
case DecoderStateTables.ISTRING_INDEX_SMALL:
case DecoderStateTables.ISTRING_INDEX_MEDIUM:
case DecoderStateTables.ISTRING_INDEX_LARGE:
default:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingNonEmptyOctet"));
}
}
/*
* C.25
*/
protected final int decodeIntegerIndexOnSecondBit() throws FastInfosetException, IOException {
final int b = read() | 0x80;
switch(DecoderStateTables.ISTRING(b)) {
case DecoderStateTables.ISTRING_INDEX_SMALL:
return b & EncodingConstants.INTEGER_2ND_BIT_SMALL_MASK;
case DecoderStateTables.ISTRING_INDEX_MEDIUM:
return (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
case DecoderStateTables.ISTRING_INDEX_LARGE:
return (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read())
+ EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
case DecoderStateTables.ISTRING_SMALL_LENGTH:
case DecoderStateTables.ISTRING_MEDIUM_LENGTH:
case DecoderStateTables.ISTRING_LARGE_LENGTH:
default:
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingIndexOnSecondBit"));
}
}
protected final void decodeHeader() throws FastInfosetException, IOException {
if (!_isFastInfosetDocument()) {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.notFIDocument"));
}
}
protected final void decodeRestrictedAlphabetAsCharBuffer() throws FastInfosetException, IOException {
if (_identifier <= EncodingConstants.RESTRICTED_ALPHABET_BUILTIN_END) {
decodeFourBitAlphabetOctetsAsCharBuffer(BuiltInRestrictedAlphabets.table[_identifier]);
// decodeAlphabetOctetsAsCharBuffer(BuiltInRestrictedAlphabets.table[_identifier]);
} else if (_identifier >= EncodingConstants.RESTRICTED_ALPHABET_APPLICATION_START) {
CharArray ca = _v.restrictedAlphabet.get(_identifier - EncodingConstants.RESTRICTED_ALPHABET_APPLICATION_START);
if (ca == null) {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.alphabetNotPresent", new Object[]{_identifier}));
}
decodeAlphabetOctetsAsCharBuffer(ca.ch);
} else {
// 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 FastInfosetException(CommonResourceBundle.getInstance().getString("message.alphabetIdentifiersReserved"));
}
}
protected final String decodeRestrictedAlphabetAsString() throws FastInfosetException, IOException {
decodeRestrictedAlphabetAsCharBuffer();
return new String(_charBuffer, 0, _charBufferLength);
}
protected final String decodeRAOctetsAsString(char[] restrictedAlphabet) throws FastInfosetException, IOException {
decodeAlphabetOctetsAsCharBuffer(restrictedAlphabet);
return new String(_charBuffer, 0, _charBufferLength);
}
protected final void decodeFourBitAlphabetOctetsAsCharBuffer(char[] restrictedAlphabet) throws FastInfosetException, IOException {
_charBufferLength = 0;
final int characters = _octetBufferLength * 2;
if (_charBuffer.length < characters) {
_charBuffer = new char[characters];
}
int v;
for (int i = 0; i < _octetBufferLength - 1; i++) {
v = _octetBuffer[_octetBufferStart++] & 0xFF;
_charBuffer[_charBufferLength++] = restrictedAlphabet[v >> 4];
_charBuffer[_charBufferLength++] = restrictedAlphabet[v & 0x0F];
}
v = _octetBuffer[_octetBufferStart++] & 0xFF;
_charBuffer[_charBufferLength++] = restrictedAlphabet[v >> 4];
v &= 0x0F;
if (v != 0x0F) {
_charBuffer[_charBufferLength++] = restrictedAlphabet[v & 0x0F];
}
}
protected final void decodeAlphabetOctetsAsCharBuffer(char[] restrictedAlphabet) throws FastInfosetException, IOException {
if (restrictedAlphabet.length < 2) {
throw new IllegalArgumentException(CommonResourceBundle.getInstance().getString("message.alphabetMustContain2orMoreChars"));
}
int bitsPerCharacter = 1;
while ((1 << bitsPerCharacter) <= restrictedAlphabet.length) {
bitsPerCharacter++;
}
final int terminatingValue = (1 << bitsPerCharacter) - 1;
int characters = (_octetBufferLength << 3) / bitsPerCharacter;
if (characters == 0) {
throw new IOException("");
}
_charBufferLength = 0;
if (_charBuffer.length < characters) {
_charBuffer = new char[characters];
}
resetBits();
for (int i = 0; i < characters; i++) {
int value = readBits(bitsPerCharacter);
if (bitsPerCharacter < 8 && value == terminatingValue) {
int octetPosition = (i * bitsPerCharacter) >>> 3;
if (octetPosition != _octetBufferLength - 1) {
throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.alphabetIncorrectlyTerminated"));
}
break;
}
_charBuffer[_charBufferLength++] = restrictedAlphabet[value];
}
}
private int _bitsLeftInOctet;
private void resetBits() {
_bitsLeftInOctet = 0;
}
private int readBits(int bits) throws IOException {
int value = 0;
while (bits > 0) {
if (_bitsLeftInOctet == 0) {
_b = _octetBuffer[_octetBufferStart++] & 0xFF;
_bitsLeftInOctet = 8;
}
int bit = ((_b & (1 << --_bitsLeftInOctet)) > 0) ? 1 : 0;
value |= (bit << --bits);
}
return value;
}
protected final void decodeUtf8StringAsCharBuffer() throws IOException {
ensureOctetBufferSize();
decodeUtf8StringIntoCharBuffer();
}
protected final void decodeUtf8StringAsCharBuffer(char[] ch, int offset) throws IOException {
ensureOctetBufferSize();
decodeUtf8StringIntoCharBuffer(ch, offset);
}
protected final String decodeUtf8StringAsString() throws IOException {
decodeUtf8StringAsCharBuffer();
return new String(_charBuffer, 0, _charBufferLength);
}
protected final void decodeUtf16StringAsCharBuffer() throws IOException {
ensureOctetBufferSize();
decodeUtf16StringIntoCharBuffer();
}
protected final String decodeUtf16StringAsString() throws IOException {
decodeUtf16StringAsCharBuffer();
return new String(_charBuffer, 0, _charBufferLength);
}
private void ensureOctetBufferSize() throws IOException {
if (_octetBufferEnd < (_octetBufferOffset + _octetBufferLength)) {
final int octetsInBuffer = _octetBufferEnd - _octetBufferOffset;
if (_octetBuffer.length < _octetBufferLength) {
// Length to read is too large, resize the buffer
byte[] newOctetBuffer = new byte[_octetBufferLength];
// Move partially read octets to the start of the buffer
System.arraycopy(_octetBuffer, _octetBufferOffset, newOctetBuffer, 0, octetsInBuffer);
_octetBuffer = newOctetBuffer;
} else {
// Move partially read octets to the start of the buffer
System.arraycopy(_octetBuffer, _octetBufferOffset, _octetBuffer, 0, octetsInBuffer);
}
_octetBufferOffset = 0;
// Read as many octets as possible to fill the buffer
final int octetsRead = _s.read(_octetBuffer, octetsInBuffer, _octetBuffer.length - octetsInBuffer);
if (octetsRead < 0) {
throw new EOFException("Unexpeceted EOF");
}
_octetBufferEnd = octetsInBuffer + octetsRead;
// Check if the number of octets that have been read is not enough
// This can happen when underlying non-blocking is used to read
if (_octetBufferEnd < _octetBufferLength) {
repeatedRead();
}
}
}
private void repeatedRead() throws IOException {
// Check if the number of octets that have been read is not enough
while (_octetBufferEnd < _octetBufferLength) {
// Read as many octets as possible to fill the buffer
final int octetsRead = _s.read(_octetBuffer, _octetBufferEnd, _octetBuffer.length - _octetBufferEnd);
if (octetsRead < 0) {
throw new EOFException("Unexpeceted EOF");
}
_octetBufferEnd += octetsRead;
}
}
protected final void decodeUtf8StringIntoCharBuffer() throws IOException {
if (_charBuffer.length < _octetBufferLength) {
_charBuffer = new char[_octetBufferLength];
}
_charBufferLength = 0;
final int end = _octetBufferLength + _octetBufferOffset;
int b1;
while (end != _octetBufferOffset) {
b1 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if (DecoderStateTables.UTF8(b1) == DecoderStateTables.UTF8_ONE_BYTE) {
_charBuffer[_charBufferLength++] = (char) b1;
} else {
decodeTwoToFourByteUtf8Character(b1, end);
}
}
}
protected final void decodeUtf8StringIntoCharBuffer(char[] ch, int offset) throws IOException {
_charBufferLength = offset;
final int end = _octetBufferLength + _octetBufferOffset;
int b1;
while (end != _octetBufferOffset) {
b1 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if (DecoderStateTables.UTF8(b1) == DecoderStateTables.UTF8_ONE_BYTE) {
ch[_charBufferLength++] = (char) b1;
} else {
decodeTwoToFourByteUtf8Character(ch, b1, end);
}
}
_charBufferLength -= offset;
}
private void decodeTwoToFourByteUtf8Character(int b1, int end) throws IOException {
switch(DecoderStateTables.UTF8(b1)) {
case DecoderStateTables.UTF8_TWO_BYTES:
{
// Decode byte 2
if (end == _octetBufferOffset) {
decodeUtf8StringLengthTooSmall();
}
final int b2 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if ((b2 & 0xC0) != 0x80) {
decodeUtf8StringIllegalState();
}
// Character guaranteed to be in [0x20, 0xD7FF] range
// since a character encoded in two bytes will be in the
// range [0x80, 0x1FFF]
_charBuffer[_charBufferLength++] = (char) (
((b1 & 0x1F) << 6)
| (b2 & 0x3F));
break;
}
case DecoderStateTables.UTF8_THREE_BYTES:
final char c = decodeUtf8ThreeByteChar(end, b1);
if (XMLChar.isContent(c)) {
_charBuffer[_charBufferLength++] = c;
} else {
decodeUtf8StringIllegalState();
}
break;
case DecoderStateTables.UTF8_FOUR_BYTES:
{
final int supplemental = decodeUtf8FourByteChar(end, b1);
if (XMLChar.isContent(supplemental)) {
_charBuffer[_charBufferLength++] = _utf8_highSurrogate;
_charBuffer[_charBufferLength++] = _utf8_lowSurrogate;
} else {
decodeUtf8StringIllegalState();
}
break;
}
default:
decodeUtf8StringIllegalState();
}
}
private void decodeTwoToFourByteUtf8Character(char[] ch, int b1, int end) throws IOException {
switch(DecoderStateTables.UTF8(b1)) {
case DecoderStateTables.UTF8_TWO_BYTES:
{
// Decode byte 2
if (end == _octetBufferOffset) {
decodeUtf8StringLengthTooSmall();
}
final int b2 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if ((b2 & 0xC0) != 0x80) {
decodeUtf8StringIllegalState();
}
// Character guaranteed to be in [0x20, 0xD7FF] range
// since a character encoded in two bytes will be in the
// range [0x80, 0x1FFF]
ch[_charBufferLength++] = (char) (
((b1 & 0x1F) << 6)
| (b2 & 0x3F));
break;
}
case DecoderStateTables.UTF8_THREE_BYTES:
final char c = decodeUtf8ThreeByteChar(end, b1);
if (XMLChar.isContent(c)) {
ch[_charBufferLength++] = c;
} else {
decodeUtf8StringIllegalState();
}
break;
case DecoderStateTables.UTF8_FOUR_BYTES:
{
final int supplemental = decodeUtf8FourByteChar(end, b1);
if (XMLChar.isContent(supplemental)) {
ch[_charBufferLength++] = _utf8_highSurrogate;
ch[_charBufferLength++] = _utf8_lowSurrogate;
} else {
decodeUtf8StringIllegalState();
}
break;
}
default:
decodeUtf8StringIllegalState();
}
}
protected final void decodeUtf8NCNameIntoCharBuffer() throws IOException {
_charBufferLength = 0;
if (_charBuffer.length < _octetBufferLength) {
_charBuffer = new char[_octetBufferLength];
}
final int end = _octetBufferLength + _octetBufferOffset;
int b1 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if (DecoderStateTables.UTF8_NCNAME(b1) == DecoderStateTables.UTF8_NCNAME_NCNAME) {
_charBuffer[_charBufferLength++] = (char) b1;
} else {
decodeUtf8NCNameStartTwoToFourByteCharacters(b1, end);
}
while (end != _octetBufferOffset) {
b1 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if (DecoderStateTables.UTF8_NCNAME(b1) < DecoderStateTables.UTF8_TWO_BYTES) {
_charBuffer[_charBufferLength++] = (char) b1;
} else {
decodeUtf8NCNameTwoToFourByteCharacters(b1, end);
}
}
}
private void decodeUtf8NCNameStartTwoToFourByteCharacters(int b1, int end) throws IOException {
switch(DecoderStateTables.UTF8_NCNAME(b1)) {
case DecoderStateTables.UTF8_TWO_BYTES:
{
// Decode byte 2
if (end == _octetBufferOffset) {
decodeUtf8StringLengthTooSmall();
}
final int b2 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if ((b2 & 0xC0) != 0x80) {
decodeUtf8StringIllegalState();
}
final char c = (char) (
((b1 & 0x1F) << 6)
| (b2 & 0x3F));
if (XMLChar.isNCNameStart(c)) {
_charBuffer[_charBufferLength++] = c;
} else {
decodeUtf8NCNameIllegalState();
}
break;
}
case DecoderStateTables.UTF8_THREE_BYTES:
final char c = decodeUtf8ThreeByteChar(end, b1);
if (XMLChar.isNCNameStart(c)) {
_charBuffer[_charBufferLength++] = c;
} else {
decodeUtf8NCNameIllegalState();
}
break;
case DecoderStateTables.UTF8_FOUR_BYTES:
{
final int supplemental = decodeUtf8FourByteChar(end, b1);
if (XMLChar.isNCNameStart(supplemental)) {
_charBuffer[_charBufferLength++] = _utf8_highSurrogate;
_charBuffer[_charBufferLength++] = _utf8_lowSurrogate;
} else {
decodeUtf8NCNameIllegalState();
}
break;
}
case DecoderStateTables.UTF8_NCNAME_NCNAME_CHAR:
default:
decodeUtf8NCNameIllegalState();
}
}
private void decodeUtf8NCNameTwoToFourByteCharacters(int b1, int end) throws IOException {
switch(DecoderStateTables.UTF8_NCNAME(b1)) {
case DecoderStateTables.UTF8_TWO_BYTES:
{
// Decode byte 2
if (end == _octetBufferOffset) {
decodeUtf8StringLengthTooSmall();
}
final int b2 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if ((b2 & 0xC0) != 0x80) {
decodeUtf8StringIllegalState();
}
final char c = (char) (
((b1 & 0x1F) << 6)
| (b2 & 0x3F));
if (XMLChar.isNCName(c)) {
_charBuffer[_charBufferLength++] = c;
} else {
decodeUtf8NCNameIllegalState();
}
break;
}
case DecoderStateTables.UTF8_THREE_BYTES:
final char c = decodeUtf8ThreeByteChar(end, b1);
if (XMLChar.isNCName(c)) {
_charBuffer[_charBufferLength++] = c;
} else {
decodeUtf8NCNameIllegalState();
}
break;
case DecoderStateTables.UTF8_FOUR_BYTES:
{
final int supplemental = decodeUtf8FourByteChar(end, b1);
if (XMLChar.isNCName(supplemental)) {
_charBuffer[_charBufferLength++] = _utf8_highSurrogate;
_charBuffer[_charBufferLength++] = _utf8_lowSurrogate;
} else {
decodeUtf8NCNameIllegalState();
}
break;
}
default:
decodeUtf8NCNameIllegalState();
}
}
private char decodeUtf8ThreeByteChar(int end, int b1) throws IOException {
// Decode byte 2
if (end == _octetBufferOffset) {
decodeUtf8StringLengthTooSmall();
}
final int b2 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if ((b2 & 0xC0) != 0x80
|| (b1 == 0xED && b2 >= 0xA0)
|| ((b1 & 0x0F) == 0 && (b2 & 0x20) == 0)) {
decodeUtf8StringIllegalState();
}
// Decode byte 3
if (end == _octetBufferOffset) {
decodeUtf8StringLengthTooSmall();
}
final int b3 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if ((b3 & 0xC0) != 0x80) {
decodeUtf8StringIllegalState();
}
return (char) (
(b1 & 0x0F) << 12
| (b2 & 0x3F) << 6
| (b3 & 0x3F));
}
private char _utf8_highSurrogate;
private char _utf8_lowSurrogate;
private int decodeUtf8FourByteChar(int end, int b1) throws IOException {
// Decode byte 2
if (end == _octetBufferOffset) {
decodeUtf8StringLengthTooSmall();
}
final int b2 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if ((b2 & 0xC0) != 0x80
|| ((b2 & 0x30) == 0 && (b1 & 0x07) == 0)) {
decodeUtf8StringIllegalState();
}
// Decode byte 3
if (end == _octetBufferOffset) {
decodeUtf8StringLengthTooSmall();
}
final int b3 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if ((b3 & 0xC0) != 0x80) {
decodeUtf8StringIllegalState();
}
// Decode byte 4
if (end == _octetBufferOffset) {
decodeUtf8StringLengthTooSmall();
}
final int b4 = _octetBuffer[_octetBufferOffset++] & 0xFF;
if ((b4 & 0xC0) != 0x80) {
decodeUtf8StringIllegalState();
}
final int uuuuu = ((b1 << 2) & 0x001C) | ((b2 >> 4) & 0x0003);
if (uuuuu > 0x10) {
decodeUtf8StringIllegalState();
}
final int wwww = uuuuu - 1;
_utf8_highSurrogate = (char) (0xD800 |
((wwww << 6) & 0x03C0) | ((b2 << 2) & 0x003C) |
((b3 >> 4) & 0x0003));
_utf8_lowSurrogate = (char) (0xDC00 | ((b3 << 6) & 0x03C0) | (b4 & 0x003F));
return XMLChar.supplemental(_utf8_highSurrogate, _utf8_lowSurrogate);
}
private void decodeUtf8StringLengthTooSmall() throws IOException {
throw new IOException(CommonResourceBundle.getInstance().getString("message.deliminatorTooSmall"));
}
private void decodeUtf8StringIllegalState() throws IOException {
throw new IOException(CommonResourceBundle.getInstance().getString("message.UTF8Encoded"));
}
private void decodeUtf8NCNameIllegalState() throws IOException {
throw new IOException(CommonResourceBundle.getInstance().getString("message.UTF8EncodedNCName"));
}
private void decodeUtf16StringIntoCharBuffer() throws IOException {
_charBufferLength = _octetBufferLength / 2;
if (_charBuffer.length < _charBufferLength) {
_charBuffer = new char[_charBufferLength];
}
for (int i = 0; i < _charBufferLength; i++) {
final char c = (char)((read() << 8) | read());
// TODO check c is a valid Char character
_charBuffer[i] = c;
}
}
protected String createQualifiedNameString(String second) {
return createQualifiedNameString(XMLNS_NAMESPACE_PREFIX_CHARS, second);
}
protected String createQualifiedNameString(char[] first, String second) {
final int l1 = first.length;
final int l2 = second.length();
final int total = l1 + l2 + 1;
if (total < _charBuffer.length) {
System.arraycopy(first, 0, _charBuffer, 0, l1);
_charBuffer[l1] = ':';
second.getChars(0, l2, _charBuffer, l1 + 1);
return new String(_charBuffer, 0, total);
} else {
StringBuilder b = new StringBuilder(new String(first));
b.append(':');
b.append(second);
return b.toString();
}
}
protected final int read() throws IOException {
if (_octetBufferOffset < _octetBufferEnd) {
return _octetBuffer[_octetBufferOffset++] & 0xFF;
} else {
_octetBufferEnd = _s.read(_octetBuffer);
if (_octetBufferEnd < 0) {
throw new EOFException(CommonResourceBundle.getInstance().getString("message.EOF"));
}
_octetBufferOffset = 1;
return _octetBuffer[0] & 0xFF;
}
}
protected final void closeIfRequired() throws IOException {
if (_s != null && _needForceStreamClose) {
_s.close();
}
}
protected final int peek() throws IOException {
return peek(null);
}
protected final int peek(OctetBufferListener octetBufferListener) throws IOException {
if (_octetBufferOffset < _octetBufferEnd) {
return _octetBuffer[_octetBufferOffset] & 0xFF;
} else {
if (octetBufferListener != null) {
octetBufferListener.onBeforeOctetBufferOverwrite();
}
_octetBufferEnd = _s.read(_octetBuffer);
if (_octetBufferEnd < 0) {
throw new EOFException(CommonResourceBundle.getInstance().getString("message.EOF"));
}
_octetBufferOffset = 0;
return _octetBuffer[0] & 0xFF;
}
}
protected final int peek2(OctetBufferListener octetBufferListener) throws IOException {
if (_octetBufferOffset + 1 < _octetBufferEnd) {
return _octetBuffer[_octetBufferOffset + 1] & 0xFF;
} else {
if (octetBufferListener != null) {
octetBufferListener.onBeforeOctetBufferOverwrite();
}
int offset = 0;
if (_octetBufferOffset < _octetBufferEnd) {
_octetBuffer[0] = _octetBuffer[_octetBufferOffset];
offset = 1;
}
_octetBufferEnd = _s.read(_octetBuffer, offset, _octetBuffer.length - offset);
if (_octetBufferEnd < 0) {
throw new EOFException(CommonResourceBundle.getInstance().getString("message.EOF"));
}
_octetBufferOffset = 0;
return _octetBuffer[1] & 0xFF;
}
}
protected class EncodingAlgorithmInputStream extends InputStream {
protected EncodingAlgorithmInputStream() {
}
@Override
public int read() throws IOException {
if (_octetBufferStart < _octetBufferOffset) {
return (_octetBuffer[_octetBufferStart++] & 0xFF);
} else {
return -1;
}
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
final int newOctetBufferStart = _octetBufferStart + len;
if (newOctetBufferStart < _octetBufferOffset) {
System.arraycopy(_octetBuffer, _octetBufferStart, b, off, len);
_octetBufferStart = newOctetBufferStart;
return len;
} else if (_octetBufferStart < _octetBufferOffset) {
final int bytesToRead = _octetBufferOffset - _octetBufferStart;
System.arraycopy(_octetBuffer, _octetBufferStart, b, off, bytesToRead);
_octetBufferStart += bytesToRead;
return bytesToRead;
} else {
return -1;
}
}
}
protected final boolean _isFastInfosetDocument() throws IOException {
// Fill up the octet buffer
peek();
_octetBufferLength = EncodingConstants.BINARY_HEADER.length;
ensureOctetBufferSize();
_octetBufferOffset += _octetBufferLength;
// Check for binary header
if (_octetBuffer[0] != EncodingConstants.BINARY_HEADER[0] ||
_octetBuffer[1] != EncodingConstants.BINARY_HEADER[1] ||
_octetBuffer[2] != EncodingConstants.BINARY_HEADER[2] ||
_octetBuffer[3] != EncodingConstants.BINARY_HEADER[3]) {
// Check for each form of XML declaration
for (byte[] values : EncodingConstants.XML_DECLARATION_VALUES) {
_octetBufferLength = values.length - _octetBufferOffset;
ensureOctetBufferSize();
_octetBufferOffset += _octetBufferLength;
// Check XML declaration
if (arrayEquals(_octetBuffer, 0, values, values.length)) {
_octetBufferLength = EncodingConstants.BINARY_HEADER.length;
ensureOctetBufferSize();
// Check for binary header
return !(_octetBuffer[_octetBufferOffset++] != EncodingConstants.BINARY_HEADER[0]
|| _octetBuffer[_octetBufferOffset++] != EncodingConstants.BINARY_HEADER[1]
|| _octetBuffer[_octetBufferOffset++] != EncodingConstants.BINARY_HEADER[2]
|| _octetBuffer[_octetBufferOffset++] != EncodingConstants.BINARY_HEADER[3]);
}
}
return false;
}
// Fast Infoset document with binary header
return true;
}
private boolean arrayEquals(byte[] b1, int offset, byte[] b2, int length) {
for (int i = 0; i < length; i++) {
if (b1[offset + i] != b2[i]) {
return false;
}
}
return true;
}
public static boolean isFastInfosetDocument(InputStream s) throws IOException {
// TODO
// Check for