aoqi@0: /* aoqi@0: * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.fastinfoset; aoqi@0: aoqi@0: import com.sun.xml.internal.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory; aoqi@0: import com.sun.xml.internal.fastinfoset.org.apache.xerces.util.XMLChar; aoqi@0: import com.sun.xml.internal.fastinfoset.util.CharArrayIntMap; aoqi@0: import com.sun.xml.internal.fastinfoset.util.KeyIntMap; aoqi@0: import com.sun.xml.internal.fastinfoset.util.LocalNameQualifiedNamesMap; aoqi@0: import com.sun.xml.internal.fastinfoset.util.StringIntMap; aoqi@0: import com.sun.xml.internal.fastinfoset.vocab.SerializerVocabulary; aoqi@0: import java.io.IOException; aoqi@0: import java.io.OutputStream; aoqi@0: import java.util.HashMap; aoqi@0: import java.util.Map; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmException; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.ExternalVocabulary; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetSerializer; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.RestrictedAlphabet; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.VocabularyApplicationData; aoqi@0: import org.xml.sax.helpers.DefaultHandler; aoqi@0: aoqi@0: /** aoqi@0: * Abstract encoder for developing concrete encoders. aoqi@0: * aoqi@0: * Concrete implementations extending Encoder will utilize methods on Encoder aoqi@0: * to encode XML infoset according to the Fast Infoset standard. It is the aoqi@0: * responsibility of the concrete implementation to ensure that methods are aoqi@0: * invoked in the correct order to produce a valid fast infoset document. aoqi@0: * aoqi@0: *

aoqi@0: * This class extends org.sax.xml.DefaultHandler so that concrete SAX aoqi@0: * implementations can be used with javax.xml.parsers.SAXParser and the parse aoqi@0: * methods that take org.sax.xml.DefaultHandler as a parameter. aoqi@0: * aoqi@0: *

aoqi@0: * Buffering of octets that are written to an {@link java.io.OutputStream} is aoqi@0: * supported in a similar manner to a {@link java.io.BufferedOutputStream}. aoqi@0: * Combining buffering with encoding enables better performance. aoqi@0: * aoqi@0: *

aoqi@0: * More than one fast infoset document may be encoded to the aoqi@0: * {@link java.io.OutputStream}. aoqi@0: * aoqi@0: */ aoqi@0: public abstract class Encoder extends DefaultHandler implements FastInfosetSerializer { aoqi@0: aoqi@0: /** aoqi@0: * Character encoding scheme system property for the encoding aoqi@0: * of content and attribute values. aoqi@0: */ aoqi@0: public static final String CHARACTER_ENCODING_SCHEME_SYSTEM_PROPERTY = aoqi@0: "com.sun.xml.internal.fastinfoset.serializer.character-encoding-scheme"; aoqi@0: aoqi@0: /** aoqi@0: * Default character encoding scheme system property for the encoding aoqi@0: * of content and attribute values. aoqi@0: */ aoqi@0: protected static final String _characterEncodingSchemeSystemDefault = getDefaultEncodingScheme(); aoqi@0: aoqi@0: private static String getDefaultEncodingScheme() { aoqi@0: String p = System.getProperty(CHARACTER_ENCODING_SCHEME_SYSTEM_PROPERTY, aoqi@0: UTF_8); aoqi@0: if (p.equals(UTF_16BE)) { aoqi@0: return UTF_16BE; aoqi@0: } else { aoqi@0: return UTF_8; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static int[] NUMERIC_CHARACTERS_TABLE; aoqi@0: aoqi@0: private static int[] DATE_TIME_CHARACTERS_TABLE; aoqi@0: aoqi@0: static { aoqi@0: NUMERIC_CHARACTERS_TABLE = new int[maxCharacter(RestrictedAlphabet.NUMERIC_CHARACTERS) + 1]; aoqi@0: DATE_TIME_CHARACTERS_TABLE = new int[maxCharacter(RestrictedAlphabet.DATE_TIME_CHARACTERS) + 1]; aoqi@0: aoqi@0: for (int i = 0; i < NUMERIC_CHARACTERS_TABLE.length ; i++) { aoqi@0: NUMERIC_CHARACTERS_TABLE[i] = -1; aoqi@0: } aoqi@0: for (int i = 0; i < DATE_TIME_CHARACTERS_TABLE.length ; i++) { aoqi@0: DATE_TIME_CHARACTERS_TABLE[i] = -1; aoqi@0: } aoqi@0: aoqi@0: for (int i = 0; i < RestrictedAlphabet.NUMERIC_CHARACTERS.length() ; i++) { aoqi@0: NUMERIC_CHARACTERS_TABLE[RestrictedAlphabet.NUMERIC_CHARACTERS.charAt(i)] = i; aoqi@0: } aoqi@0: for (int i = 0; i < RestrictedAlphabet.DATE_TIME_CHARACTERS.length() ; i++) { aoqi@0: DATE_TIME_CHARACTERS_TABLE[RestrictedAlphabet.DATE_TIME_CHARACTERS.charAt(i)] = i; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static int maxCharacter(String alphabet) { aoqi@0: int c = 0; aoqi@0: for (int i = 0; i < alphabet.length() ; i++) { aoqi@0: if (c < alphabet.charAt(i)) { aoqi@0: c = alphabet.charAt(i); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return c; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * True if DTD and internal subset shall be ignored. aoqi@0: */ aoqi@0: private boolean _ignoreDTD; aoqi@0: aoqi@0: /** aoqi@0: * True if comments shall be ignored. aoqi@0: */ aoqi@0: private boolean _ignoreComments; aoqi@0: aoqi@0: /** aoqi@0: * True if procesing instructions shall be ignored. aoqi@0: */ aoqi@0: private boolean _ignoreProcessingInstructions; aoqi@0: aoqi@0: /** aoqi@0: * True if white space characters for text content shall be ignored. aoqi@0: */ aoqi@0: private boolean _ignoreWhiteSpaceTextContent; aoqi@0: aoqi@0: /** aoqi@0: * True, if the local name string is used as the key to find the aoqi@0: * associated set of qualified names. aoqi@0: *

aoqi@0: * False, if the : string is used as the key aoqi@0: * to find the associated set of qualified names. aoqi@0: */ aoqi@0: private boolean _useLocalNameAsKeyForQualifiedNameLookup; aoqi@0: aoqi@0: /** aoqi@0: * True if strings for text content and attribute values will be aoqi@0: * UTF-8 encoded otherwise they will be UTF-16 encoded. aoqi@0: */ aoqi@0: private boolean _encodingStringsAsUtf8 = true; aoqi@0: aoqi@0: /** aoqi@0: * Encoding constant generated from the string encoding. aoqi@0: */ aoqi@0: private int _nonIdentifyingStringOnThirdBitCES; aoqi@0: aoqi@0: /** aoqi@0: * Encoding constant generated from the string encoding. aoqi@0: */ aoqi@0: private int _nonIdentifyingStringOnFirstBitCES; aoqi@0: aoqi@0: /** aoqi@0: * The map of URIs to algorithms. aoqi@0: */ aoqi@0: private Map _registeredEncodingAlgorithms = new HashMap(); aoqi@0: aoqi@0: /** aoqi@0: * The vocabulary that is used by the encoder aoqi@0: */ aoqi@0: protected SerializerVocabulary _v; aoqi@0: aoqi@0: /** aoqi@0: * The vocabulary application data that is used by the encoder aoqi@0: */ aoqi@0: protected VocabularyApplicationData _vData; aoqi@0: aoqi@0: /** aoqi@0: * True if the vocubulary is internal to the encoder aoqi@0: */ aoqi@0: private boolean _vIsInternal; aoqi@0: aoqi@0: /** aoqi@0: * True if terminatation of an information item is required aoqi@0: */ aoqi@0: protected boolean _terminate = false; aoqi@0: aoqi@0: /** aoqi@0: * The current octet that is to be written. aoqi@0: */ aoqi@0: protected int _b; aoqi@0: aoqi@0: /** aoqi@0: * The {@link java.io.OutputStream} that the encoded XML infoset (the aoqi@0: * fast infoset document) is written to. aoqi@0: */ aoqi@0: protected OutputStream _s; aoqi@0: aoqi@0: /** aoqi@0: * The internal buffer of characters used for the UTF-8 or UTF-16 encoding aoqi@0: * of characters. aoqi@0: */ aoqi@0: protected char[] _charBuffer = new char[512]; aoqi@0: aoqi@0: /** aoqi@0: * The internal buffer of bytes. aoqi@0: */ aoqi@0: protected byte[] _octetBuffer = new byte[1024]; aoqi@0: aoqi@0: /** aoqi@0: * The current position in the internal buffer. aoqi@0: */ aoqi@0: protected int _octetBufferIndex; aoqi@0: aoqi@0: /** aoqi@0: * The current mark in the internal buffer. aoqi@0: * aoqi@0: *

aoqi@0: * If the value of the mark is < 0 then the mark is not set. aoqi@0: */ aoqi@0: protected int _markIndex = -1; aoqi@0: aoqi@0: /** aoqi@0: * The minimum size of [normalized value] of Attribute Information aoqi@0: * Items that will be indexed. aoqi@0: */ aoqi@0: protected int minAttributeValueSize = FastInfosetSerializer.MIN_ATTRIBUTE_VALUE_SIZE; aoqi@0: aoqi@0: /** aoqi@0: * The maximum size of [normalized value] of Attribute Information aoqi@0: * Items that will be indexed. aoqi@0: */ aoqi@0: protected int maxAttributeValueSize = FastInfosetSerializer.MAX_ATTRIBUTE_VALUE_SIZE; aoqi@0: aoqi@0: /** aoqi@0: * The limit on the size of indexed Map for attribute values aoqi@0: * Limit is measured in characters number aoqi@0: */ aoqi@0: protected int attributeValueMapTotalCharactersConstraint = FastInfosetSerializer.ATTRIBUTE_VALUE_MAP_MEMORY_CONSTRAINT / 2; aoqi@0: aoqi@0: /** aoqi@0: * The minimum size of character content chunks aoqi@0: * of Character Information Items or Comment Information Items that aoqi@0: * will be indexed. aoqi@0: */ aoqi@0: protected int minCharacterContentChunkSize = FastInfosetSerializer.MIN_CHARACTER_CONTENT_CHUNK_SIZE; aoqi@0: aoqi@0: /** aoqi@0: * The maximum size of character content chunks aoqi@0: * of Character Information Items or Comment Information Items that aoqi@0: * will be indexed. aoqi@0: */ aoqi@0: protected int maxCharacterContentChunkSize = FastInfosetSerializer.MAX_CHARACTER_CONTENT_CHUNK_SIZE; aoqi@0: aoqi@0: /** aoqi@0: * The limit on the size of indexed Map for character content chunks aoqi@0: * Limit is measured in characters number aoqi@0: */ aoqi@0: protected int characterContentChunkMapTotalCharactersConstraint = FastInfosetSerializer.CHARACTER_CONTENT_CHUNK_MAP_MEMORY_CONSTRAINT / 2; aoqi@0: aoqi@0: /** aoqi@0: * Default constructor for the Encoder. aoqi@0: */ aoqi@0: protected Encoder() { aoqi@0: setCharacterEncodingScheme(_characterEncodingSchemeSystemDefault); aoqi@0: } aoqi@0: aoqi@0: protected Encoder(boolean useLocalNameAsKeyForQualifiedNameLookup) { aoqi@0: setCharacterEncodingScheme(_characterEncodingSchemeSystemDefault); aoqi@0: _useLocalNameAsKeyForQualifiedNameLookup = useLocalNameAsKeyForQualifiedNameLookup; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // FastInfosetSerializer interface aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public final void setIgnoreDTD(boolean ignoreDTD) { aoqi@0: _ignoreDTD = ignoreDTD; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public final boolean getIgnoreDTD() { aoqi@0: return _ignoreDTD; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public final void setIgnoreComments(boolean ignoreComments) { aoqi@0: _ignoreComments = ignoreComments; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public final boolean getIgnoreComments() { aoqi@0: return _ignoreComments; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public final void setIgnoreProcesingInstructions(boolean aoqi@0: ignoreProcesingInstructions) { aoqi@0: _ignoreProcessingInstructions = ignoreProcesingInstructions; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public final boolean getIgnoreProcesingInstructions() { aoqi@0: return _ignoreProcessingInstructions; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public final void setIgnoreWhiteSpaceTextContent(boolean ignoreWhiteSpaceTextContent) { aoqi@0: _ignoreWhiteSpaceTextContent = ignoreWhiteSpaceTextContent; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public final boolean getIgnoreWhiteSpaceTextContent() { aoqi@0: return _ignoreWhiteSpaceTextContent; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public void setCharacterEncodingScheme(String characterEncodingScheme) { aoqi@0: if (characterEncodingScheme.equals(UTF_16BE)) { aoqi@0: _encodingStringsAsUtf8 = false; aoqi@0: _nonIdentifyingStringOnThirdBitCES = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_UTF_16_FLAG; aoqi@0: _nonIdentifyingStringOnFirstBitCES = EncodingConstants.NISTRING_UTF_16_FLAG; aoqi@0: } else { aoqi@0: _encodingStringsAsUtf8 = true; aoqi@0: _nonIdentifyingStringOnThirdBitCES = EncodingConstants.CHARACTER_CHUNK; aoqi@0: _nonIdentifyingStringOnFirstBitCES = 0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public String getCharacterEncodingScheme() { aoqi@0: return (_encodingStringsAsUtf8) ? UTF_8 : UTF_16BE; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public void setRegisteredEncodingAlgorithms(Map algorithms) { aoqi@0: _registeredEncodingAlgorithms = algorithms; aoqi@0: if (_registeredEncodingAlgorithms == null) { aoqi@0: _registeredEncodingAlgorithms = new HashMap(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public Map getRegisteredEncodingAlgorithms() { aoqi@0: return _registeredEncodingAlgorithms; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public int getMinCharacterContentChunkSize() { aoqi@0: return minCharacterContentChunkSize; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public void setMinCharacterContentChunkSize(int size) { aoqi@0: if (size < 0 ) { aoqi@0: size = 0; aoqi@0: } aoqi@0: aoqi@0: minCharacterContentChunkSize = size; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public int getMaxCharacterContentChunkSize() { aoqi@0: return maxCharacterContentChunkSize; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public void setMaxCharacterContentChunkSize(int size) { aoqi@0: if (size < 0 ) { aoqi@0: size = 0; aoqi@0: } aoqi@0: aoqi@0: maxCharacterContentChunkSize = size; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public int getCharacterContentChunkMapMemoryLimit() { aoqi@0: return characterContentChunkMapTotalCharactersConstraint * 2; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public void setCharacterContentChunkMapMemoryLimit(int size) { aoqi@0: if (size < 0 ) { aoqi@0: size = 0; aoqi@0: } aoqi@0: aoqi@0: characterContentChunkMapTotalCharactersConstraint = size / 2; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Checks whether character content chunk (its length) matches length limit aoqi@0: * aoqi@0: * @param length the length of character content chunk is checking to be added to Map. aoqi@0: * @return whether character content chunk length matches limit aoqi@0: */ aoqi@0: public boolean isCharacterContentChunkLengthMatchesLimit(int length) { aoqi@0: return length >= minCharacterContentChunkSize && aoqi@0: length < maxCharacterContentChunkSize; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Checks whether character content table has enough memory to aoqi@0: * store character content chunk with the given length aoqi@0: * aoqi@0: * @param length the length of character content chunk is checking to be added to Map. aoqi@0: * @param map the custom CharArrayIntMap, which memory limits will be checked. aoqi@0: * @return whether character content map has enough memory aoqi@0: */ aoqi@0: public boolean canAddCharacterContentToTable(int length, CharArrayIntMap map) { aoqi@0: return map.getTotalCharacterCount() + length < aoqi@0: characterContentChunkMapTotalCharactersConstraint; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public int getMinAttributeValueSize() { aoqi@0: return minAttributeValueSize; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public void setMinAttributeValueSize(int size) { aoqi@0: if (size < 0 ) { aoqi@0: size = 0; aoqi@0: } aoqi@0: aoqi@0: minAttributeValueSize = size; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public int getMaxAttributeValueSize() { aoqi@0: return maxAttributeValueSize; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public void setMaxAttributeValueSize(int size) { aoqi@0: if (size < 0 ) { aoqi@0: size = 0; aoqi@0: } aoqi@0: aoqi@0: maxAttributeValueSize = size; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public void setAttributeValueMapMemoryLimit(int size) { aoqi@0: if (size < 0 ) { aoqi@0: size = 0; aoqi@0: } aoqi@0: aoqi@0: attributeValueMapTotalCharactersConstraint = size / 2; aoqi@0: aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public int getAttributeValueMapMemoryLimit() { aoqi@0: return attributeValueMapTotalCharactersConstraint * 2; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Checks whether attribute value (its length) matches length limit aoqi@0: * aoqi@0: * @param length the length of attribute aoqi@0: * @return whether attribute value matches limit aoqi@0: */ aoqi@0: public boolean isAttributeValueLengthMatchesLimit(int length) { aoqi@0: return length >= minAttributeValueSize && aoqi@0: length < maxAttributeValueSize; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Checks whether attribute table has enough memory to aoqi@0: * store attribute value with the given length aoqi@0: * aoqi@0: * @param length the length of attribute value is checking to be added to Map. aoqi@0: * @return whether attribute map has enough memory aoqi@0: */ aoqi@0: public boolean canAddAttributeToTable(int length) { aoqi@0: return _v.attributeValue.getTotalCharacterCount() + length < aoqi@0: attributeValueMapTotalCharactersConstraint; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public void setExternalVocabulary(ExternalVocabulary v) { aoqi@0: // Create internal serializer vocabulary aoqi@0: _v = new SerializerVocabulary(); aoqi@0: // Set the external vocabulary aoqi@0: SerializerVocabulary ev = new SerializerVocabulary(v.vocabulary, aoqi@0: _useLocalNameAsKeyForQualifiedNameLookup); aoqi@0: _v.setExternalVocabulary(v.URI, aoqi@0: ev, false); aoqi@0: aoqi@0: _vIsInternal = true; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public void setVocabularyApplicationData(VocabularyApplicationData data) { aoqi@0: _vData = data; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@inheritDoc} aoqi@0: */ aoqi@0: public VocabularyApplicationData getVocabularyApplicationData() { aoqi@0: return _vData; aoqi@0: } aoqi@0: aoqi@0: // End of FastInfosetSerializer interface aoqi@0: aoqi@0: /** aoqi@0: * Reset the encoder for reuse encoding another XML infoset. aoqi@0: */ aoqi@0: public void reset() { aoqi@0: _terminate = false; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Set the OutputStream to encode the XML infoset to a aoqi@0: * fast infoset document. aoqi@0: * aoqi@0: * @param s the OutputStream where the fast infoset document is written to. aoqi@0: */ aoqi@0: public void setOutputStream(OutputStream s) { aoqi@0: _octetBufferIndex = 0; aoqi@0: _markIndex = -1; aoqi@0: _s = s; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Set the SerializerVocabulary to be used for encoding. aoqi@0: * aoqi@0: * @param vocabulary the vocabulary to be used for encoding. aoqi@0: */ aoqi@0: public void setVocabulary(SerializerVocabulary vocabulary) { aoqi@0: _v = vocabulary; aoqi@0: _vIsInternal = false; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the header of a fast infoset document. aoqi@0: * aoqi@0: * @param encodeXmlDecl true if the XML declaration should be encoded. aoqi@0: */ aoqi@0: protected final void encodeHeader(boolean encodeXmlDecl) throws IOException { aoqi@0: if (encodeXmlDecl) { aoqi@0: _s.write(EncodingConstants.XML_DECLARATION_VALUES[0]); aoqi@0: } aoqi@0: _s.write(EncodingConstants.BINARY_HEADER); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the initial vocabulary of a fast infoset document. aoqi@0: * aoqi@0: */ aoqi@0: protected final void encodeInitialVocabulary() throws IOException { aoqi@0: if (_v == null) { aoqi@0: _v = new SerializerVocabulary(); aoqi@0: _vIsInternal = true; aoqi@0: } else if (_vIsInternal) { aoqi@0: _v.clear(); aoqi@0: if (_vData != null) aoqi@0: _vData.clear(); aoqi@0: } aoqi@0: aoqi@0: if (!_v.hasInitialVocabulary() && !_v.hasExternalVocabulary()) { aoqi@0: write(0); aoqi@0: } else if (_v.hasInitialVocabulary()) { aoqi@0: _b = EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG; aoqi@0: write(_b); aoqi@0: aoqi@0: SerializerVocabulary initialVocabulary = _v.getReadOnlyVocabulary(); aoqi@0: aoqi@0: // TODO check for contents of vocabulary to assign bits aoqi@0: if (initialVocabulary.hasExternalVocabulary()) { aoqi@0: _b = EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG; aoqi@0: write(_b); aoqi@0: write(0); aoqi@0: } aoqi@0: aoqi@0: if (initialVocabulary.hasExternalVocabulary()) { aoqi@0: encodeNonEmptyOctetStringOnSecondBit(_v.getExternalVocabularyURI()); aoqi@0: } aoqi@0: aoqi@0: // TODO check for contents of vocabulary to encode values aoqi@0: } else if (_v.hasExternalVocabulary()) { aoqi@0: _b = EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG; aoqi@0: write(_b); aoqi@0: aoqi@0: _b = EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG; aoqi@0: write(_b); aoqi@0: write(0); aoqi@0: aoqi@0: encodeNonEmptyOctetStringOnSecondBit(_v.getExternalVocabularyURI()); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the termination of the Document Information Item. aoqi@0: * aoqi@0: */ aoqi@0: protected final void encodeDocumentTermination() throws IOException { aoqi@0: encodeElementTermination(); aoqi@0: encodeTermination(); aoqi@0: _flush(); aoqi@0: _s.flush(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the termination of an Element Information Item. aoqi@0: * aoqi@0: */ aoqi@0: protected final void encodeElementTermination() throws IOException { aoqi@0: _terminate = true; aoqi@0: switch (_b) { aoqi@0: case EncodingConstants.TERMINATOR: aoqi@0: _b = EncodingConstants.DOUBLE_TERMINATOR; aoqi@0: break; aoqi@0: case EncodingConstants.DOUBLE_TERMINATOR: aoqi@0: write(EncodingConstants.DOUBLE_TERMINATOR); aoqi@0: default: aoqi@0: _b = EncodingConstants.TERMINATOR; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a termination if required. aoqi@0: * aoqi@0: */ aoqi@0: protected final void encodeTermination() throws IOException { aoqi@0: if (_terminate) { aoqi@0: write(_b); aoqi@0: _b = 0; aoqi@0: _terminate = false; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a Attribute Information Item that is a namespace declaration. aoqi@0: * aoqi@0: * @param prefix the prefix of the namespace declaration, aoqi@0: * if "" then there is no prefix for the namespace declaration. aoqi@0: * @param uri the URI of the namespace declaration, aoqi@0: * if "" then there is no URI for the namespace declaration. aoqi@0: */ aoqi@0: protected final void encodeNamespaceAttribute(String prefix, String uri) throws IOException { aoqi@0: _b = EncodingConstants.NAMESPACE_ATTRIBUTE; aoqi@0: if (prefix.length() > 0) { aoqi@0: _b |= EncodingConstants.NAMESPACE_ATTRIBUTE_PREFIX_FLAG; aoqi@0: } aoqi@0: if (uri.length() > 0) { aoqi@0: _b |= EncodingConstants.NAMESPACE_ATTRIBUTE_NAME_FLAG; aoqi@0: } aoqi@0: aoqi@0: // NOTE a prefix with out a namespace name is an undeclaration aoqi@0: // of the namespace bound to the prefix aoqi@0: // TODO needs to investigate how the startPrefixMapping works in aoqi@0: // relation to undeclaration aoqi@0: aoqi@0: write(_b); aoqi@0: aoqi@0: if (prefix.length() > 0) { aoqi@0: encodeIdentifyingNonEmptyStringOnFirstBit(prefix, _v.prefix); aoqi@0: } aoqi@0: if (uri.length() > 0) { aoqi@0: encodeIdentifyingNonEmptyStringOnFirstBit(uri, _v.namespaceName); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a chunk of Character Information Items. aoqi@0: * aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * @throws ArrayIndexOutOfBoundsException. aoqi@0: */ aoqi@0: protected final void encodeCharacters(char[] ch, int offset, int length) throws IOException { aoqi@0: final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); aoqi@0: encodeNonIdentifyingStringOnThirdBit(ch, offset, length, _v.characterContentChunk, addToTable, true); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a chunk of Character Information Items. aoqi@0: * aoqi@0: * If the array of characters is to be indexed (as determined by aoqi@0: * {@link Encoder#characterContentChunkSizeContraint}) then the array is not cloned aoqi@0: * when adding the array to the vocabulary. aoqi@0: * aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * @throws ArrayIndexOutOfBoundsException. aoqi@0: */ aoqi@0: protected final void encodeCharactersNoClone(char[] ch, int offset, int length) throws IOException { aoqi@0: final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); aoqi@0: encodeNonIdentifyingStringOnThirdBit(ch, offset, length, _v.characterContentChunk, addToTable, false); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a chunk of Character Information Items using a numeric aoqi@0: * alphabet that results in the encoding of a character in 4 bits aoqi@0: * (or two characters per octet). aoqi@0: * aoqi@0: * @param id the restricted alphabet identifier. aoqi@0: * @param table the table mapping characters to 4 bit values. aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * @param addToTable if characters should be added to table. aoqi@0: * @throws ArrayIndexOutOfBoundsException. aoqi@0: */ aoqi@0: protected final void encodeNumericFourBitCharacters(char[] ch, int offset, int length, aoqi@0: boolean addToTable) throws FastInfosetException, IOException { aoqi@0: encodeFourBitCharacters(RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX, aoqi@0: NUMERIC_CHARACTERS_TABLE, ch, offset, length, addToTable); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a chunk of Character Information Items using a date-time aoqi@0: * alphabet that results in the encoding of a character in 4 bits aoqi@0: * (or two characters per octet). aoqi@0: * aoqi@0: * @param id the restricted alphabet identifier. aoqi@0: * @param table the table mapping characters to 4 bit values. aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * @param addToTable if characters should be added to table. aoqi@0: * @throws ArrayIndexOutOfBoundsException. aoqi@0: */ aoqi@0: protected final void encodeDateTimeFourBitCharacters(char[] ch, int offset, int length, aoqi@0: boolean addToTable) throws FastInfosetException, IOException { aoqi@0: encodeFourBitCharacters(RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX, aoqi@0: DATE_TIME_CHARACTERS_TABLE, ch, offset, length, addToTable); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a chunk of Character Information Items using a restricted aoqi@0: * alphabet that results in the encoding of a character in 4 bits aoqi@0: * (or two characters per octet). aoqi@0: * aoqi@0: * @param id the restricted alphabet identifier. aoqi@0: * @param table the table mapping characters to 4 bit values. aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * @param addToTable if characters should be added to table. aoqi@0: * @throws ArrayIndexOutOfBoundsException. aoqi@0: */ aoqi@0: protected final void encodeFourBitCharacters(int id, int[] table, char[] ch, int offset, int length, aoqi@0: boolean addToTable) throws FastInfosetException, IOException { aoqi@0: if (addToTable) { aoqi@0: // if char array could be added to table aoqi@0: boolean canAddCharacterContentToTable = aoqi@0: canAddCharacterContentToTable(length, _v.characterContentChunk); aoqi@0: aoqi@0: // obtain/get index aoqi@0: int index = canAddCharacterContentToTable ? aoqi@0: _v.characterContentChunk.obtainIndex(ch, offset, length, true) : aoqi@0: _v.characterContentChunk.get(ch, offset, length); aoqi@0: aoqi@0: if (index != KeyIntMap.NOT_PRESENT) { aoqi@0: // if char array is in table aoqi@0: _b = EncodingConstants.CHARACTER_CHUNK | 0x20; aoqi@0: encodeNonZeroIntegerOnFourthBit(index); aoqi@0: return; aoqi@0: } else if (canAddCharacterContentToTable) { aoqi@0: // if char array is not in table, but could be added aoqi@0: _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG | EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG; aoqi@0: } else { aoqi@0: // if char array is not in table and could not be added aoqi@0: _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG; aoqi@0: } aoqi@0: } else { aoqi@0: _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG; aoqi@0: } aoqi@0: aoqi@0: write (_b); aoqi@0: aoqi@0: // Encode bottom 6 bits of enoding algorithm id aoqi@0: _b = id << 2; aoqi@0: aoqi@0: encodeNonEmptyFourBitCharacterStringOnSeventhBit(table, ch, offset, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a chunk of Character Information Items using a restricted aoqi@0: * alphabet table. aoqi@0: * aoqi@0: * @param alphabet the alphabet defining the mapping between characters and aoqi@0: * integer values. aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * @param addToTable if characters should be added to table aoqi@0: * @throws ArrayIndexOutOfBoundsException. aoqi@0: * @throws FastInfosetException if the alphabet is not present in the aoqi@0: * vocabulary. aoqi@0: */ aoqi@0: protected final void encodeAlphabetCharacters(String alphabet, char[] ch, int offset, int length, aoqi@0: boolean addToTable) throws FastInfosetException, IOException { aoqi@0: if (addToTable) { aoqi@0: // if char array could be added to table aoqi@0: boolean canAddCharacterContentToTable = aoqi@0: canAddCharacterContentToTable(length, _v.characterContentChunk); aoqi@0: aoqi@0: // obtain/get index aoqi@0: int index = canAddCharacterContentToTable ? aoqi@0: _v.characterContentChunk.obtainIndex(ch, offset, length, true) : aoqi@0: _v.characterContentChunk.get(ch, offset, length); aoqi@0: aoqi@0: if (index != KeyIntMap.NOT_PRESENT) { aoqi@0: // if char array is in table aoqi@0: _b = EncodingConstants.CHARACTER_CHUNK | 0x20; aoqi@0: encodeNonZeroIntegerOnFourthBit(index); aoqi@0: return; aoqi@0: } else if (canAddCharacterContentToTable) { aoqi@0: // if char array is not in table, but could be added aoqi@0: _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG | EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG; aoqi@0: } else { aoqi@0: // if char array is not in table and could not be added aoqi@0: _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG; aoqi@0: } aoqi@0: } else { aoqi@0: _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG; aoqi@0: } aoqi@0: aoqi@0: int id = _v.restrictedAlphabet.get(alphabet); aoqi@0: if (id == KeyIntMap.NOT_PRESENT) { aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.restrictedAlphabetNotPresent")); aoqi@0: } aoqi@0: id += EncodingConstants.RESTRICTED_ALPHABET_APPLICATION_START; aoqi@0: aoqi@0: _b |= (id & 0xC0) >> 6; aoqi@0: write(_b); aoqi@0: aoqi@0: // Encode bottom 6 bits of enoding algorithm id aoqi@0: _b = (id & 0x3F) << 2; aoqi@0: aoqi@0: encodeNonEmptyNBitCharacterStringOnSeventhBit(alphabet, ch, offset, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a Processing Instruction Information Item. aoqi@0: * aoqi@0: * @param target the target of the processing instruction. aoqi@0: * @param data the data of the processing instruction. aoqi@0: */ aoqi@0: protected final void encodeProcessingInstruction(String target, String data) throws IOException { aoqi@0: write(EncodingConstants.PROCESSING_INSTRUCTION); aoqi@0: aoqi@0: // Target aoqi@0: encodeIdentifyingNonEmptyStringOnFirstBit(target, _v.otherNCName); aoqi@0: aoqi@0: // Data aoqi@0: boolean addToTable = isCharacterContentChunkLengthMatchesLimit(data.length()); aoqi@0: encodeNonIdentifyingStringOnFirstBit(data, _v.otherString, addToTable); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a Document Type Declaration. aoqi@0: * aoqi@0: * @param systemId the system identifier of the external subset. aoqi@0: * @param publicId the public identifier of the external subset. aoqi@0: */ aoqi@0: protected final void encodeDocumentTypeDeclaration(String systemId, String publicId) throws IOException { aoqi@0: _b = EncodingConstants.DOCUMENT_TYPE_DECLARATION; aoqi@0: if (systemId != null && systemId.length() > 0) { aoqi@0: _b |= EncodingConstants.DOCUMENT_TYPE_SYSTEM_IDENTIFIER_FLAG; aoqi@0: } aoqi@0: if (publicId != null && publicId.length() > 0) { aoqi@0: _b |= EncodingConstants.DOCUMENT_TYPE_PUBLIC_IDENTIFIER_FLAG; aoqi@0: } aoqi@0: write(_b); aoqi@0: aoqi@0: if (systemId != null && systemId.length() > 0) { aoqi@0: encodeIdentifyingNonEmptyStringOnFirstBit(systemId, _v.otherURI); aoqi@0: } aoqi@0: if (publicId != null && publicId.length() > 0) { aoqi@0: encodeIdentifyingNonEmptyStringOnFirstBit(publicId, _v.otherURI); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a Comment Information Item. aoqi@0: * aoqi@0: * @param ch the array of characters that is as comment. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * @throws ArrayIndexOutOfBoundsException. aoqi@0: */ aoqi@0: protected final void encodeComment(char[] ch, int offset, int length) throws IOException { aoqi@0: write(EncodingConstants.COMMENT); aoqi@0: aoqi@0: boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); aoqi@0: encodeNonIdentifyingStringOnFirstBit(ch, offset, length, _v.otherString, addToTable, true); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a Comment Information Item. aoqi@0: * aoqi@0: * If the array of characters that is a comment is to be indexed (as aoqi@0: * determined by {@link Encoder#characterContentChunkSizeContraint}) then aoqi@0: * the array is not cloned when adding the array to the vocabulary. aoqi@0: * aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * @throws ArrayIndexOutOfBoundsException. aoqi@0: */ aoqi@0: protected final void encodeCommentNoClone(char[] ch, int offset, int length) throws IOException { aoqi@0: write(EncodingConstants.COMMENT); aoqi@0: aoqi@0: boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); aoqi@0: encodeNonIdentifyingStringOnFirstBit(ch, offset, length, _v.otherString, addToTable, false); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a qualified name of an Element Informaiton Item on the third bit aoqi@0: * of an octet. aoqi@0: * Implementation of clause C.18 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: *

aoqi@0: * The index of the qualified name will be encoded if the name is present aoqi@0: * in the vocabulary otherwise the qualified name will be encoded literally aoqi@0: * (see {@link #encodeLiteralElementQualifiedNameOnThirdBit}). aoqi@0: * aoqi@0: * @param namespaceURI the namespace URI of the qualified name. aoqi@0: * @param prefix the prefix of the qualified name. aoqi@0: * @param localName the local name of the qualified name. aoqi@0: */ aoqi@0: protected final void encodeElementQualifiedNameOnThirdBit(String namespaceURI, String prefix, String localName) throws IOException { aoqi@0: LocalNameQualifiedNamesMap.Entry entry = _v.elementName.obtainEntry(localName); aoqi@0: if (entry._valueIndex > 0) { aoqi@0: QualifiedName[] names = entry._value; aoqi@0: for (int i = 0; i < entry._valueIndex; i++) { aoqi@0: if ((prefix == names[i].prefix || prefix.equals(names[i].prefix)) aoqi@0: && (namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) { aoqi@0: encodeNonZeroIntegerOnThirdBit(names[i].index); aoqi@0: return; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: encodeLiteralElementQualifiedNameOnThirdBit(namespaceURI, prefix, aoqi@0: localName, entry); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a literal qualified name of an Element Informaiton Item on the aoqi@0: * third bit of an octet. aoqi@0: * Implementation of clause C.18 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param namespaceURI the namespace URI of the qualified name. aoqi@0: * @param prefix the prefix of the qualified name. aoqi@0: * @param localName the local name of the qualified name. aoqi@0: */ aoqi@0: protected final void encodeLiteralElementQualifiedNameOnThirdBit(String namespaceURI, String prefix, String localName, aoqi@0: LocalNameQualifiedNamesMap.Entry entry) throws IOException { aoqi@0: QualifiedName name = new QualifiedName(prefix, namespaceURI, localName, "", _v.elementName.getNextIndex()); aoqi@0: entry.addQualifiedName(name); aoqi@0: aoqi@0: int namespaceURIIndex = KeyIntMap.NOT_PRESENT; aoqi@0: int prefixIndex = KeyIntMap.NOT_PRESENT; aoqi@0: if (namespaceURI.length() > 0) { aoqi@0: namespaceURIIndex = _v.namespaceName.get(namespaceURI); aoqi@0: if (namespaceURIIndex == KeyIntMap.NOT_PRESENT) { aoqi@0: throw new IOException(CommonResourceBundle.getInstance().getString("message.namespaceURINotIndexed", new Object[]{namespaceURI})); aoqi@0: } aoqi@0: aoqi@0: if (prefix.length() > 0) { aoqi@0: prefixIndex = _v.prefix.get(prefix); aoqi@0: if (prefixIndex == KeyIntMap.NOT_PRESENT) { aoqi@0: throw new IOException(CommonResourceBundle.getInstance().getString("message.prefixNotIndexed", new Object[]{prefix})); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: int localNameIndex = _v.localName.obtainIndex(localName); aoqi@0: aoqi@0: _b |= EncodingConstants.ELEMENT_LITERAL_QNAME_FLAG; aoqi@0: if (namespaceURIIndex >= 0) { aoqi@0: _b |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG; aoqi@0: if (prefixIndex >= 0) { aoqi@0: _b |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG; aoqi@0: } aoqi@0: } aoqi@0: write(_b); aoqi@0: aoqi@0: if (namespaceURIIndex >= 0) { aoqi@0: if (prefixIndex >= 0) { aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(prefixIndex); aoqi@0: } aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(namespaceURIIndex); aoqi@0: } aoqi@0: aoqi@0: if (localNameIndex >= 0) { aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex); aoqi@0: } else { aoqi@0: encodeNonEmptyOctetStringOnSecondBit(localName); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a qualified name of an Attribute Informaiton Item on the third bit aoqi@0: * of an octet. aoqi@0: * Implementation of clause C.17 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: *

aoqi@0: * The index of the qualified name will be encoded if the name is present aoqi@0: * in the vocabulary otherwise the qualified name will be encoded literally aoqi@0: * (see {@link #encodeLiteralAttributeQualifiedNameOnSecondBit}). aoqi@0: * aoqi@0: * @param namespaceURI the namespace URI of the qualified name. aoqi@0: * @param prefix the prefix of the qualified name. aoqi@0: * @param localName the local name of the qualified name. aoqi@0: */ aoqi@0: protected final void encodeAttributeQualifiedNameOnSecondBit(String namespaceURI, String prefix, String localName) throws IOException { aoqi@0: LocalNameQualifiedNamesMap.Entry entry = _v.attributeName.obtainEntry(localName); aoqi@0: if (entry._valueIndex > 0) { aoqi@0: QualifiedName[] names = entry._value; aoqi@0: for (int i = 0; i < entry._valueIndex; i++) { aoqi@0: if ((prefix == names[i].prefix || prefix.equals(names[i].prefix)) aoqi@0: && (namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) { aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitZero(names[i].index); aoqi@0: return; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: encodeLiteralAttributeQualifiedNameOnSecondBit(namespaceURI, prefix, aoqi@0: localName, entry); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a literal qualified name of an Attribute Informaiton Item on the aoqi@0: * third bit of an octet. aoqi@0: * Implementation of clause C.17 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param namespaceURI the namespace URI of the qualified name. aoqi@0: * @param prefix the prefix of the qualified name. aoqi@0: * @param localName the local name of the qualified name. aoqi@0: */ aoqi@0: protected final boolean encodeLiteralAttributeQualifiedNameOnSecondBit(String namespaceURI, String prefix, String localName, aoqi@0: LocalNameQualifiedNamesMap.Entry entry) throws IOException { aoqi@0: int namespaceURIIndex = KeyIntMap.NOT_PRESENT; aoqi@0: int prefixIndex = KeyIntMap.NOT_PRESENT; aoqi@0: if (namespaceURI.length() > 0) { aoqi@0: namespaceURIIndex = _v.namespaceName.get(namespaceURI); aoqi@0: if (namespaceURIIndex == KeyIntMap.NOT_PRESENT) { aoqi@0: if (namespaceURI == EncodingConstants.XMLNS_NAMESPACE_NAME || aoqi@0: namespaceURI.equals(EncodingConstants.XMLNS_NAMESPACE_NAME)) { aoqi@0: return false; aoqi@0: } else { aoqi@0: throw new IOException(CommonResourceBundle.getInstance().getString("message.namespaceURINotIndexed", new Object[]{namespaceURI})); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (prefix.length() > 0) { aoqi@0: prefixIndex = _v.prefix.get(prefix); aoqi@0: if (prefixIndex == KeyIntMap.NOT_PRESENT) { aoqi@0: throw new IOException(CommonResourceBundle.getInstance().getString("message.prefixNotIndexed", new Object[]{prefix})); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: int localNameIndex = _v.localName.obtainIndex(localName); aoqi@0: aoqi@0: QualifiedName name = new QualifiedName(prefix, namespaceURI, localName, "", _v.attributeName.getNextIndex()); aoqi@0: entry.addQualifiedName(name); aoqi@0: aoqi@0: _b = EncodingConstants.ATTRIBUTE_LITERAL_QNAME_FLAG; aoqi@0: if (namespaceURI.length() > 0) { aoqi@0: _b |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG; aoqi@0: if (prefix.length() > 0) { aoqi@0: _b |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: write(_b); aoqi@0: aoqi@0: if (namespaceURIIndex >= 0) { aoqi@0: if (prefixIndex >= 0) { aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(prefixIndex); aoqi@0: } aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(namespaceURIIndex); aoqi@0: } else if (namespaceURI != "") { aoqi@0: // XML prefix and namespace name aoqi@0: encodeNonEmptyOctetStringOnSecondBit("xml"); aoqi@0: encodeNonEmptyOctetStringOnSecondBit("http://www.w3.org/XML/1998/namespace"); aoqi@0: } aoqi@0: aoqi@0: if (localNameIndex >= 0) { aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex); aoqi@0: } else { aoqi@0: encodeNonEmptyOctetStringOnSecondBit(localName); aoqi@0: } aoqi@0: aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non identifying string on the first bit of an octet. aoqi@0: * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param s the string to encode aoqi@0: * @param map the vocabulary table of strings to indexes. aoqi@0: * @param addToTable true if the string could be added to the vocabulary aoqi@0: * table (if table has enough memory) aoqi@0: * @param mustBeAddedToTable true if the string must be added to the vocabulary aoqi@0: * table (if not already present in the table). aoqi@0: */ aoqi@0: protected final void encodeNonIdentifyingStringOnFirstBit(String s, StringIntMap map, aoqi@0: boolean addToTable, boolean mustBeAddedToTable) throws IOException { aoqi@0: if (s == null || s.length() == 0) { aoqi@0: // C.26 an index (first bit '1') with seven '1' bits for an empty string aoqi@0: write(0xFF); aoqi@0: } else { aoqi@0: if (addToTable || mustBeAddedToTable) { aoqi@0: // if attribute value could be added to table aoqi@0: boolean canAddAttributeToTable = mustBeAddedToTable || aoqi@0: canAddAttributeToTable(s.length()); aoqi@0: aoqi@0: // obtain/get index aoqi@0: int index = canAddAttributeToTable ? aoqi@0: map.obtainIndex(s) : aoqi@0: map.get(s); aoqi@0: aoqi@0: if (index != KeyIntMap.NOT_PRESENT) { aoqi@0: // if attribute value is in table aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(index); aoqi@0: } else if (canAddAttributeToTable) { aoqi@0: // if attribute value is not in table, but could be added aoqi@0: _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG | aoqi@0: _nonIdentifyingStringOnFirstBitCES; aoqi@0: encodeNonEmptyCharacterStringOnFifthBit(s); aoqi@0: } else { aoqi@0: // if attribute value is not in table and could not be added aoqi@0: _b = _nonIdentifyingStringOnFirstBitCES; aoqi@0: encodeNonEmptyCharacterStringOnFifthBit(s); aoqi@0: } aoqi@0: } else { aoqi@0: _b = _nonIdentifyingStringOnFirstBitCES; aoqi@0: encodeNonEmptyCharacterStringOnFifthBit(s); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non identifying string on the first bit of an octet. aoqi@0: * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param s the string to encode aoqi@0: * @param map the vocabulary table of character arrays to indexes. aoqi@0: * @param addToTable true if the string should be added to the vocabulary aoqi@0: * table (if not already present in the table). aoqi@0: */ aoqi@0: protected final void encodeNonIdentifyingStringOnFirstBit(String s, CharArrayIntMap map, boolean addToTable) throws IOException { aoqi@0: if (s == null || s.length() == 0) { aoqi@0: // C.26 an index (first bit '1') with seven '1' bits for an empty string aoqi@0: write(0xFF); aoqi@0: } else { aoqi@0: if (addToTable) { aoqi@0: final char[] ch = s.toCharArray(); aoqi@0: final int length = s.length(); aoqi@0: aoqi@0: // if char array could be added to table aoqi@0: boolean canAddCharacterContentToTable = aoqi@0: canAddCharacterContentToTable(length, map); aoqi@0: aoqi@0: // obtain/get index aoqi@0: int index = canAddCharacterContentToTable ? aoqi@0: map.obtainIndex(ch, 0, length, false) : aoqi@0: map.get(ch, 0, length); aoqi@0: aoqi@0: if (index != KeyIntMap.NOT_PRESENT) { aoqi@0: // if char array is in table aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(index); aoqi@0: } else if (canAddCharacterContentToTable) { aoqi@0: // if char array is not in table, but could be added aoqi@0: _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG | aoqi@0: _nonIdentifyingStringOnFirstBitCES; aoqi@0: encodeNonEmptyCharacterStringOnFifthBit(ch, 0, length); aoqi@0: } else { aoqi@0: // if char array is not in table and could not be added aoqi@0: _b = _nonIdentifyingStringOnFirstBitCES; aoqi@0: encodeNonEmptyCharacterStringOnFifthBit(s); aoqi@0: } aoqi@0: } else { aoqi@0: _b = _nonIdentifyingStringOnFirstBitCES; aoqi@0: encodeNonEmptyCharacterStringOnFifthBit(s); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non identifying string on the first bit of an octet. aoqi@0: * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * @param map the vocabulary table of character arrays to indexes. aoqi@0: * @param addToTable true if the string should be added to the vocabulary aoqi@0: * table (if not already present in the table). aoqi@0: * @param clone true if the array of characters should be cloned if added aoqi@0: * to the vocabulary table. aoqi@0: */ aoqi@0: protected final void encodeNonIdentifyingStringOnFirstBit(char[] ch, int offset, int length, CharArrayIntMap map, aoqi@0: boolean addToTable, boolean clone) throws IOException { aoqi@0: if (length == 0) { aoqi@0: // C.26 an index (first bit '1') with seven '1' bits for an empty string aoqi@0: write(0xFF); aoqi@0: } else { aoqi@0: if (addToTable) { aoqi@0: // if char array could be added to table aoqi@0: boolean canAddCharacterContentToTable = aoqi@0: canAddCharacterContentToTable(length, map); aoqi@0: aoqi@0: // obtain/get index aoqi@0: int index = canAddCharacterContentToTable ? aoqi@0: map.obtainIndex(ch, offset, length, clone) : aoqi@0: map.get(ch, offset, length); aoqi@0: aoqi@0: if (index != KeyIntMap.NOT_PRESENT) { aoqi@0: // if char array is in table aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(index); aoqi@0: } else if (canAddCharacterContentToTable) { aoqi@0: // if char array is not in table, but could be added aoqi@0: _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG | aoqi@0: _nonIdentifyingStringOnFirstBitCES; aoqi@0: encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length); aoqi@0: } else { aoqi@0: // if char array is not in table and could not be added aoqi@0: _b = _nonIdentifyingStringOnFirstBitCES; aoqi@0: encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length); aoqi@0: } aoqi@0: } else { aoqi@0: _b = _nonIdentifyingStringOnFirstBitCES; aoqi@0: encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void encodeNumericNonIdentifyingStringOnFirstBit( aoqi@0: String s, boolean addToTable, boolean mustBeAddedToTable) aoqi@0: throws IOException, FastInfosetException { aoqi@0: encodeNonIdentifyingStringOnFirstBit( aoqi@0: RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX, aoqi@0: NUMERIC_CHARACTERS_TABLE, s, addToTable, aoqi@0: mustBeAddedToTable); aoqi@0: } aoqi@0: aoqi@0: protected final void encodeDateTimeNonIdentifyingStringOnFirstBit( aoqi@0: String s, boolean addToTable, boolean mustBeAddedToTable) aoqi@0: throws IOException, FastInfosetException { aoqi@0: encodeNonIdentifyingStringOnFirstBit( aoqi@0: RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX, aoqi@0: DATE_TIME_CHARACTERS_TABLE, s, addToTable, aoqi@0: mustBeAddedToTable); aoqi@0: } aoqi@0: aoqi@0: protected final void encodeNonIdentifyingStringOnFirstBit(int id, int[] table, aoqi@0: String s, boolean addToTable, boolean mustBeAddedToTable) aoqi@0: throws IOException, FastInfosetException { aoqi@0: if (s == null || s.length() == 0) { aoqi@0: // C.26 an index (first bit '1') with seven '1' bits for an empty string aoqi@0: write(0xFF); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: if (addToTable || mustBeAddedToTable) { aoqi@0: // if attribute value could be added to table aoqi@0: boolean canAddAttributeToTable = mustBeAddedToTable || aoqi@0: canAddAttributeToTable(s.length()); aoqi@0: aoqi@0: // obtain/get index aoqi@0: int index = canAddAttributeToTable ? aoqi@0: _v.attributeValue.obtainIndex(s) : aoqi@0: _v.attributeValue.get(s); aoqi@0: aoqi@0: if (index != KeyIntMap.NOT_PRESENT) { aoqi@0: // if attribute value is in table aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(index); aoqi@0: return; aoqi@0: } else if (canAddAttributeToTable) { aoqi@0: // if attribute value is not in table, but could be added aoqi@0: _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG | aoqi@0: EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG; aoqi@0: } else { aoqi@0: // if attribute value is not in table and could not be added aoqi@0: _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG; aoqi@0: } aoqi@0: } else { aoqi@0: _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG; aoqi@0: } aoqi@0: aoqi@0: // Encode identification and top four bits of alphabet id aoqi@0: write (_b | ((id & 0xF0) >> 4)); aoqi@0: // Encode bottom 4 bits of alphabet id aoqi@0: _b = (id & 0x0F) << 4; aoqi@0: aoqi@0: final int length = s.length(); aoqi@0: final int octetPairLength = length / 2; aoqi@0: final int octetSingleLength = length % 2; aoqi@0: encodeNonZeroOctetStringLengthOnFifthBit(octetPairLength + octetSingleLength); aoqi@0: encodeNonEmptyFourBitCharacterString(table, s.toCharArray(), 0, octetPairLength, octetSingleLength); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non identifying string on the first bit of an octet as binary aoqi@0: * data using an encoding algorithm. aoqi@0: * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param URI the encoding algorithm URI. If the URI == null then the aoqi@0: * encoding algorithm identifier takes precendence. aoqi@0: * @param id the encoding algorithm identifier. aoqi@0: * @param data the data to be encoded using an encoding algorithm. aoqi@0: * @throws EncodingAlgorithmException if the encoding algorithm URI is not aoqi@0: * present in the vocabulary, or the encoding algorithm identifier aoqi@0: * is not with the required range. aoqi@0: */ aoqi@0: protected final void encodeNonIdentifyingStringOnFirstBit(String URI, int id, Object data) throws FastInfosetException, IOException { aoqi@0: if (URI != null) { aoqi@0: id = _v.encodingAlgorithm.get(URI); aoqi@0: if (id == KeyIntMap.NOT_PRESENT) { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI})); aoqi@0: } aoqi@0: id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START; aoqi@0: aoqi@0: EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI); aoqi@0: if (ea != null) { aoqi@0: encodeAIIObjectAlgorithmData(id, data, ea); aoqi@0: } else { aoqi@0: if (data instanceof byte[]) { aoqi@0: byte[] d = (byte[])data; aoqi@0: encodeAIIOctetAlgorithmData(id, d, 0, d.length); aoqi@0: } else { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI")); aoqi@0: } aoqi@0: } aoqi@0: } else if (id <= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { aoqi@0: int length = 0; aoqi@0: switch(id) { aoqi@0: case EncodingAlgorithmIndexes.HEXADECIMAL: aoqi@0: case EncodingAlgorithmIndexes.BASE64: aoqi@0: length = ((byte[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.SHORT: aoqi@0: length = ((short[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.INT: aoqi@0: length = ((int[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.LONG: aoqi@0: case EncodingAlgorithmIndexes.UUID: aoqi@0: length = ((long[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.BOOLEAN: aoqi@0: length = ((boolean[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.FLOAT: aoqi@0: length = ((float[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.DOUBLE: aoqi@0: length = ((double[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.CDATA: aoqi@0: throw new UnsupportedOperationException(CommonResourceBundle.getInstance().getString("message.CDATA")); aoqi@0: default: aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.UnsupportedBuiltInAlgorithm", new Object[]{Integer.valueOf(id)})); aoqi@0: } aoqi@0: encodeAIIBuiltInAlgorithmData(id, data, 0, length); aoqi@0: } else if (id >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { aoqi@0: if (data instanceof byte[]) { aoqi@0: byte[] d = (byte[])data; aoqi@0: encodeAIIOctetAlgorithmData(id, d, 0, d.length); aoqi@0: } else { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI")); aoqi@0: } aoqi@0: } else { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the [normalized value] of an Attribute Information Item using aoqi@0: * using an encoding algorithm. aoqi@0: * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param id the encoding algorithm identifier. aoqi@0: * @param d the data, as an array of bytes, to be encoded. aoqi@0: * @param offset the offset into the array of bytes. aoqi@0: * @param length the length of bytes. aoqi@0: */ aoqi@0: protected final void encodeAIIOctetAlgorithmData(int id, byte[] d, int offset, int length) throws IOException { aoqi@0: // Encode identification and top four bits of encoding algorithm id aoqi@0: write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG | aoqi@0: ((id & 0xF0) >> 4)); aoqi@0: aoqi@0: // Encode bottom 4 bits of enoding algorithm id aoqi@0: _b = (id & 0x0F) << 4; aoqi@0: aoqi@0: // Encode the length aoqi@0: encodeNonZeroOctetStringLengthOnFifthBit(length); aoqi@0: aoqi@0: write(d, offset, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the [normalized value] of an Attribute Information Item using aoqi@0: * using an encoding algorithm. aoqi@0: * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param id the encoding algorithm identifier. aoqi@0: * @param data the data to be encoded using an encoding algorithm. aoqi@0: * @param ea the encoding algorithm to use to encode the data into an aoqi@0: * array of bytes. aoqi@0: */ aoqi@0: protected final void encodeAIIObjectAlgorithmData(int id, Object data, EncodingAlgorithm ea) throws FastInfosetException, IOException { aoqi@0: // Encode identification and top four bits of encoding algorithm id aoqi@0: write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG | aoqi@0: ((id & 0xF0) >> 4)); aoqi@0: aoqi@0: // Encode bottom 4 bits of enoding algorithm id aoqi@0: _b = (id & 0x0F) << 4; aoqi@0: aoqi@0: _encodingBufferOutputStream.reset(); aoqi@0: ea.encodeToOutputStream(data, _encodingBufferOutputStream); aoqi@0: encodeNonZeroOctetStringLengthOnFifthBit(_encodingBufferIndex); aoqi@0: write(_encodingBuffer, _encodingBufferIndex); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the [normalized value] of an Attribute Information Item using aoqi@0: * using a built in encoding algorithm. aoqi@0: * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param id the built in encoding algorithm identifier. aoqi@0: * @param data the data to be encoded using an encoding algorithm. The data aoqi@0: * represents an array of items specified by the encoding algorithm aoqi@0: * identifier aoqi@0: * @param offset the offset into the array of bytes. aoqi@0: * @param length the length of bytes. aoqi@0: */ aoqi@0: protected final void encodeAIIBuiltInAlgorithmData(int id, Object data, int offset, int length) throws IOException { aoqi@0: // Encode identification and top four bits of encoding algorithm id aoqi@0: write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG | aoqi@0: ((id & 0xF0) >> 4)); aoqi@0: aoqi@0: // Encode bottom 4 bits of enoding algorithm id aoqi@0: _b = (id & 0x0F) << 4; aoqi@0: aoqi@0: final int octetLength = BuiltInEncodingAlgorithmFactory.getAlgorithm(id). aoqi@0: getOctetLengthFromPrimitiveLength(length); aoqi@0: aoqi@0: encodeNonZeroOctetStringLengthOnFifthBit(octetLength); aoqi@0: aoqi@0: ensureSize(octetLength); aoqi@0: BuiltInEncodingAlgorithmFactory.getAlgorithm(id). aoqi@0: encodeToBytes(data, offset, length, _octetBuffer, _octetBufferIndex); aoqi@0: _octetBufferIndex += octetLength; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non identifying string on the third bit of an octet. aoqi@0: * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * @param map the vocabulary table of character arrays to indexes. aoqi@0: * @param addToTable true if the array of characters should be added to the vocabulary aoqi@0: * table (if not already present in the table). aoqi@0: * @param clone true if the array of characters should be cloned if added aoqi@0: * to the vocabulary table. aoqi@0: */ aoqi@0: protected final void encodeNonIdentifyingStringOnThirdBit(char[] ch, int offset, int length, aoqi@0: CharArrayIntMap map, boolean addToTable, boolean clone) throws IOException { aoqi@0: // length cannot be zero since sequence of CIIs has to be > 0 aoqi@0: aoqi@0: if (addToTable) { aoqi@0: // if char array could be added to table aoqi@0: boolean canAddCharacterContentToTable = aoqi@0: canAddCharacterContentToTable(length, map); aoqi@0: aoqi@0: // obtain/get index aoqi@0: int index = canAddCharacterContentToTable ? aoqi@0: map.obtainIndex(ch, offset, length, clone) : aoqi@0: map.get(ch, offset, length); aoqi@0: aoqi@0: if (index != KeyIntMap.NOT_PRESENT) { aoqi@0: // if char array is in table aoqi@0: _b = EncodingConstants.CHARACTER_CHUNK | 0x20; aoqi@0: encodeNonZeroIntegerOnFourthBit(index); aoqi@0: } else if (canAddCharacterContentToTable) { aoqi@0: // if char array is not in table, but could be added aoqi@0: _b = EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG | aoqi@0: _nonIdentifyingStringOnThirdBitCES; aoqi@0: encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length); aoqi@0: } else { aoqi@0: // if char array is not in table and could not be added aoqi@0: _b = _nonIdentifyingStringOnThirdBitCES; aoqi@0: encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length); aoqi@0: } aoqi@0: } else { aoqi@0: // char array will not be added to map aoqi@0: _b = _nonIdentifyingStringOnThirdBitCES; aoqi@0: encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non identifying string on the third bit of an octet as binary aoqi@0: * data using an encoding algorithm. aoqi@0: * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param URI the encoding algorithm URI. If the URI == null then the aoqi@0: * encoding algorithm identifier takes precendence. aoqi@0: * @param id the encoding algorithm identifier. aoqi@0: * @param data the data to be encoded using an encoding algorithm. aoqi@0: * @throws EncodingAlgorithmException if the encoding algorithm URI is not aoqi@0: * present in the vocabulary, or the encoding algorithm identifier aoqi@0: * is not with the required range. aoqi@0: */ aoqi@0: protected final void encodeNonIdentifyingStringOnThirdBit(String URI, int id, Object data) throws FastInfosetException, IOException { aoqi@0: if (URI != null) { aoqi@0: id = _v.encodingAlgorithm.get(URI); aoqi@0: if (id == KeyIntMap.NOT_PRESENT) { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI})); aoqi@0: } aoqi@0: id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START; aoqi@0: aoqi@0: EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI); aoqi@0: if (ea != null) { aoqi@0: encodeCIIObjectAlgorithmData(id, data, ea); aoqi@0: } else { aoqi@0: if (data instanceof byte[]) { aoqi@0: byte[] d = (byte[])data; aoqi@0: encodeCIIOctetAlgorithmData(id, d, 0, d.length); aoqi@0: } else { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI")); aoqi@0: } aoqi@0: } aoqi@0: } else if (id <= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { aoqi@0: int length = 0; aoqi@0: switch(id) { aoqi@0: case EncodingAlgorithmIndexes.HEXADECIMAL: aoqi@0: case EncodingAlgorithmIndexes.BASE64: aoqi@0: length = ((byte[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.SHORT: aoqi@0: length = ((short[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.INT: aoqi@0: length = ((int[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.LONG: aoqi@0: case EncodingAlgorithmIndexes.UUID: aoqi@0: length = ((long[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.BOOLEAN: aoqi@0: length = ((boolean[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.FLOAT: aoqi@0: length = ((float[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.DOUBLE: aoqi@0: length = ((double[])data).length; aoqi@0: break; aoqi@0: case EncodingAlgorithmIndexes.CDATA: aoqi@0: throw new UnsupportedOperationException(CommonResourceBundle.getInstance().getString("message.CDATA")); aoqi@0: default: aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.UnsupportedBuiltInAlgorithm", new Object[]{Integer.valueOf(id)})); aoqi@0: } aoqi@0: encodeCIIBuiltInAlgorithmData(id, data, 0, length); aoqi@0: } else if (id >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { aoqi@0: if (data instanceof byte[]) { aoqi@0: byte[] d = (byte[])data; aoqi@0: encodeCIIOctetAlgorithmData(id, d, 0, d.length); aoqi@0: } else { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI")); aoqi@0: } aoqi@0: } else { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved")); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non identifying string on the third bit of an octet as binary aoqi@0: * data using an encoding algorithm. aoqi@0: * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param URI the encoding algorithm URI. If the URI == null then the aoqi@0: * encoding algorithm identifier takes precendence. aoqi@0: * @param id the encoding algorithm identifier. aoqi@0: * @param d the data, as an array of bytes, to be encoded. aoqi@0: * @param offset the offset into the array of bytes. aoqi@0: * @param length the length of bytes. aoqi@0: * @throws EncodingAlgorithmException if the encoding algorithm URI is not aoqi@0: * present in the vocabulary. aoqi@0: */ aoqi@0: protected final void encodeNonIdentifyingStringOnThirdBit(String URI, int id, byte[] d, int offset, int length) throws FastInfosetException, IOException { aoqi@0: if (URI != null) { aoqi@0: id = _v.encodingAlgorithm.get(URI); aoqi@0: if (id == KeyIntMap.NOT_PRESENT) { aoqi@0: throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI})); aoqi@0: } aoqi@0: id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START; aoqi@0: } aoqi@0: aoqi@0: encodeCIIOctetAlgorithmData(id, d, offset, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a chunk of Character Information Items using aoqi@0: * using an encoding algorithm. aoqi@0: * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param id the encoding algorithm identifier. aoqi@0: * @param d the data, as an array of bytes, to be encoded. aoqi@0: * @param offset the offset into the array of bytes. aoqi@0: * @param length the length of bytes. aoqi@0: */ aoqi@0: protected final void encodeCIIOctetAlgorithmData(int id, byte[] d, int offset, int length) throws IOException { aoqi@0: // Encode identification and top two bits of encoding algorithm id aoqi@0: write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG | aoqi@0: ((id & 0xC0) >> 6)); aoqi@0: aoqi@0: // Encode bottom 6 bits of enoding algorithm id aoqi@0: _b = (id & 0x3F) << 2; aoqi@0: aoqi@0: // Encode the length aoqi@0: encodeNonZeroOctetStringLengthOnSenventhBit(length); aoqi@0: aoqi@0: write(d, offset, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a chunk of Character Information Items using aoqi@0: * using an encoding algorithm. aoqi@0: * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param id the encoding algorithm identifier. aoqi@0: * @param data the data to be encoded using an encoding algorithm. aoqi@0: * @param ea the encoding algorithm to use to encode the data into an aoqi@0: * array of bytes. aoqi@0: */ aoqi@0: protected final void encodeCIIObjectAlgorithmData(int id, Object data, EncodingAlgorithm ea) throws FastInfosetException, IOException { aoqi@0: // Encode identification and top two bits of encoding algorithm id aoqi@0: write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG | aoqi@0: ((id & 0xC0) >> 6)); aoqi@0: aoqi@0: // Encode bottom 6 bits of enoding algorithm id aoqi@0: _b = (id & 0x3F) << 2; aoqi@0: aoqi@0: _encodingBufferOutputStream.reset(); aoqi@0: ea.encodeToOutputStream(data, _encodingBufferOutputStream); aoqi@0: encodeNonZeroOctetStringLengthOnSenventhBit(_encodingBufferIndex); aoqi@0: write(_encodingBuffer, _encodingBufferIndex); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a chunk of Character Information Items using aoqi@0: * using an encoding algorithm. aoqi@0: * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param id the built in encoding algorithm identifier. aoqi@0: * @param data the data to be encoded using an encoding algorithm. The data aoqi@0: * represents an array of items specified by the encoding algorithm aoqi@0: * identifier aoqi@0: * @param offset the offset into the array of bytes. aoqi@0: * @param length the length of bytes. aoqi@0: */ aoqi@0: protected final void encodeCIIBuiltInAlgorithmData(int id, Object data, int offset, int length) throws FastInfosetException, IOException { aoqi@0: // Encode identification and top two bits of encoding algorithm id aoqi@0: write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG | aoqi@0: ((id & 0xC0) >> 6)); aoqi@0: aoqi@0: // Encode bottom 6 bits of enoding algorithm id aoqi@0: _b = (id & 0x3F) << 2; aoqi@0: aoqi@0: final int octetLength = BuiltInEncodingAlgorithmFactory.getAlgorithm(id). aoqi@0: getOctetLengthFromPrimitiveLength(length); aoqi@0: aoqi@0: encodeNonZeroOctetStringLengthOnSenventhBit(octetLength); aoqi@0: aoqi@0: ensureSize(octetLength); aoqi@0: BuiltInEncodingAlgorithmFactory.getAlgorithm(id). aoqi@0: encodeToBytes(data, offset, length, _octetBuffer, _octetBufferIndex); aoqi@0: _octetBufferIndex += octetLength; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a chunk of Character Information Items using aoqi@0: * using the CDATA built in encoding algorithm. aoqi@0: * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: */ aoqi@0: protected final void encodeCIIBuiltInAlgorithmDataAsCDATA(char[] ch, int offset, int length) throws FastInfosetException, IOException { aoqi@0: // Encode identification and top two bits of encoding algorithm id aoqi@0: write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG); aoqi@0: aoqi@0: // Encode bottom 6 bits of enoding algorithm id aoqi@0: _b = EncodingAlgorithmIndexes.CDATA << 2; aoqi@0: aoqi@0: aoqi@0: length = encodeUTF8String(ch, offset, length); aoqi@0: encodeNonZeroOctetStringLengthOnSenventhBit(length); aoqi@0: write(_encodingBuffer, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non empty identifying string on the first bit of an octet. aoqi@0: * Implementation of clause C.13 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param s the identifying string. aoqi@0: * @param map the vocabulary table to use to determin the index of the aoqi@0: * identifying string aoqi@0: */ aoqi@0: protected final void encodeIdentifyingNonEmptyStringOnFirstBit(String s, StringIntMap map) throws IOException { aoqi@0: int index = map.obtainIndex(s); aoqi@0: if (index == KeyIntMap.NOT_PRESENT) { aoqi@0: // _b = 0; aoqi@0: encodeNonEmptyOctetStringOnSecondBit(s); aoqi@0: } else { aoqi@0: // _b = 0x80; aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitOne(index); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non empty string on the second bit of an octet using the UTF-8 aoqi@0: * encoding. aoqi@0: * Implementation of clause C.22 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param s the string. aoqi@0: */ aoqi@0: protected final void encodeNonEmptyOctetStringOnSecondBit(String s) throws IOException { aoqi@0: final int length = encodeUTF8String(s); aoqi@0: encodeNonZeroOctetStringLengthOnSecondBit(length); aoqi@0: write(_encodingBuffer, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the length of a UTF-8 encoded string on the second bit of an octet. aoqi@0: * Implementation of clause C.22 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param length the length to encode. aoqi@0: */ aoqi@0: protected final void encodeNonZeroOctetStringLengthOnSecondBit(int length) throws IOException { aoqi@0: if (length < EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT) { aoqi@0: // [1, 64] aoqi@0: write(length - 1); aoqi@0: } else if (length < EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT) { aoqi@0: // [65, 320] aoqi@0: write(EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_FLAG); // 010 00000 aoqi@0: write(length - EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT); aoqi@0: } else { aoqi@0: // [321, 4294967296] aoqi@0: write(EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_LARGE_FLAG); // 0110 0000 aoqi@0: length -= EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT; aoqi@0: write(length >>> 24); aoqi@0: write((length >> 16) & 0xFF); aoqi@0: write((length >> 8) & 0xFF); aoqi@0: write(length & 0xFF); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non empty string on the fifth bit of an octet using the UTF-8 aoqi@0: * or UTF-16 encoding. aoqi@0: * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param s the string. aoqi@0: */ aoqi@0: protected final void encodeNonEmptyCharacterStringOnFifthBit(String s) throws IOException { aoqi@0: final int length = (_encodingStringsAsUtf8) ? encodeUTF8String(s) : encodeUtf16String(s); aoqi@0: encodeNonZeroOctetStringLengthOnFifthBit(length); aoqi@0: write(_encodingBuffer, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non empty string on the fifth bit of an octet using the UTF-8 aoqi@0: * or UTF-16 encoding. aoqi@0: * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: */ aoqi@0: protected final void encodeNonEmptyCharacterStringOnFifthBit(char[] ch, int offset, int length) throws IOException { aoqi@0: length = (_encodingStringsAsUtf8) ? encodeUTF8String(ch, offset, length) : encodeUtf16String(ch, offset, length); aoqi@0: encodeNonZeroOctetStringLengthOnFifthBit(length); aoqi@0: write(_encodingBuffer, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the length of a UTF-8 or UTF-16 encoded string on the fifth bit aoqi@0: * of an octet. aoqi@0: * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param length the length to encode. aoqi@0: */ aoqi@0: protected final void encodeNonZeroOctetStringLengthOnFifthBit(int length) throws IOException { aoqi@0: if (length < EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT) { aoqi@0: // [1, 8] aoqi@0: write(_b | (length - 1)); aoqi@0: } else if (length < EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT) { aoqi@0: // [9, 264] aoqi@0: write(_b | EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_FLAG); // 000010 00 aoqi@0: write(length - EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT); aoqi@0: } else { aoqi@0: // [265, 4294967296] aoqi@0: write(_b | EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_LARGE_FLAG); // 000011 00 aoqi@0: length -= EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT; aoqi@0: write(length >>> 24); aoqi@0: write((length >> 16) & 0xFF); aoqi@0: write((length >> 8) & 0xFF); aoqi@0: write(length & 0xFF); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non empty string on the seventh bit of an octet using the UTF-8 aoqi@0: * or UTF-16 encoding. aoqi@0: * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: */ aoqi@0: protected final void encodeNonEmptyCharacterStringOnSeventhBit(char[] ch, int offset, int length) throws IOException { aoqi@0: length = (_encodingStringsAsUtf8) ? encodeUTF8String(ch, offset, length) : encodeUtf16String(ch, offset, length); aoqi@0: encodeNonZeroOctetStringLengthOnSenventhBit(length); aoqi@0: write(_encodingBuffer, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non empty string on the seventh bit of an octet using a restricted aoqi@0: * alphabet that results in the encoding of a character in 4 bits aoqi@0: * (or two characters per octet). aoqi@0: * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param table the table mapping characters to 4 bit values. aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: */ aoqi@0: protected final void encodeNonEmptyFourBitCharacterStringOnSeventhBit(int[] table, char[] ch, int offset, int length) throws FastInfosetException, IOException { aoqi@0: final int octetPairLength = length / 2; aoqi@0: final int octetSingleLength = length % 2; aoqi@0: aoqi@0: // Encode the length aoqi@0: encodeNonZeroOctetStringLengthOnSenventhBit(octetPairLength + octetSingleLength); aoqi@0: encodeNonEmptyFourBitCharacterString(table, ch, offset, octetPairLength, octetSingleLength); aoqi@0: } aoqi@0: aoqi@0: protected final void encodeNonEmptyFourBitCharacterString(int[] table, char[] ch, int offset, aoqi@0: int octetPairLength, int octetSingleLength) throws FastInfosetException, IOException { aoqi@0: ensureSize(octetPairLength + octetSingleLength); aoqi@0: // Encode all pairs aoqi@0: int v = 0; aoqi@0: for (int i = 0; i < octetPairLength; i++) { aoqi@0: v = (table[ch[offset++]] << 4) | table[ch[offset++]]; aoqi@0: if (v < 0) { aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange")); aoqi@0: } aoqi@0: _octetBuffer[_octetBufferIndex++] = (byte)v; aoqi@0: } aoqi@0: // Encode single character at end with termination bits aoqi@0: if (octetSingleLength == 1) { aoqi@0: v = (table[ch[offset]] << 4) | 0x0F; aoqi@0: if (v < 0) { aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange")); aoqi@0: } aoqi@0: _octetBuffer[_octetBufferIndex++] = (byte)v; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non empty string on the seventh bit of an octet using a restricted aoqi@0: * alphabet table. aoqi@0: * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param alphabet the alphabet defining the mapping between characters and aoqi@0: * integer values. aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: */ aoqi@0: protected final void encodeNonEmptyNBitCharacterStringOnSeventhBit(String alphabet, char[] ch, int offset, int length) throws FastInfosetException, IOException { aoqi@0: int bitsPerCharacter = 1; aoqi@0: while ((1 << bitsPerCharacter) <= alphabet.length()) { aoqi@0: bitsPerCharacter++; aoqi@0: } aoqi@0: aoqi@0: final int bits = length * bitsPerCharacter; aoqi@0: final int octets = bits / 8; aoqi@0: final int bitsOfLastOctet = bits % 8; aoqi@0: final int totalOctets = octets + ((bitsOfLastOctet > 0) ? 1 : 0); aoqi@0: aoqi@0: // Encode the length aoqi@0: encodeNonZeroOctetStringLengthOnSenventhBit(totalOctets); aoqi@0: aoqi@0: resetBits(); aoqi@0: ensureSize(totalOctets); aoqi@0: int v = 0; aoqi@0: for (int i = 0; i < length; i++) { aoqi@0: final char c = ch[offset + i]; aoqi@0: // This is grotesquely slow, need to use hash table of character to int value aoqi@0: for (v = 0; v < alphabet.length(); v++) { aoqi@0: if (c == alphabet.charAt(v)) { aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: if (v == alphabet.length()) { aoqi@0: throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange")); aoqi@0: } aoqi@0: writeBits(bitsPerCharacter, v); aoqi@0: } aoqi@0: aoqi@0: if (bitsOfLastOctet > 0) { aoqi@0: _b |= (1 << (8 - bitsOfLastOctet)) - 1; aoqi@0: write(_b); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private int _bitsLeftInOctet; aoqi@0: aoqi@0: private final void resetBits() { aoqi@0: _bitsLeftInOctet = 8; aoqi@0: _b = 0; aoqi@0: } aoqi@0: aoqi@0: private final void writeBits(int bits, int v) throws IOException { aoqi@0: while (bits > 0) { aoqi@0: final int bit = (v & (1 << --bits)) > 0 ? 1 : 0; aoqi@0: _b |= bit << (--_bitsLeftInOctet); aoqi@0: if (_bitsLeftInOctet == 0) { aoqi@0: write(_b); aoqi@0: _bitsLeftInOctet = 8; aoqi@0: _b = 0; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the length of a encoded string on the seventh bit aoqi@0: * of an octet. aoqi@0: * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param length the length to encode. aoqi@0: */ aoqi@0: protected final void encodeNonZeroOctetStringLengthOnSenventhBit(int length) throws IOException { aoqi@0: if (length < EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT) { aoqi@0: // [1, 2] aoqi@0: write(_b | (length - 1)); aoqi@0: } else if (length < EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT) { aoqi@0: // [3, 258] aoqi@0: write(_b | EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_FLAG); // 00000010 aoqi@0: write(length - EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT); aoqi@0: } else { aoqi@0: // [259, 4294967296] aoqi@0: write(_b | EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_LARGE_FLAG); // 00000011 aoqi@0: length -= EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT; aoqi@0: write(length >>> 24); aoqi@0: write((length >> 16) & 0xFF); aoqi@0: write((length >> 8) & 0xFF); aoqi@0: write(length & 0xFF); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non zero integer on the second bit of an octet, setting aoqi@0: * the first bit to 1. aoqi@0: * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: *

aoqi@0: * The first bit of the first octet is set, as specified in clause C.13 of aoqi@0: * ITU-T Rec. X.891 | ISO/IEC 24824-1 aoqi@0: * aoqi@0: * @param i The integer to encode, which is a member of the interval aoqi@0: * [0, 1048575]. In the specification the interval is [1, 1048576] aoqi@0: * aoqi@0: */ aoqi@0: protected final void encodeNonZeroIntegerOnSecondBitFirstBitOne(int i) throws IOException { aoqi@0: if (i < EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT) { aoqi@0: // [1, 64] ( [0, 63] ) 6 bits aoqi@0: write(0x80 | i); aoqi@0: } else if (i < EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT) { aoqi@0: // [65, 8256] ( [64, 8255] ) 13 bits aoqi@0: i -= EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT; aoqi@0: _b = (0x80 | EncodingConstants.INTEGER_2ND_BIT_MEDIUM_FLAG) | (i >> 8); // 010 00000 aoqi@0: // _b = 0xC0 | (i >> 8); // 010 00000 aoqi@0: write(_b); aoqi@0: write(i & 0xFF); aoqi@0: } else if (i < EncodingConstants.INTEGER_2ND_BIT_LARGE_LIMIT) { aoqi@0: // [8257, 1048576] ( [8256, 1048575] ) 20 bits aoqi@0: i -= EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT; aoqi@0: _b = (0x80 | EncodingConstants.INTEGER_2ND_BIT_LARGE_FLAG) | (i >> 16); // 0110 0000 aoqi@0: // _b = 0xE0 | (i >> 16); // 0110 0000 aoqi@0: write(_b); aoqi@0: write((i >> 8) & 0xFF); aoqi@0: write(i & 0xFF); aoqi@0: } else { aoqi@0: throw new IOException( aoqi@0: CommonResourceBundle.getInstance().getString("message.integerMaxSize", aoqi@0: new Object[]{Integer.valueOf(EncodingConstants.INTEGER_2ND_BIT_LARGE_LIMIT)})); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non zero integer on the second bit of an octet, setting aoqi@0: * the first bit to 0. aoqi@0: * Implementation of clause C.25 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: *

aoqi@0: * The first bit of the first octet is set, as specified in clause C.13 of aoqi@0: * ITU-T Rec. X.891 | ISO/IEC 24824-1 aoqi@0: * aoqi@0: * @param i The integer to encode, which is a member of the interval aoqi@0: * [0, 1048575]. In the specification the interval is [1, 1048576] aoqi@0: * aoqi@0: */ aoqi@0: protected final void encodeNonZeroIntegerOnSecondBitFirstBitZero(int i) throws IOException { aoqi@0: if (i < EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT) { aoqi@0: // [1, 64] ( [0, 63] ) 6 bits aoqi@0: write(i); aoqi@0: } else if (i < EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT) { aoqi@0: // [65, 8256] ( [64, 8255] ) 13 bits aoqi@0: i -= EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT; aoqi@0: _b = EncodingConstants.INTEGER_2ND_BIT_MEDIUM_FLAG | (i >> 8); // 010 00000 aoqi@0: write(_b); aoqi@0: write(i & 0xFF); aoqi@0: } else { aoqi@0: // [8257, 1048576] ( [8256, 1048575] ) 20 bits aoqi@0: i -= EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT; aoqi@0: _b = EncodingConstants.INTEGER_2ND_BIT_LARGE_FLAG | (i >> 16); // 0110 0000 aoqi@0: write(_b); aoqi@0: write((i >> 8) & 0xFF); aoqi@0: write(i & 0xFF); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non zero integer on the third bit of an octet. aoqi@0: * Implementation of clause C.27 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param i The integer to encode, which is a member of the interval aoqi@0: * [0, 1048575]. In the specification the interval is [1, 1048576] aoqi@0: * aoqi@0: */ aoqi@0: protected final void encodeNonZeroIntegerOnThirdBit(int i) throws IOException { aoqi@0: if (i < EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT) { aoqi@0: // [1, 32] ( [0, 31] ) 5 bits aoqi@0: write(_b | i); aoqi@0: } else if (i < EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT) { aoqi@0: // [33, 2080] ( [32, 2079] ) 11 bits aoqi@0: i -= EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT; aoqi@0: _b |= EncodingConstants.INTEGER_3RD_BIT_MEDIUM_FLAG | (i >> 8); // 00100 000 aoqi@0: write(_b); aoqi@0: write(i & 0xFF); aoqi@0: } else if (i < EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT) { aoqi@0: // [2081, 526368] ( [2080, 526367] ) 19 bits aoqi@0: i -= EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT; aoqi@0: _b |= EncodingConstants.INTEGER_3RD_BIT_LARGE_FLAG | (i >> 16); // 00101 000 aoqi@0: write(_b); aoqi@0: write((i >> 8) & 0xFF); aoqi@0: write(i & 0xFF); aoqi@0: } else { aoqi@0: // [526369, 1048576] ( [526368, 1048575] ) 20 bits aoqi@0: i -= EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT; aoqi@0: _b |= EncodingConstants.INTEGER_3RD_BIT_LARGE_LARGE_FLAG; // 00110 000 aoqi@0: write(_b); aoqi@0: write(i >> 16); aoqi@0: write((i >> 8) & 0xFF); aoqi@0: write(i & 0xFF); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non zero integer on the fourth bit of an octet. aoqi@0: * Implementation of clause C.28 of ITU-T Rec. X.891 | ISO/IEC 24824-1. aoqi@0: * aoqi@0: * @param i The integer to encode, which is a member of the interval aoqi@0: * [0, 1048575]. In the specification the interval is [1, 1048576] aoqi@0: * aoqi@0: */ aoqi@0: protected final void encodeNonZeroIntegerOnFourthBit(int i) throws IOException { aoqi@0: if (i < EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT) { aoqi@0: // [1, 16] ( [0, 15] ) 4 bits aoqi@0: write(_b | i); aoqi@0: } else if (i < EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT) { aoqi@0: // [17, 1040] ( [16, 1039] ) 10 bits aoqi@0: i -= EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT; aoqi@0: _b |= EncodingConstants.INTEGER_4TH_BIT_MEDIUM_FLAG | (i >> 8); // 000 100 00 aoqi@0: write(_b); aoqi@0: write(i & 0xFF); aoqi@0: } else if (i < EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT) { aoqi@0: // [1041, 263184] ( [1040, 263183] ) 18 bits aoqi@0: i -= EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT; aoqi@0: _b |= EncodingConstants.INTEGER_4TH_BIT_LARGE_FLAG | (i >> 16); // 000 101 00 aoqi@0: write(_b); aoqi@0: write((i >> 8) & 0xFF); aoqi@0: write(i & 0xFF); aoqi@0: } else { aoqi@0: // [263185, 1048576] ( [263184, 1048575] ) 20 bits aoqi@0: i -= EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT; aoqi@0: _b |= EncodingConstants.INTEGER_4TH_BIT_LARGE_LARGE_FLAG; // 000 110 00 aoqi@0: write(_b); aoqi@0: write(i >> 16); aoqi@0: write((i >> 8) & 0xFF); aoqi@0: write(i & 0xFF); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non empty string using the UTF-8 encoding. aoqi@0: * aoqi@0: * @param b the current octet that is being written. aoqi@0: * @param s the string to be UTF-8 encoded. aoqi@0: * @param constants the array of constants to use when encoding to determin aoqi@0: * how the length of the UTF-8 encoded string is encoded. aoqi@0: */ aoqi@0: protected final void encodeNonEmptyUTF8StringAsOctetString(int b, String s, int[] constants) throws IOException { aoqi@0: final char[] ch = s.toCharArray(); aoqi@0: encodeNonEmptyUTF8StringAsOctetString(b, ch, 0, ch.length, constants); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non empty string using the UTF-8 encoding. aoqi@0: * aoqi@0: * @param b the current octet that is being written. aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: * how the length of the UTF-8 encoded string is encoded. aoqi@0: * @param constants the array of constants to use when encoding to determin aoqi@0: * how the length of the UTF-8 encoded string is encoded. aoqi@0: */ aoqi@0: protected final void encodeNonEmptyUTF8StringAsOctetString(int b, char ch[], int offset, int length, int[] constants) throws IOException { aoqi@0: length = encodeUTF8String(ch, offset, length); aoqi@0: encodeNonZeroOctetStringLength(b, length, constants); aoqi@0: write(_encodingBuffer, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode the length of non empty UTF-8 encoded string. aoqi@0: * aoqi@0: * @param b the current octet that is being written. aoqi@0: * @param length the length of the UTF-8 encoded string. aoqi@0: * how the length of the UTF-8 encoded string is encoded. aoqi@0: * @param constants the array of constants to use when encoding to determin aoqi@0: * how the length of the UTF-8 encoded string is encoded. aoqi@0: */ aoqi@0: protected final void encodeNonZeroOctetStringLength(int b, int length, int[] constants) throws IOException { aoqi@0: if (length < constants[EncodingConstants.OCTET_STRING_LENGTH_SMALL_LIMIT]) { aoqi@0: write(b | (length - 1)); aoqi@0: } else if (length < constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_LIMIT]) { aoqi@0: write(b | constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_FLAG]); aoqi@0: write(length - constants[EncodingConstants.OCTET_STRING_LENGTH_SMALL_LIMIT]); aoqi@0: } else { aoqi@0: write(b | constants[EncodingConstants.OCTET_STRING_LENGTH_LARGE_FLAG]); aoqi@0: length -= constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_LIMIT]; aoqi@0: write(length >>> 24); aoqi@0: write((length >> 16) & 0xFF); aoqi@0: write((length >> 8) & 0xFF); aoqi@0: write(length & 0xFF); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a non zero integer. aoqi@0: * aoqi@0: * @param b the current octet that is being written. aoqi@0: * @param i the non zero integer. aoqi@0: * @param constants the array of constants to use when encoding to determin aoqi@0: * how the non zero integer is encoded. aoqi@0: */ aoqi@0: protected final void encodeNonZeroInteger(int b, int i, int[] constants) throws IOException { aoqi@0: if (i < constants[EncodingConstants.INTEGER_SMALL_LIMIT]) { aoqi@0: write(b | i); aoqi@0: } else if (i < constants[EncodingConstants.INTEGER_MEDIUM_LIMIT]) { aoqi@0: i -= constants[EncodingConstants.INTEGER_SMALL_LIMIT]; aoqi@0: write(b | constants[EncodingConstants.INTEGER_MEDIUM_FLAG] | (i >> 8)); aoqi@0: write(i & 0xFF); aoqi@0: } else if (i < constants[EncodingConstants.INTEGER_LARGE_LIMIT]) { aoqi@0: i -= constants[EncodingConstants.INTEGER_MEDIUM_LIMIT]; aoqi@0: write(b | constants[EncodingConstants.INTEGER_LARGE_FLAG] | (i >> 16)); aoqi@0: write((i >> 8) & 0xFF); aoqi@0: write(i & 0xFF); aoqi@0: } else if (i < EncodingConstants.INTEGER_MAXIMUM_SIZE) { aoqi@0: i -= constants[EncodingConstants.INTEGER_LARGE_LIMIT]; aoqi@0: write(b | constants[EncodingConstants.INTEGER_LARGE_LARGE_FLAG]); aoqi@0: write(i >> 16); aoqi@0: write((i >> 8) & 0xFF); aoqi@0: write(i & 0xFF); aoqi@0: } else { aoqi@0: throw new IOException(CommonResourceBundle.getInstance().getString("message.integerMaxSize", new Object[]{Integer.valueOf(EncodingConstants.INTEGER_MAXIMUM_SIZE)})); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Mark the current position in the buffered stream. aoqi@0: */ aoqi@0: protected final void mark() { aoqi@0: _markIndex = _octetBufferIndex; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Reset the marked position in the buffered stream. aoqi@0: */ aoqi@0: protected final void resetMark() { aoqi@0: _markIndex = -1; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @return true if the mark has been set, otherwise false if the mark aoqi@0: * has not been set. aoqi@0: */ aoqi@0: protected final boolean hasMark() { aoqi@0: return _markIndex != -1; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Write a byte to the buffered stream. aoqi@0: */ aoqi@0: protected final void write(int i) throws IOException { aoqi@0: if (_octetBufferIndex < _octetBuffer.length) { aoqi@0: _octetBuffer[_octetBufferIndex++] = (byte)i; aoqi@0: } else { aoqi@0: if (_markIndex == -1) { aoqi@0: _s.write(_octetBuffer); aoqi@0: _octetBufferIndex = 1; aoqi@0: _octetBuffer[0] = (byte)i; aoqi@0: } else { aoqi@0: resize(_octetBuffer.length * 3 / 2); aoqi@0: _octetBuffer[_octetBufferIndex++] = (byte)i; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Write an array of bytes to the buffered stream. aoqi@0: * aoqi@0: * @param b the array of bytes. aoqi@0: * @param length the length of bytes. aoqi@0: */ aoqi@0: protected final void write(byte[] b, int length) throws IOException { aoqi@0: write(b, 0, length); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Write an array of bytes to the buffered stream. aoqi@0: * aoqi@0: * @param b the array of bytes. aoqi@0: * @param offset the offset into the array of bytes. aoqi@0: * @param length the length of bytes. aoqi@0: */ aoqi@0: protected final void write(byte[] b, int offset, int length) throws IOException { aoqi@0: if ((_octetBufferIndex + length) < _octetBuffer.length) { aoqi@0: System.arraycopy(b, offset, _octetBuffer, _octetBufferIndex, length); aoqi@0: _octetBufferIndex += length; aoqi@0: } else { aoqi@0: if (_markIndex == -1) { aoqi@0: _s.write(_octetBuffer, 0, _octetBufferIndex); aoqi@0: _s.write(b, offset, length); aoqi@0: _octetBufferIndex = 0; aoqi@0: } else { aoqi@0: resize((_octetBuffer.length + length) * 3 / 2 + 1); aoqi@0: System.arraycopy(b, offset, _octetBuffer, _octetBufferIndex, length); aoqi@0: _octetBufferIndex += length; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void ensureSize(int length) { aoqi@0: if ((_octetBufferIndex + length) > _octetBuffer.length) { aoqi@0: resize((_octetBufferIndex + length) * 3 / 2 + 1); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void resize(int length) { aoqi@0: byte[] b = new byte[length]; aoqi@0: System.arraycopy(_octetBuffer, 0, b, 0, _octetBufferIndex); aoqi@0: _octetBuffer = b; aoqi@0: } aoqi@0: aoqi@0: private void _flush() throws IOException { aoqi@0: if (_octetBufferIndex > 0) { aoqi@0: _s.write(_octetBuffer, 0, _octetBufferIndex); aoqi@0: _octetBufferIndex = 0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: private EncodingBufferOutputStream _encodingBufferOutputStream = new EncodingBufferOutputStream(); aoqi@0: aoqi@0: private byte[] _encodingBuffer = new byte[512]; aoqi@0: aoqi@0: private int _encodingBufferIndex; aoqi@0: aoqi@0: private class EncodingBufferOutputStream extends OutputStream { aoqi@0: aoqi@0: public void write(int b) throws IOException { aoqi@0: if (_encodingBufferIndex < _encodingBuffer.length) { aoqi@0: _encodingBuffer[_encodingBufferIndex++] = (byte)b; aoqi@0: } else { aoqi@0: byte newbuf[] = new byte[Math.max(_encodingBuffer.length << 1, _encodingBufferIndex)]; aoqi@0: System.arraycopy(_encodingBuffer, 0, newbuf, 0, _encodingBufferIndex); aoqi@0: _encodingBuffer = newbuf; aoqi@0: aoqi@0: _encodingBuffer[_encodingBufferIndex++] = (byte)b; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void write(byte b[], int off, int len) throws IOException { aoqi@0: if ((off < 0) || (off > b.length) || (len < 0) || aoqi@0: ((off + len) > b.length) || ((off + len) < 0)) { aoqi@0: throw new IndexOutOfBoundsException(); aoqi@0: } else if (len == 0) { aoqi@0: return; aoqi@0: } aoqi@0: final int newoffset = _encodingBufferIndex + len; aoqi@0: if (newoffset > _encodingBuffer.length) { aoqi@0: byte newbuf[] = new byte[Math.max(_encodingBuffer.length << 1, newoffset)]; aoqi@0: System.arraycopy(_encodingBuffer, 0, newbuf, 0, _encodingBufferIndex); aoqi@0: _encodingBuffer = newbuf; aoqi@0: } aoqi@0: System.arraycopy(b, off, _encodingBuffer, _encodingBufferIndex, len); aoqi@0: _encodingBufferIndex = newoffset; aoqi@0: } aoqi@0: aoqi@0: public int getLength() { aoqi@0: return _encodingBufferIndex; aoqi@0: } aoqi@0: aoqi@0: public void reset() { aoqi@0: _encodingBufferIndex = 0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a string using the UTF-8 encoding. aoqi@0: * aoqi@0: * @param s the string to encode. aoqi@0: */ aoqi@0: protected final int encodeUTF8String(String s) throws IOException { aoqi@0: final int length = s.length(); aoqi@0: if (length < _charBuffer.length) { aoqi@0: s.getChars(0, length, _charBuffer, 0); aoqi@0: return encodeUTF8String(_charBuffer, 0, length); aoqi@0: } else { aoqi@0: char[] ch = s.toCharArray(); aoqi@0: return encodeUTF8String(ch, 0, length); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void ensureEncodingBufferSizeForUtf8String(int length) { aoqi@0: final int newLength = 4 * length; aoqi@0: if (_encodingBuffer.length < newLength) { aoqi@0: _encodingBuffer = new byte[newLength]; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a string using the UTF-8 encoding. aoqi@0: * aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: */ aoqi@0: protected final int encodeUTF8String(char[] ch, int offset, int length) throws IOException { aoqi@0: int bpos = 0; aoqi@0: aoqi@0: // Make sure buffer is large enough aoqi@0: ensureEncodingBufferSizeForUtf8String(length); aoqi@0: aoqi@0: final int end = offset + length; aoqi@0: int c; aoqi@0: while (end != offset) { aoqi@0: c = ch[offset++]; aoqi@0: if (c < 0x80) { aoqi@0: // 1 byte, 7 bits aoqi@0: _encodingBuffer[bpos++] = (byte) c; aoqi@0: } else if (c < 0x800) { aoqi@0: // 2 bytes, 11 bits aoqi@0: _encodingBuffer[bpos++] = aoqi@0: (byte) (0xC0 | (c >> 6)); // first 5 aoqi@0: _encodingBuffer[bpos++] = aoqi@0: (byte) (0x80 | (c & 0x3F)); // second 6 aoqi@0: } else if (c <= '\uFFFF') { aoqi@0: if (!XMLChar.isHighSurrogate(c) && !XMLChar.isLowSurrogate(c)) { aoqi@0: // 3 bytes, 16 bits aoqi@0: _encodingBuffer[bpos++] = aoqi@0: (byte) (0xE0 | (c >> 12)); // first 4 aoqi@0: _encodingBuffer[bpos++] = aoqi@0: (byte) (0x80 | ((c >> 6) & 0x3F)); // second 6 aoqi@0: _encodingBuffer[bpos++] = aoqi@0: (byte) (0x80 | (c & 0x3F)); // third 6 aoqi@0: } else { aoqi@0: // 4 bytes, high and low surrogate aoqi@0: encodeCharacterAsUtf8FourByte(c, ch, offset, end, bpos); aoqi@0: bpos += 4; aoqi@0: offset++; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return bpos; aoqi@0: } aoqi@0: aoqi@0: private void encodeCharacterAsUtf8FourByte(int c, char[] ch, int chpos, int chend, int bpos) throws IOException { aoqi@0: if (chpos == chend) { aoqi@0: throw new IOException(""); aoqi@0: } aoqi@0: aoqi@0: final char d = ch[chpos]; aoqi@0: if (!XMLChar.isLowSurrogate(d)) { aoqi@0: throw new IOException(""); aoqi@0: } aoqi@0: aoqi@0: final int uc = (((c & 0x3ff) << 10) | (d & 0x3ff)) + 0x10000; aoqi@0: if (uc < 0 || uc >= 0x200000) { aoqi@0: throw new IOException(""); aoqi@0: } aoqi@0: aoqi@0: _encodingBuffer[bpos++] = (byte)(0xF0 | ((uc >> 18))); aoqi@0: _encodingBuffer[bpos++] = (byte)(0x80 | ((uc >> 12) & 0x3F)); aoqi@0: _encodingBuffer[bpos++] = (byte)(0x80 | ((uc >> 6) & 0x3F)); aoqi@0: _encodingBuffer[bpos++] = (byte)(0x80 | (uc & 0x3F)); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a string using the UTF-16 encoding. aoqi@0: * aoqi@0: * @param s the string to encode. aoqi@0: */ aoqi@0: protected final int encodeUtf16String(String s) throws IOException { aoqi@0: final int length = s.length(); aoqi@0: if (length < _charBuffer.length) { aoqi@0: s.getChars(0, length, _charBuffer, 0); aoqi@0: return encodeUtf16String(_charBuffer, 0, length); aoqi@0: } else { aoqi@0: char[] ch = s.toCharArray(); aoqi@0: return encodeUtf16String(ch, 0, length); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void ensureEncodingBufferSizeForUtf16String(int length) { aoqi@0: final int newLength = 2 * length; aoqi@0: if (_encodingBuffer.length < newLength) { aoqi@0: _encodingBuffer = new byte[newLength]; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Encode a string using the UTF-16 encoding. aoqi@0: * aoqi@0: * @param ch the array of characters. aoqi@0: * @param offset the offset into the array of characters. aoqi@0: * @param length the length of characters. aoqi@0: */ aoqi@0: protected final int encodeUtf16String(char[] ch, int offset, int length) throws IOException { aoqi@0: int byteLength = 0; aoqi@0: aoqi@0: // Make sure buffer is large enough aoqi@0: ensureEncodingBufferSizeForUtf16String(length); aoqi@0: aoqi@0: final int n = offset + length; aoqi@0: for (int i = offset; i < n; i++) { aoqi@0: final int c = (int) ch[i]; aoqi@0: _encodingBuffer[byteLength++] = (byte)(c >> 8); aoqi@0: _encodingBuffer[byteLength++] = (byte)(c & 0xFF); aoqi@0: } aoqi@0: aoqi@0: return byteLength; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Obtain the prefix from a qualified name. aoqi@0: * aoqi@0: * @param qName the qualified name aoqi@0: * @return the prefix, or "" if there is no prefix. aoqi@0: */ aoqi@0: public static String getPrefixFromQualifiedName(String qName) { aoqi@0: int i = qName.indexOf(':'); aoqi@0: String prefix = ""; aoqi@0: if (i != -1) { aoqi@0: prefix = qName.substring(0, i); aoqi@0: } aoqi@0: return prefix; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Check if character array contains characters that are all white space. aoqi@0: * aoqi@0: * @param ch the character array aoqi@0: * @param start the starting character index into the array to check from aoqi@0: * @param length the number of characters to check aoqi@0: * @return true if all characters are white space, false otherwise aoqi@0: */ aoqi@0: public static boolean isWhiteSpace(final char[] ch, int start, final int length) { aoqi@0: if (!XMLChar.isSpace(ch[start])) return false; aoqi@0: aoqi@0: final int end = start + length; aoqi@0: while(++start < end && XMLChar.isSpace(ch[start])); aoqi@0: aoqi@0: return start == end; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Check if a String contains characters that are all white space. aoqi@0: * aoqi@0: * @param s the string aoqi@0: * @return true if all characters are white space, false otherwise aoqi@0: */ aoqi@0: public static boolean isWhiteSpace(String s) { aoqi@0: if (!XMLChar.isSpace(s.charAt(0))) return false; aoqi@0: aoqi@0: final int end = s.length(); aoqi@0: int start = 1; aoqi@0: while(start < end && XMLChar.isSpace(s.charAt(start++))); aoqi@0: return start == end; aoqi@0: } aoqi@0: }