| /* |
| * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC. |
| */ |
| |
| package com.sun.xml.internal.fastinfoset; |
| |
| import com.sun.xml.internal.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory; |
| import com.sun.xml.internal.fastinfoset.org.apache.xerces.util.XMLChar; |
| import com.sun.xml.internal.fastinfoset.util.CharArrayIntMap; |
| import com.sun.xml.internal.fastinfoset.util.KeyIntMap; |
| import com.sun.xml.internal.fastinfoset.util.LocalNameQualifiedNamesMap; |
| import com.sun.xml.internal.fastinfoset.util.StringIntMap; |
| import com.sun.xml.internal.fastinfoset.vocab.SerializerVocabulary; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.util.HashMap; |
| import java.util.Map; |
| import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm; |
| import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmException; |
| import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes; |
| import com.sun.xml.internal.org.jvnet.fastinfoset.ExternalVocabulary; |
| import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException; |
| import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetSerializer; |
| import com.sun.xml.internal.org.jvnet.fastinfoset.RestrictedAlphabet; |
| import com.sun.xml.internal.org.jvnet.fastinfoset.VocabularyApplicationData; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| /** |
| * Abstract encoder for developing concrete encoders. |
| * |
| * Concrete implementations extending Encoder will utilize methods on Encoder |
| * to encode XML infoset according to the Fast Infoset standard. It is the |
| * responsibility of the concrete implementation to ensure that methods are |
| * invoked in the correct order to produce a valid fast infoset document. |
| * |
| * <p> |
| * This class extends org.sax.xml.DefaultHandler so that concrete SAX |
| * implementations can be used with javax.xml.parsers.SAXParser and the parse |
| * methods that take org.sax.xml.DefaultHandler as a parameter. |
| * |
| * <p> |
| * Buffering of octets that are written to an {@link java.io.OutputStream} is |
| * supported in a similar manner to a {@link java.io.BufferedOutputStream}. |
| * Combining buffering with encoding enables better performance. |
| * |
| * <p> |
| * More than one fast infoset document may be encoded to the |
| * {@link java.io.OutputStream}. |
| * |
| */ |
| public abstract class Encoder extends DefaultHandler implements FastInfosetSerializer { |
| |
| /** |
| * Character encoding scheme system property for the encoding |
| * of content and attribute values. |
| */ |
| public static final String CHARACTER_ENCODING_SCHEME_SYSTEM_PROPERTY = |
| "com.sun.xml.internal.fastinfoset.serializer.character-encoding-scheme"; |
| |
| /** |
| * Default character encoding scheme system property for the encoding |
| * of content and attribute values. |
| */ |
| protected static final String _characterEncodingSchemeSystemDefault = getDefaultEncodingScheme(); |
| |
| private static String getDefaultEncodingScheme() { |
| String p = System.getProperty(CHARACTER_ENCODING_SCHEME_SYSTEM_PROPERTY, |
| UTF_8); |
| if (p.equals(UTF_16BE)) { |
| return UTF_16BE; |
| } else { |
| return UTF_8; |
| } |
| } |
| |
| private static int[] NUMERIC_CHARACTERS_TABLE; |
| |
| private static int[] DATE_TIME_CHARACTERS_TABLE; |
| |
| static { |
| NUMERIC_CHARACTERS_TABLE = new int[maxCharacter(RestrictedAlphabet.NUMERIC_CHARACTERS) + 1]; |
| DATE_TIME_CHARACTERS_TABLE = new int[maxCharacter(RestrictedAlphabet.DATE_TIME_CHARACTERS) + 1]; |
| |
| for (int i = 0; i < NUMERIC_CHARACTERS_TABLE.length ; i++) { |
| NUMERIC_CHARACTERS_TABLE[i] = -1; |
| } |
| for (int i = 0; i < DATE_TIME_CHARACTERS_TABLE.length ; i++) { |
| DATE_TIME_CHARACTERS_TABLE[i] = -1; |
| } |
| |
| for (int i = 0; i < RestrictedAlphabet.NUMERIC_CHARACTERS.length() ; i++) { |
| NUMERIC_CHARACTERS_TABLE[RestrictedAlphabet.NUMERIC_CHARACTERS.charAt(i)] = i; |
| } |
| for (int i = 0; i < RestrictedAlphabet.DATE_TIME_CHARACTERS.length() ; i++) { |
| DATE_TIME_CHARACTERS_TABLE[RestrictedAlphabet.DATE_TIME_CHARACTERS.charAt(i)] = i; |
| } |
| } |
| |
| private static int maxCharacter(String alphabet) { |
| int c = 0; |
| for (int i = 0; i < alphabet.length() ; i++) { |
| if (c < alphabet.charAt(i)) { |
| c = alphabet.charAt(i); |
| } |
| } |
| |
| return c; |
| } |
| |
| /** |
| * True if DTD and internal subset shall be ignored. |
| */ |
| private boolean _ignoreDTD; |
| |
| /** |
| * True if comments shall be ignored. |
| */ |
| private boolean _ignoreComments; |
| |
| /** |
| * True if procesing instructions shall be ignored. |
| */ |
| private boolean _ignoreProcessingInstructions; |
| |
| /** |
| * True if white space characters for text content shall be ignored. |
| */ |
| private boolean _ignoreWhiteSpaceTextContent; |
| |
| /** |
| * True, if the local name string is used as the key to find the |
| * associated set of qualified names. |
| * <p> |
| * False, if the <prefix>:<local name> string is used as the key |
| * to find the associated set of qualified names. |
| */ |
| private boolean _useLocalNameAsKeyForQualifiedNameLookup; |
| |
| /** |
| * True if strings for text content and attribute values will be |
| * UTF-8 encoded otherwise they will be UTF-16 encoded. |
| */ |
| private boolean _encodingStringsAsUtf8 = true; |
| |
| /** |
| * Encoding constant generated from the string encoding. |
| */ |
| private int _nonIdentifyingStringOnThirdBitCES; |
| |
| /** |
| * Encoding constant generated from the string encoding. |
| */ |
| private int _nonIdentifyingStringOnFirstBitCES; |
| |
| /** |
| * The map of URIs to algorithms. |
| */ |
| private Map _registeredEncodingAlgorithms = new HashMap(); |
| |
| /** |
| * The vocabulary that is used by the encoder |
| */ |
| protected SerializerVocabulary _v; |
| |
| /** |
| * The vocabulary application data that is used by the encoder |
| */ |
| protected VocabularyApplicationData _vData; |
| |
| /** |
| * True if the vocubulary is internal to the encoder |
| */ |
| private boolean _vIsInternal; |
| |
| /** |
| * True if terminatation of an information item is required |
| */ |
| protected boolean _terminate = false; |
| |
| /** |
| * The current octet that is to be written. |
| */ |
| protected int _b; |
| |
| /** |
| * The {@link java.io.OutputStream} that the encoded XML infoset (the |
| * fast infoset document) is written to. |
| */ |
| protected OutputStream _s; |
| |
| /** |
| * The internal buffer of characters used for the UTF-8 or UTF-16 encoding |
| * of characters. |
| */ |
| protected char[] _charBuffer = new char[512]; |
| |
| /** |
| * The internal buffer of bytes. |
| */ |
| protected byte[] _octetBuffer = new byte[1024]; |
| |
| /** |
| * The current position in the internal buffer. |
| */ |
| protected int _octetBufferIndex; |
| |
| /** |
| * The current mark in the internal buffer. |
| * |
| * <p> |
| * If the value of the mark is < 0 then the mark is not set. |
| */ |
| protected int _markIndex = -1; |
| |
| /** |
| * The minimum size of [normalized value] of Attribute Information |
| * Items that will be indexed. |
| */ |
| protected int minAttributeValueSize = FastInfosetSerializer.MIN_ATTRIBUTE_VALUE_SIZE; |
| |
| /** |
| * The maximum size of [normalized value] of Attribute Information |
| * Items that will be indexed. |
| */ |
| protected int maxAttributeValueSize = FastInfosetSerializer.MAX_ATTRIBUTE_VALUE_SIZE; |
| |
| /** |
| * The limit on the size of indexed Map for attribute values |
| * Limit is measured in characters number |
| */ |
| protected int attributeValueMapTotalCharactersConstraint = FastInfosetSerializer.ATTRIBUTE_VALUE_MAP_MEMORY_CONSTRAINT / 2; |
| |
| /** |
| * The minimum size of character content chunks |
| * of Character Information Items or Comment Information Items that |
| * will be indexed. |
| */ |
| protected int minCharacterContentChunkSize = FastInfosetSerializer.MIN_CHARACTER_CONTENT_CHUNK_SIZE; |
| |
| /** |
| * The maximum size of character content chunks |
| * of Character Information Items or Comment Information Items that |
| * will be indexed. |
| */ |
| protected int maxCharacterContentChunkSize = FastInfosetSerializer.MAX_CHARACTER_CONTENT_CHUNK_SIZE; |
| |
| /** |
| * The limit on the size of indexed Map for character content chunks |
| * Limit is measured in characters number |
| */ |
| protected int characterContentChunkMapTotalCharactersConstraint = FastInfosetSerializer.CHARACTER_CONTENT_CHUNK_MAP_MEMORY_CONSTRAINT / 2; |
| |
| /** |
| * Default constructor for the Encoder. |
| */ |
| protected Encoder() { |
| setCharacterEncodingScheme(_characterEncodingSchemeSystemDefault); |
| } |
| |
| protected Encoder(boolean useLocalNameAsKeyForQualifiedNameLookup) { |
| setCharacterEncodingScheme(_characterEncodingSchemeSystemDefault); |
| _useLocalNameAsKeyForQualifiedNameLookup = useLocalNameAsKeyForQualifiedNameLookup; |
| } |
| |
| |
| // FastInfosetSerializer interface |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public final void setIgnoreDTD(boolean ignoreDTD) { |
| _ignoreDTD = ignoreDTD; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public final boolean getIgnoreDTD() { |
| return _ignoreDTD; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public final void setIgnoreComments(boolean ignoreComments) { |
| _ignoreComments = ignoreComments; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public final boolean getIgnoreComments() { |
| return _ignoreComments; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public final void setIgnoreProcesingInstructions(boolean |
| ignoreProcesingInstructions) { |
| _ignoreProcessingInstructions = ignoreProcesingInstructions; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public final boolean getIgnoreProcesingInstructions() { |
| return _ignoreProcessingInstructions; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public final void setIgnoreWhiteSpaceTextContent(boolean ignoreWhiteSpaceTextContent) { |
| _ignoreWhiteSpaceTextContent = ignoreWhiteSpaceTextContent; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public final boolean getIgnoreWhiteSpaceTextContent() { |
| return _ignoreWhiteSpaceTextContent; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setCharacterEncodingScheme(String characterEncodingScheme) { |
| if (characterEncodingScheme.equals(UTF_16BE)) { |
| _encodingStringsAsUtf8 = false; |
| _nonIdentifyingStringOnThirdBitCES = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_UTF_16_FLAG; |
| _nonIdentifyingStringOnFirstBitCES = EncodingConstants.NISTRING_UTF_16_FLAG; |
| } else { |
| _encodingStringsAsUtf8 = true; |
| _nonIdentifyingStringOnThirdBitCES = EncodingConstants.CHARACTER_CHUNK; |
| _nonIdentifyingStringOnFirstBitCES = 0; |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public String getCharacterEncodingScheme() { |
| return (_encodingStringsAsUtf8) ? UTF_8 : UTF_16BE; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setRegisteredEncodingAlgorithms(Map algorithms) { |
| _registeredEncodingAlgorithms = algorithms; |
| if (_registeredEncodingAlgorithms == null) { |
| _registeredEncodingAlgorithms = new HashMap(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Map getRegisteredEncodingAlgorithms() { |
| return _registeredEncodingAlgorithms; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int getMinCharacterContentChunkSize() { |
| return minCharacterContentChunkSize; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setMinCharacterContentChunkSize(int size) { |
| if (size < 0 ) { |
| size = 0; |
| } |
| |
| minCharacterContentChunkSize = size; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int getMaxCharacterContentChunkSize() { |
| return maxCharacterContentChunkSize; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setMaxCharacterContentChunkSize(int size) { |
| if (size < 0 ) { |
| size = 0; |
| } |
| |
| maxCharacterContentChunkSize = size; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int getCharacterContentChunkMapMemoryLimit() { |
| return characterContentChunkMapTotalCharactersConstraint * 2; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setCharacterContentChunkMapMemoryLimit(int size) { |
| if (size < 0 ) { |
| size = 0; |
| } |
| |
| characterContentChunkMapTotalCharactersConstraint = size / 2; |
| } |
| |
| /** |
| * Checks whether character content chunk (its length) matches length limit |
| * |
| * @param length the length of character content chunk is checking to be added to Map. |
| * @return whether character content chunk length matches limit |
| */ |
| public boolean isCharacterContentChunkLengthMatchesLimit(int length) { |
| return length >= minCharacterContentChunkSize && |
| length < maxCharacterContentChunkSize; |
| } |
| |
| /** |
| * Checks whether character content table has enough memory to |
| * store character content chunk with the given length |
| * |
| * @param length the length of character content chunk is checking to be added to Map. |
| * @param map the custom CharArrayIntMap, which memory limits will be checked. |
| * @return whether character content map has enough memory |
| */ |
| public boolean canAddCharacterContentToTable(int length, CharArrayIntMap map) { |
| return map.getTotalCharacterCount() + length < |
| characterContentChunkMapTotalCharactersConstraint; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int getMinAttributeValueSize() { |
| return minAttributeValueSize; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setMinAttributeValueSize(int size) { |
| if (size < 0 ) { |
| size = 0; |
| } |
| |
| minAttributeValueSize = size; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int getMaxAttributeValueSize() { |
| return maxAttributeValueSize; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setMaxAttributeValueSize(int size) { |
| if (size < 0 ) { |
| size = 0; |
| } |
| |
| maxAttributeValueSize = size; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setAttributeValueMapMemoryLimit(int size) { |
| if (size < 0 ) { |
| size = 0; |
| } |
| |
| attributeValueMapTotalCharactersConstraint = size / 2; |
| |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int getAttributeValueMapMemoryLimit() { |
| return attributeValueMapTotalCharactersConstraint * 2; |
| } |
| |
| /** |
| * Checks whether attribute value (its length) matches length limit |
| * |
| * @param length the length of attribute |
| * @return whether attribute value matches limit |
| */ |
| public boolean isAttributeValueLengthMatchesLimit(int length) { |
| return length >= minAttributeValueSize && |
| length < maxAttributeValueSize; |
| } |
| |
| /** |
| * Checks whether attribute table has enough memory to |
| * store attribute value with the given length |
| * |
| * @param length the length of attribute value is checking to be added to Map. |
| * @return whether attribute map has enough memory |
| */ |
| public boolean canAddAttributeToTable(int length) { |
| return _v.attributeValue.getTotalCharacterCount() + length < |
| attributeValueMapTotalCharactersConstraint; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setExternalVocabulary(ExternalVocabulary v) { |
| // Create internal serializer vocabulary |
| _v = new SerializerVocabulary(); |
| // Set the external vocabulary |
| SerializerVocabulary ev = new SerializerVocabulary(v.vocabulary, |
| _useLocalNameAsKeyForQualifiedNameLookup); |
| _v.setExternalVocabulary(v.URI, |
| ev, false); |
| |
| _vIsInternal = true; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setVocabularyApplicationData(VocabularyApplicationData data) { |
| _vData = data; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public VocabularyApplicationData getVocabularyApplicationData() { |
| return _vData; |
| } |
| |
| // End of FastInfosetSerializer interface |
| |
| /** |
| * Reset the encoder for reuse encoding another XML infoset. |
| */ |
| public void reset() { |
| _terminate = false; |
| } |
| |
| /** |
| * Set the OutputStream to encode the XML infoset to a |
| * fast infoset document. |
| * |
| * @param s the OutputStream where the fast infoset document is written to. |
| */ |
| public void setOutputStream(OutputStream s) { |
| _octetBufferIndex = 0; |
| _markIndex = -1; |
| _s = s; |
| } |
| |
| /** |
| * Set the SerializerVocabulary to be used for encoding. |
| * |
| * @param vocabulary the vocabulary to be used for encoding. |
| */ |
| public void setVocabulary(SerializerVocabulary vocabulary) { |
| _v = vocabulary; |
| _vIsInternal = false; |
| } |
| |
| /** |
| * Encode the header of a fast infoset document. |
| * |
| * @param encodeXmlDecl true if the XML declaration should be encoded. |
| */ |
| protected final void encodeHeader(boolean encodeXmlDecl) throws IOException { |
| if (encodeXmlDecl) { |
| _s.write(EncodingConstants.XML_DECLARATION_VALUES[0]); |
| } |
| _s.write(EncodingConstants.BINARY_HEADER); |
| } |
| |
| /** |
| * Encode the initial vocabulary of a fast infoset document. |
| * |
| */ |
| protected final void encodeInitialVocabulary() throws IOException { |
| if (_v == null) { |
| _v = new SerializerVocabulary(); |
| _vIsInternal = true; |
| } else if (_vIsInternal) { |
| _v.clear(); |
| if (_vData != null) |
| _vData.clear(); |
| } |
| |
| if (!_v.hasInitialVocabulary() && !_v.hasExternalVocabulary()) { |
| write(0); |
| } else if (_v.hasInitialVocabulary()) { |
| _b = EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG; |
| write(_b); |
| |
| SerializerVocabulary initialVocabulary = _v.getReadOnlyVocabulary(); |
| |
| // TODO check for contents of vocabulary to assign bits |
| if (initialVocabulary.hasExternalVocabulary()) { |
| _b = EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG; |
| write(_b); |
| write(0); |
| } |
| |
| if (initialVocabulary.hasExternalVocabulary()) { |
| encodeNonEmptyOctetStringOnSecondBit(_v.getExternalVocabularyURI()); |
| } |
| |
| // TODO check for contents of vocabulary to encode values |
| } else if (_v.hasExternalVocabulary()) { |
| _b = EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG; |
| write(_b); |
| |
| _b = EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG; |
| write(_b); |
| write(0); |
| |
| encodeNonEmptyOctetStringOnSecondBit(_v.getExternalVocabularyURI()); |
| } |
| } |
| |
| /** |
| * Encode the termination of the Document Information Item. |
| * |
| */ |
| protected final void encodeDocumentTermination() throws IOException { |
| encodeElementTermination(); |
| encodeTermination(); |
| _flush(); |
| _s.flush(); |
| } |
| |
| /** |
| * Encode the termination of an Element Information Item. |
| * |
| */ |
| protected final void encodeElementTermination() throws IOException { |
| _terminate = true; |
| switch (_b) { |
| case EncodingConstants.TERMINATOR: |
| _b = EncodingConstants.DOUBLE_TERMINATOR; |
| break; |
| case EncodingConstants.DOUBLE_TERMINATOR: |
| write(EncodingConstants.DOUBLE_TERMINATOR); |
| default: |
| _b = EncodingConstants.TERMINATOR; |
| } |
| } |
| |
| /** |
| * Encode a termination if required. |
| * |
| */ |
| protected final void encodeTermination() throws IOException { |
| if (_terminate) { |
| write(_b); |
| _b = 0; |
| _terminate = false; |
| } |
| } |
| |
| /** |
| * Encode a Attribute Information Item that is a namespace declaration. |
| * |
| * @param prefix the prefix of the namespace declaration, |
| * if "" then there is no prefix for the namespace declaration. |
| * @param uri the URI of the namespace declaration, |
| * if "" then there is no URI for the namespace declaration. |
| */ |
| protected final void encodeNamespaceAttribute(String prefix, String uri) throws IOException { |
| _b = EncodingConstants.NAMESPACE_ATTRIBUTE; |
| if (prefix.length() > 0) { |
| _b |= EncodingConstants.NAMESPACE_ATTRIBUTE_PREFIX_FLAG; |
| } |
| if (uri.length() > 0) { |
| _b |= EncodingConstants.NAMESPACE_ATTRIBUTE_NAME_FLAG; |
| } |
| |
| // NOTE a prefix with out a namespace name is an undeclaration |
| // of the namespace bound to the prefix |
| // TODO needs to investigate how the startPrefixMapping works in |
| // relation to undeclaration |
| |
| write(_b); |
| |
| if (prefix.length() > 0) { |
| encodeIdentifyingNonEmptyStringOnFirstBit(prefix, _v.prefix); |
| } |
| if (uri.length() > 0) { |
| encodeIdentifyingNonEmptyStringOnFirstBit(uri, _v.namespaceName); |
| } |
| } |
| |
| /** |
| * Encode a chunk of Character Information Items. |
| * |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * @throws ArrayIndexOutOfBoundsException. |
| */ |
| protected final void encodeCharacters(char[] ch, int offset, int length) throws IOException { |
| final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); |
| encodeNonIdentifyingStringOnThirdBit(ch, offset, length, _v.characterContentChunk, addToTable, true); |
| } |
| |
| /** |
| * Encode a chunk of Character Information Items. |
| * |
| * If the array of characters is to be indexed (as determined by |
| * {@link Encoder#characterContentChunkSizeContraint}) then the array is not cloned |
| * when adding the array to the vocabulary. |
| * |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * @throws ArrayIndexOutOfBoundsException. |
| */ |
| protected final void encodeCharactersNoClone(char[] ch, int offset, int length) throws IOException { |
| final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); |
| encodeNonIdentifyingStringOnThirdBit(ch, offset, length, _v.characterContentChunk, addToTable, false); |
| } |
| |
| /** |
| * Encode a chunk of Character Information Items using a numeric |
| * alphabet that results in the encoding of a character in 4 bits |
| * (or two characters per octet). |
| * |
| * @param id the restricted alphabet identifier. |
| * @param table the table mapping characters to 4 bit values. |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * @param addToTable if characters should be added to table. |
| * @throws ArrayIndexOutOfBoundsException. |
| */ |
| protected final void encodeNumericFourBitCharacters(char[] ch, int offset, int length, |
| boolean addToTable) throws FastInfosetException, IOException { |
| encodeFourBitCharacters(RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX, |
| NUMERIC_CHARACTERS_TABLE, ch, offset, length, addToTable); |
| } |
| |
| /** |
| * Encode a chunk of Character Information Items using a date-time |
| * alphabet that results in the encoding of a character in 4 bits |
| * (or two characters per octet). |
| * |
| * @param id the restricted alphabet identifier. |
| * @param table the table mapping characters to 4 bit values. |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * @param addToTable if characters should be added to table. |
| * @throws ArrayIndexOutOfBoundsException. |
| */ |
| protected final void encodeDateTimeFourBitCharacters(char[] ch, int offset, int length, |
| boolean addToTable) throws FastInfosetException, IOException { |
| encodeFourBitCharacters(RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX, |
| DATE_TIME_CHARACTERS_TABLE, ch, offset, length, addToTable); |
| } |
| |
| /** |
| * Encode a chunk of Character Information Items using a restricted |
| * alphabet that results in the encoding of a character in 4 bits |
| * (or two characters per octet). |
| * |
| * @param id the restricted alphabet identifier. |
| * @param table the table mapping characters to 4 bit values. |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * @param addToTable if characters should be added to table. |
| * @throws ArrayIndexOutOfBoundsException. |
| */ |
| protected final void encodeFourBitCharacters(int id, int[] table, char[] ch, int offset, int length, |
| boolean addToTable) throws FastInfosetException, IOException { |
| if (addToTable) { |
| // if char array could be added to table |
| boolean canAddCharacterContentToTable = |
| canAddCharacterContentToTable(length, _v.characterContentChunk); |
| |
| // obtain/get index |
| int index = canAddCharacterContentToTable ? |
| _v.characterContentChunk.obtainIndex(ch, offset, length, true) : |
| _v.characterContentChunk.get(ch, offset, length); |
| |
| if (index != KeyIntMap.NOT_PRESENT) { |
| // if char array is in table |
| _b = EncodingConstants.CHARACTER_CHUNK | 0x20; |
| encodeNonZeroIntegerOnFourthBit(index); |
| return; |
| } else if (canAddCharacterContentToTable) { |
| // if char array is not in table, but could be added |
| _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG | EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG; |
| } else { |
| // if char array is not in table and could not be added |
| _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG; |
| } |
| } else { |
| _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG; |
| } |
| |
| write (_b); |
| |
| // Encode bottom 6 bits of enoding algorithm id |
| _b = id << 2; |
| |
| encodeNonEmptyFourBitCharacterStringOnSeventhBit(table, ch, offset, length); |
| } |
| |
| /** |
| * Encode a chunk of Character Information Items using a restricted |
| * alphabet table. |
| * |
| * @param alphabet the alphabet defining the mapping between characters and |
| * integer values. |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * @param addToTable if characters should be added to table |
| * @throws ArrayIndexOutOfBoundsException. |
| * @throws FastInfosetException if the alphabet is not present in the |
| * vocabulary. |
| */ |
| protected final void encodeAlphabetCharacters(String alphabet, char[] ch, int offset, int length, |
| boolean addToTable) throws FastInfosetException, IOException { |
| if (addToTable) { |
| // if char array could be added to table |
| boolean canAddCharacterContentToTable = |
| canAddCharacterContentToTable(length, _v.characterContentChunk); |
| |
| // obtain/get index |
| int index = canAddCharacterContentToTable ? |
| _v.characterContentChunk.obtainIndex(ch, offset, length, true) : |
| _v.characterContentChunk.get(ch, offset, length); |
| |
| if (index != KeyIntMap.NOT_PRESENT) { |
| // if char array is in table |
| _b = EncodingConstants.CHARACTER_CHUNK | 0x20; |
| encodeNonZeroIntegerOnFourthBit(index); |
| return; |
| } else if (canAddCharacterContentToTable) { |
| // if char array is not in table, but could be added |
| _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG | EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG; |
| } else { |
| // if char array is not in table and could not be added |
| _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG; |
| } |
| } else { |
| _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG; |
| } |
| |
| int id = _v.restrictedAlphabet.get(alphabet); |
| if (id == KeyIntMap.NOT_PRESENT) { |
| throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.restrictedAlphabetNotPresent")); |
| } |
| id += EncodingConstants.RESTRICTED_ALPHABET_APPLICATION_START; |
| |
| _b |= (id & 0xC0) >> 6; |
| write(_b); |
| |
| // Encode bottom 6 bits of enoding algorithm id |
| _b = (id & 0x3F) << 2; |
| |
| encodeNonEmptyNBitCharacterStringOnSeventhBit(alphabet, ch, offset, length); |
| } |
| |
| /** |
| * Encode a Processing Instruction Information Item. |
| * |
| * @param target the target of the processing instruction. |
| * @param data the data of the processing instruction. |
| */ |
| protected final void encodeProcessingInstruction(String target, String data) throws IOException { |
| write(EncodingConstants.PROCESSING_INSTRUCTION); |
| |
| // Target |
| encodeIdentifyingNonEmptyStringOnFirstBit(target, _v.otherNCName); |
| |
| // Data |
| boolean addToTable = isCharacterContentChunkLengthMatchesLimit(data.length()); |
| encodeNonIdentifyingStringOnFirstBit(data, _v.otherString, addToTable); |
| } |
| |
| /** |
| * Encode a Document Type Declaration. |
| * |
| * @param systemId the system identifier of the external subset. |
| * @param publicId the public identifier of the external subset. |
| */ |
| protected final void encodeDocumentTypeDeclaration(String systemId, String publicId) throws IOException { |
| _b = EncodingConstants.DOCUMENT_TYPE_DECLARATION; |
| if (systemId != null && systemId.length() > 0) { |
| _b |= EncodingConstants.DOCUMENT_TYPE_SYSTEM_IDENTIFIER_FLAG; |
| } |
| if (publicId != null && publicId.length() > 0) { |
| _b |= EncodingConstants.DOCUMENT_TYPE_PUBLIC_IDENTIFIER_FLAG; |
| } |
| write(_b); |
| |
| if (systemId != null && systemId.length() > 0) { |
| encodeIdentifyingNonEmptyStringOnFirstBit(systemId, _v.otherURI); |
| } |
| if (publicId != null && publicId.length() > 0) { |
| encodeIdentifyingNonEmptyStringOnFirstBit(publicId, _v.otherURI); |
| } |
| } |
| |
| /** |
| * Encode a Comment Information Item. |
| * |
| * @param ch the array of characters that is as comment. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * @throws ArrayIndexOutOfBoundsException. |
| */ |
| protected final void encodeComment(char[] ch, int offset, int length) throws IOException { |
| write(EncodingConstants.COMMENT); |
| |
| boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); |
| encodeNonIdentifyingStringOnFirstBit(ch, offset, length, _v.otherString, addToTable, true); |
| } |
| |
| /** |
| * Encode a Comment Information Item. |
| * |
| * If the array of characters that is a comment is to be indexed (as |
| * determined by {@link Encoder#characterContentChunkSizeContraint}) then |
| * the array is not cloned when adding the array to the vocabulary. |
| * |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * @throws ArrayIndexOutOfBoundsException. |
| */ |
| protected final void encodeCommentNoClone(char[] ch, int offset, int length) throws IOException { |
| write(EncodingConstants.COMMENT); |
| |
| boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); |
| encodeNonIdentifyingStringOnFirstBit(ch, offset, length, _v.otherString, addToTable, false); |
| } |
| |
| /** |
| * Encode a qualified name of an Element Informaiton Item on the third bit |
| * of an octet. |
| * Implementation of clause C.18 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * <p> |
| * The index of the qualified name will be encoded if the name is present |
| * in the vocabulary otherwise the qualified name will be encoded literally |
| * (see {@link #encodeLiteralElementQualifiedNameOnThirdBit}). |
| * |
| * @param namespaceURI the namespace URI of the qualified name. |
| * @param prefix the prefix of the qualified name. |
| * @param localName the local name of the qualified name. |
| */ |
| protected final void encodeElementQualifiedNameOnThirdBit(String namespaceURI, String prefix, String localName) throws IOException { |
| LocalNameQualifiedNamesMap.Entry entry = _v.elementName.obtainEntry(localName); |
| if (entry._valueIndex > 0) { |
| QualifiedName[] names = entry._value; |
| for (int i = 0; i < entry._valueIndex; i++) { |
| if ((prefix == names[i].prefix || prefix.equals(names[i].prefix)) |
| && (namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) { |
| encodeNonZeroIntegerOnThirdBit(names[i].index); |
| return; |
| } |
| } |
| } |
| |
| encodeLiteralElementQualifiedNameOnThirdBit(namespaceURI, prefix, |
| localName, entry); |
| } |
| |
| /** |
| * Encode a literal qualified name of an Element Informaiton Item on the |
| * third bit of an octet. |
| * Implementation of clause C.18 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param namespaceURI the namespace URI of the qualified name. |
| * @param prefix the prefix of the qualified name. |
| * @param localName the local name of the qualified name. |
| */ |
| protected final void encodeLiteralElementQualifiedNameOnThirdBit(String namespaceURI, String prefix, String localName, |
| LocalNameQualifiedNamesMap.Entry entry) throws IOException { |
| QualifiedName name = new QualifiedName(prefix, namespaceURI, localName, "", _v.elementName.getNextIndex()); |
| entry.addQualifiedName(name); |
| |
| int namespaceURIIndex = KeyIntMap.NOT_PRESENT; |
| int prefixIndex = KeyIntMap.NOT_PRESENT; |
| if (namespaceURI.length() > 0) { |
| namespaceURIIndex = _v.namespaceName.get(namespaceURI); |
| if (namespaceURIIndex == KeyIntMap.NOT_PRESENT) { |
| throw new IOException(CommonResourceBundle.getInstance().getString("message.namespaceURINotIndexed", new Object[]{namespaceURI})); |
| } |
| |
| if (prefix.length() > 0) { |
| prefixIndex = _v.prefix.get(prefix); |
| if (prefixIndex == KeyIntMap.NOT_PRESENT) { |
| throw new IOException(CommonResourceBundle.getInstance().getString("message.prefixNotIndexed", new Object[]{prefix})); |
| } |
| } |
| } |
| |
| int localNameIndex = _v.localName.obtainIndex(localName); |
| |
| _b |= EncodingConstants.ELEMENT_LITERAL_QNAME_FLAG; |
| if (namespaceURIIndex >= 0) { |
| _b |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG; |
| if (prefixIndex >= 0) { |
| _b |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG; |
| } |
| } |
| write(_b); |
| |
| if (namespaceURIIndex >= 0) { |
| if (prefixIndex >= 0) { |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(prefixIndex); |
| } |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(namespaceURIIndex); |
| } |
| |
| if (localNameIndex >= 0) { |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex); |
| } else { |
| encodeNonEmptyOctetStringOnSecondBit(localName); |
| } |
| } |
| |
| /** |
| * Encode a qualified name of an Attribute Informaiton Item on the third bit |
| * of an octet. |
| * Implementation of clause C.17 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * <p> |
| * The index of the qualified name will be encoded if the name is present |
| * in the vocabulary otherwise the qualified name will be encoded literally |
| * (see {@link #encodeLiteralAttributeQualifiedNameOnSecondBit}). |
| * |
| * @param namespaceURI the namespace URI of the qualified name. |
| * @param prefix the prefix of the qualified name. |
| * @param localName the local name of the qualified name. |
| */ |
| protected final void encodeAttributeQualifiedNameOnSecondBit(String namespaceURI, String prefix, String localName) throws IOException { |
| LocalNameQualifiedNamesMap.Entry entry = _v.attributeName.obtainEntry(localName); |
| if (entry._valueIndex > 0) { |
| QualifiedName[] names = entry._value; |
| for (int i = 0; i < entry._valueIndex; i++) { |
| if ((prefix == names[i].prefix || prefix.equals(names[i].prefix)) |
| && (namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) { |
| encodeNonZeroIntegerOnSecondBitFirstBitZero(names[i].index); |
| return; |
| } |
| } |
| } |
| |
| encodeLiteralAttributeQualifiedNameOnSecondBit(namespaceURI, prefix, |
| localName, entry); |
| } |
| |
| /** |
| * Encode a literal qualified name of an Attribute Informaiton Item on the |
| * third bit of an octet. |
| * Implementation of clause C.17 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param namespaceURI the namespace URI of the qualified name. |
| * @param prefix the prefix of the qualified name. |
| * @param localName the local name of the qualified name. |
| */ |
| protected final boolean encodeLiteralAttributeQualifiedNameOnSecondBit(String namespaceURI, String prefix, String localName, |
| LocalNameQualifiedNamesMap.Entry entry) throws IOException { |
| int namespaceURIIndex = KeyIntMap.NOT_PRESENT; |
| int prefixIndex = KeyIntMap.NOT_PRESENT; |
| if (namespaceURI.length() > 0) { |
| namespaceURIIndex = _v.namespaceName.get(namespaceURI); |
| if (namespaceURIIndex == KeyIntMap.NOT_PRESENT) { |
| if (namespaceURI == EncodingConstants.XMLNS_NAMESPACE_NAME || |
| namespaceURI.equals(EncodingConstants.XMLNS_NAMESPACE_NAME)) { |
| return false; |
| } else { |
| throw new IOException(CommonResourceBundle.getInstance().getString("message.namespaceURINotIndexed", new Object[]{namespaceURI})); |
| } |
| } |
| |
| if (prefix.length() > 0) { |
| prefixIndex = _v.prefix.get(prefix); |
| if (prefixIndex == KeyIntMap.NOT_PRESENT) { |
| throw new IOException(CommonResourceBundle.getInstance().getString("message.prefixNotIndexed", new Object[]{prefix})); |
| } |
| } |
| } |
| |
| int localNameIndex = _v.localName.obtainIndex(localName); |
| |
| QualifiedName name = new QualifiedName(prefix, namespaceURI, localName, "", _v.attributeName.getNextIndex()); |
| entry.addQualifiedName(name); |
| |
| _b = EncodingConstants.ATTRIBUTE_LITERAL_QNAME_FLAG; |
| if (namespaceURI.length() > 0) { |
| _b |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG; |
| if (prefix.length() > 0) { |
| _b |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG; |
| } |
| } |
| |
| write(_b); |
| |
| if (namespaceURIIndex >= 0) { |
| if (prefixIndex >= 0) { |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(prefixIndex); |
| } |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(namespaceURIIndex); |
| } else if (namespaceURI != "") { |
| // XML prefix and namespace name |
| encodeNonEmptyOctetStringOnSecondBit("xml"); |
| encodeNonEmptyOctetStringOnSecondBit("http://www.w3.org/XML/1998/namespace"); |
| } |
| |
| if (localNameIndex >= 0) { |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex); |
| } else { |
| encodeNonEmptyOctetStringOnSecondBit(localName); |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Encode a non identifying string on the first bit of an octet. |
| * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param s the string to encode |
| * @param map the vocabulary table of strings to indexes. |
| * @param addToTable true if the string could be added to the vocabulary |
| * table (if table has enough memory) |
| * @param mustBeAddedToTable true if the string must be added to the vocabulary |
| * table (if not already present in the table). |
| */ |
| protected final void encodeNonIdentifyingStringOnFirstBit(String s, StringIntMap map, |
| boolean addToTable, boolean mustBeAddedToTable) throws IOException { |
| if (s == null || s.length() == 0) { |
| // C.26 an index (first bit '1') with seven '1' bits for an empty string |
| write(0xFF); |
| } else { |
| if (addToTable || mustBeAddedToTable) { |
| // if attribute value could be added to table |
| boolean canAddAttributeToTable = mustBeAddedToTable || |
| canAddAttributeToTable(s.length()); |
| |
| // obtain/get index |
| int index = canAddAttributeToTable ? |
| map.obtainIndex(s) : |
| map.get(s); |
| |
| if (index != KeyIntMap.NOT_PRESENT) { |
| // if attribute value is in table |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(index); |
| } else if (canAddAttributeToTable) { |
| // if attribute value is not in table, but could be added |
| _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG | |
| _nonIdentifyingStringOnFirstBitCES; |
| encodeNonEmptyCharacterStringOnFifthBit(s); |
| } else { |
| // if attribute value is not in table and could not be added |
| _b = _nonIdentifyingStringOnFirstBitCES; |
| encodeNonEmptyCharacterStringOnFifthBit(s); |
| } |
| } else { |
| _b = _nonIdentifyingStringOnFirstBitCES; |
| encodeNonEmptyCharacterStringOnFifthBit(s); |
| } |
| } |
| } |
| |
| /** |
| * Encode a non identifying string on the first bit of an octet. |
| * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param s the string to encode |
| * @param map the vocabulary table of character arrays to indexes. |
| * @param addToTable true if the string should be added to the vocabulary |
| * table (if not already present in the table). |
| */ |
| protected final void encodeNonIdentifyingStringOnFirstBit(String s, CharArrayIntMap map, boolean addToTable) throws IOException { |
| if (s == null || s.length() == 0) { |
| // C.26 an index (first bit '1') with seven '1' bits for an empty string |
| write(0xFF); |
| } else { |
| if (addToTable) { |
| final char[] ch = s.toCharArray(); |
| final int length = s.length(); |
| |
| // if char array could be added to table |
| boolean canAddCharacterContentToTable = |
| canAddCharacterContentToTable(length, map); |
| |
| // obtain/get index |
| int index = canAddCharacterContentToTable ? |
| map.obtainIndex(ch, 0, length, false) : |
| map.get(ch, 0, length); |
| |
| if (index != KeyIntMap.NOT_PRESENT) { |
| // if char array is in table |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(index); |
| } else if (canAddCharacterContentToTable) { |
| // if char array is not in table, but could be added |
| _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG | |
| _nonIdentifyingStringOnFirstBitCES; |
| encodeNonEmptyCharacterStringOnFifthBit(ch, 0, length); |
| } else { |
| // if char array is not in table and could not be added |
| _b = _nonIdentifyingStringOnFirstBitCES; |
| encodeNonEmptyCharacterStringOnFifthBit(s); |
| } |
| } else { |
| _b = _nonIdentifyingStringOnFirstBitCES; |
| encodeNonEmptyCharacterStringOnFifthBit(s); |
| } |
| } |
| } |
| |
| /** |
| * Encode a non identifying string on the first bit of an octet. |
| * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * @param map the vocabulary table of character arrays to indexes. |
| * @param addToTable true if the string should be added to the vocabulary |
| * table (if not already present in the table). |
| * @param clone true if the array of characters should be cloned if added |
| * to the vocabulary table. |
| */ |
| protected final void encodeNonIdentifyingStringOnFirstBit(char[] ch, int offset, int length, CharArrayIntMap map, |
| boolean addToTable, boolean clone) throws IOException { |
| if (length == 0) { |
| // C.26 an index (first bit '1') with seven '1' bits for an empty string |
| write(0xFF); |
| } else { |
| if (addToTable) { |
| // if char array could be added to table |
| boolean canAddCharacterContentToTable = |
| canAddCharacterContentToTable(length, map); |
| |
| // obtain/get index |
| int index = canAddCharacterContentToTable ? |
| map.obtainIndex(ch, offset, length, clone) : |
| map.get(ch, offset, length); |
| |
| if (index != KeyIntMap.NOT_PRESENT) { |
| // if char array is in table |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(index); |
| } else if (canAddCharacterContentToTable) { |
| // if char array is not in table, but could be added |
| _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG | |
| _nonIdentifyingStringOnFirstBitCES; |
| encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length); |
| } else { |
| // if char array is not in table and could not be added |
| _b = _nonIdentifyingStringOnFirstBitCES; |
| encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length); |
| } |
| } else { |
| _b = _nonIdentifyingStringOnFirstBitCES; |
| encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length); |
| } |
| } |
| } |
| |
| protected final void encodeNumericNonIdentifyingStringOnFirstBit( |
| String s, boolean addToTable, boolean mustBeAddedToTable) |
| throws IOException, FastInfosetException { |
| encodeNonIdentifyingStringOnFirstBit( |
| RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX, |
| NUMERIC_CHARACTERS_TABLE, s, addToTable, |
| mustBeAddedToTable); |
| } |
| |
| protected final void encodeDateTimeNonIdentifyingStringOnFirstBit( |
| String s, boolean addToTable, boolean mustBeAddedToTable) |
| throws IOException, FastInfosetException { |
| encodeNonIdentifyingStringOnFirstBit( |
| RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX, |
| DATE_TIME_CHARACTERS_TABLE, s, addToTable, |
| mustBeAddedToTable); |
| } |
| |
| protected final void encodeNonIdentifyingStringOnFirstBit(int id, int[] table, |
| String s, boolean addToTable, boolean mustBeAddedToTable) |
| throws IOException, FastInfosetException { |
| if (s == null || s.length() == 0) { |
| // C.26 an index (first bit '1') with seven '1' bits for an empty string |
| write(0xFF); |
| return; |
| } |
| |
| if (addToTable || mustBeAddedToTable) { |
| // if attribute value could be added to table |
| boolean canAddAttributeToTable = mustBeAddedToTable || |
| canAddAttributeToTable(s.length()); |
| |
| // obtain/get index |
| int index = canAddAttributeToTable ? |
| _v.attributeValue.obtainIndex(s) : |
| _v.attributeValue.get(s); |
| |
| if (index != KeyIntMap.NOT_PRESENT) { |
| // if attribute value is in table |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(index); |
| return; |
| } else if (canAddAttributeToTable) { |
| // if attribute value is not in table, but could be added |
| _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG | |
| EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG; |
| } else { |
| // if attribute value is not in table and could not be added |
| _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG; |
| } |
| } else { |
| _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG; |
| } |
| |
| // Encode identification and top four bits of alphabet id |
| write (_b | ((id & 0xF0) >> 4)); |
| // Encode bottom 4 bits of alphabet id |
| _b = (id & 0x0F) << 4; |
| |
| final int length = s.length(); |
| final int octetPairLength = length / 2; |
| final int octetSingleLength = length % 2; |
| encodeNonZeroOctetStringLengthOnFifthBit(octetPairLength + octetSingleLength); |
| encodeNonEmptyFourBitCharacterString(table, s.toCharArray(), 0, octetPairLength, octetSingleLength); |
| } |
| |
| /** |
| * Encode a non identifying string on the first bit of an octet as binary |
| * data using an encoding algorithm. |
| * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param URI the encoding algorithm URI. If the URI == null then the |
| * encoding algorithm identifier takes precendence. |
| * @param id the encoding algorithm identifier. |
| * @param data the data to be encoded using an encoding algorithm. |
| * @throws EncodingAlgorithmException if the encoding algorithm URI is not |
| * present in the vocabulary, or the encoding algorithm identifier |
| * is not with the required range. |
| */ |
| protected final void encodeNonIdentifyingStringOnFirstBit(String URI, int id, Object data) throws FastInfosetException, IOException { |
| if (URI != null) { |
| id = _v.encodingAlgorithm.get(URI); |
| if (id == KeyIntMap.NOT_PRESENT) { |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI})); |
| } |
| id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START; |
| |
| EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI); |
| if (ea != null) { |
| encodeAIIObjectAlgorithmData(id, data, ea); |
| } else { |
| if (data instanceof byte[]) { |
| byte[] d = (byte[])data; |
| encodeAIIOctetAlgorithmData(id, d, 0, d.length); |
| } else { |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI")); |
| } |
| } |
| } else if (id <= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { |
| int length = 0; |
| switch(id) { |
| case EncodingAlgorithmIndexes.HEXADECIMAL: |
| case EncodingAlgorithmIndexes.BASE64: |
| length = ((byte[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.SHORT: |
| length = ((short[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.INT: |
| length = ((int[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.LONG: |
| case EncodingAlgorithmIndexes.UUID: |
| length = ((long[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.BOOLEAN: |
| length = ((boolean[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.FLOAT: |
| length = ((float[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.DOUBLE: |
| length = ((double[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.CDATA: |
| throw new UnsupportedOperationException(CommonResourceBundle.getInstance().getString("message.CDATA")); |
| default: |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.UnsupportedBuiltInAlgorithm", new Object[]{Integer.valueOf(id)})); |
| } |
| encodeAIIBuiltInAlgorithmData(id, data, 0, length); |
| } else if (id >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { |
| if (data instanceof byte[]) { |
| byte[] d = (byte[])data; |
| encodeAIIOctetAlgorithmData(id, d, 0, d.length); |
| } else { |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI")); |
| } |
| } else { |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved")); |
| } |
| } |
| |
| /** |
| * Encode the [normalized value] of an Attribute Information Item using |
| * using an encoding algorithm. |
| * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param id the encoding algorithm identifier. |
| * @param d the data, as an array of bytes, to be encoded. |
| * @param offset the offset into the array of bytes. |
| * @param length the length of bytes. |
| */ |
| protected final void encodeAIIOctetAlgorithmData(int id, byte[] d, int offset, int length) throws IOException { |
| // Encode identification and top four bits of encoding algorithm id |
| write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG | |
| ((id & 0xF0) >> 4)); |
| |
| // Encode bottom 4 bits of enoding algorithm id |
| _b = (id & 0x0F) << 4; |
| |
| // Encode the length |
| encodeNonZeroOctetStringLengthOnFifthBit(length); |
| |
| write(d, offset, length); |
| } |
| |
| /** |
| * Encode the [normalized value] of an Attribute Information Item using |
| * using an encoding algorithm. |
| * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param id the encoding algorithm identifier. |
| * @param data the data to be encoded using an encoding algorithm. |
| * @param ea the encoding algorithm to use to encode the data into an |
| * array of bytes. |
| */ |
| protected final void encodeAIIObjectAlgorithmData(int id, Object data, EncodingAlgorithm ea) throws FastInfosetException, IOException { |
| // Encode identification and top four bits of encoding algorithm id |
| write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG | |
| ((id & 0xF0) >> 4)); |
| |
| // Encode bottom 4 bits of enoding algorithm id |
| _b = (id & 0x0F) << 4; |
| |
| _encodingBufferOutputStream.reset(); |
| ea.encodeToOutputStream(data, _encodingBufferOutputStream); |
| encodeNonZeroOctetStringLengthOnFifthBit(_encodingBufferIndex); |
| write(_encodingBuffer, _encodingBufferIndex); |
| } |
| |
| /** |
| * Encode the [normalized value] of an Attribute Information Item using |
| * using a built in encoding algorithm. |
| * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param id the built in encoding algorithm identifier. |
| * @param data the data to be encoded using an encoding algorithm. The data |
| * represents an array of items specified by the encoding algorithm |
| * identifier |
| * @param offset the offset into the array of bytes. |
| * @param length the length of bytes. |
| */ |
| protected final void encodeAIIBuiltInAlgorithmData(int id, Object data, int offset, int length) throws IOException { |
| // Encode identification and top four bits of encoding algorithm id |
| write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG | |
| ((id & 0xF0) >> 4)); |
| |
| // Encode bottom 4 bits of enoding algorithm id |
| _b = (id & 0x0F) << 4; |
| |
| final int octetLength = BuiltInEncodingAlgorithmFactory.getAlgorithm(id). |
| getOctetLengthFromPrimitiveLength(length); |
| |
| encodeNonZeroOctetStringLengthOnFifthBit(octetLength); |
| |
| ensureSize(octetLength); |
| BuiltInEncodingAlgorithmFactory.getAlgorithm(id). |
| encodeToBytes(data, offset, length, _octetBuffer, _octetBufferIndex); |
| _octetBufferIndex += octetLength; |
| } |
| |
| /** |
| * Encode a non identifying string on the third bit of an octet. |
| * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * @param map the vocabulary table of character arrays to indexes. |
| * @param addToTable true if the array of characters should be added to the vocabulary |
| * table (if not already present in the table). |
| * @param clone true if the array of characters should be cloned if added |
| * to the vocabulary table. |
| */ |
| protected final void encodeNonIdentifyingStringOnThirdBit(char[] ch, int offset, int length, |
| CharArrayIntMap map, boolean addToTable, boolean clone) throws IOException { |
| // length cannot be zero since sequence of CIIs has to be > 0 |
| |
| if (addToTable) { |
| // if char array could be added to table |
| boolean canAddCharacterContentToTable = |
| canAddCharacterContentToTable(length, map); |
| |
| // obtain/get index |
| int index = canAddCharacterContentToTable ? |
| map.obtainIndex(ch, offset, length, clone) : |
| map.get(ch, offset, length); |
| |
| if (index != KeyIntMap.NOT_PRESENT) { |
| // if char array is in table |
| _b = EncodingConstants.CHARACTER_CHUNK | 0x20; |
| encodeNonZeroIntegerOnFourthBit(index); |
| } else if (canAddCharacterContentToTable) { |
| // if char array is not in table, but could be added |
| _b = EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG | |
| _nonIdentifyingStringOnThirdBitCES; |
| encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length); |
| } else { |
| // if char array is not in table and could not be added |
| _b = _nonIdentifyingStringOnThirdBitCES; |
| encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length); |
| } |
| } else { |
| // char array will not be added to map |
| _b = _nonIdentifyingStringOnThirdBitCES; |
| encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length); |
| } |
| } |
| |
| /** |
| * Encode a non identifying string on the third bit of an octet as binary |
| * data using an encoding algorithm. |
| * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param URI the encoding algorithm URI. If the URI == null then the |
| * encoding algorithm identifier takes precendence. |
| * @param id the encoding algorithm identifier. |
| * @param data the data to be encoded using an encoding algorithm. |
| * @throws EncodingAlgorithmException if the encoding algorithm URI is not |
| * present in the vocabulary, or the encoding algorithm identifier |
| * is not with the required range. |
| */ |
| protected final void encodeNonIdentifyingStringOnThirdBit(String URI, int id, Object data) throws FastInfosetException, IOException { |
| if (URI != null) { |
| id = _v.encodingAlgorithm.get(URI); |
| if (id == KeyIntMap.NOT_PRESENT) { |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI})); |
| } |
| id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START; |
| |
| EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI); |
| if (ea != null) { |
| encodeCIIObjectAlgorithmData(id, data, ea); |
| } else { |
| if (data instanceof byte[]) { |
| byte[] d = (byte[])data; |
| encodeCIIOctetAlgorithmData(id, d, 0, d.length); |
| } else { |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI")); |
| } |
| } |
| } else if (id <= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { |
| int length = 0; |
| switch(id) { |
| case EncodingAlgorithmIndexes.HEXADECIMAL: |
| case EncodingAlgorithmIndexes.BASE64: |
| length = ((byte[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.SHORT: |
| length = ((short[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.INT: |
| length = ((int[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.LONG: |
| case EncodingAlgorithmIndexes.UUID: |
| length = ((long[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.BOOLEAN: |
| length = ((boolean[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.FLOAT: |
| length = ((float[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.DOUBLE: |
| length = ((double[])data).length; |
| break; |
| case EncodingAlgorithmIndexes.CDATA: |
| throw new UnsupportedOperationException(CommonResourceBundle.getInstance().getString("message.CDATA")); |
| default: |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.UnsupportedBuiltInAlgorithm", new Object[]{Integer.valueOf(id)})); |
| } |
| encodeCIIBuiltInAlgorithmData(id, data, 0, length); |
| } else if (id >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { |
| if (data instanceof byte[]) { |
| byte[] d = (byte[])data; |
| encodeCIIOctetAlgorithmData(id, d, 0, d.length); |
| } else { |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI")); |
| } |
| } else { |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved")); |
| } |
| } |
| |
| /** |
| * Encode a non identifying string on the third bit of an octet as binary |
| * data using an encoding algorithm. |
| * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param URI the encoding algorithm URI. If the URI == null then the |
| * encoding algorithm identifier takes precendence. |
| * @param id the encoding algorithm identifier. |
| * @param d the data, as an array of bytes, to be encoded. |
| * @param offset the offset into the array of bytes. |
| * @param length the length of bytes. |
| * @throws EncodingAlgorithmException if the encoding algorithm URI is not |
| * present in the vocabulary. |
| */ |
| protected final void encodeNonIdentifyingStringOnThirdBit(String URI, int id, byte[] d, int offset, int length) throws FastInfosetException, IOException { |
| if (URI != null) { |
| id = _v.encodingAlgorithm.get(URI); |
| if (id == KeyIntMap.NOT_PRESENT) { |
| throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI})); |
| } |
| id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START; |
| } |
| |
| encodeCIIOctetAlgorithmData(id, d, offset, length); |
| } |
| |
| /** |
| * Encode a chunk of Character Information Items using |
| * using an encoding algorithm. |
| * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param id the encoding algorithm identifier. |
| * @param d the data, as an array of bytes, to be encoded. |
| * @param offset the offset into the array of bytes. |
| * @param length the length of bytes. |
| */ |
| protected final void encodeCIIOctetAlgorithmData(int id, byte[] d, int offset, int length) throws IOException { |
| // Encode identification and top two bits of encoding algorithm id |
| write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG | |
| ((id & 0xC0) >> 6)); |
| |
| // Encode bottom 6 bits of enoding algorithm id |
| _b = (id & 0x3F) << 2; |
| |
| // Encode the length |
| encodeNonZeroOctetStringLengthOnSenventhBit(length); |
| |
| write(d, offset, length); |
| } |
| |
| /** |
| * Encode a chunk of Character Information Items using |
| * using an encoding algorithm. |
| * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param id the encoding algorithm identifier. |
| * @param data the data to be encoded using an encoding algorithm. |
| * @param ea the encoding algorithm to use to encode the data into an |
| * array of bytes. |
| */ |
| protected final void encodeCIIObjectAlgorithmData(int id, Object data, EncodingAlgorithm ea) throws FastInfosetException, IOException { |
| // Encode identification and top two bits of encoding algorithm id |
| write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG | |
| ((id & 0xC0) >> 6)); |
| |
| // Encode bottom 6 bits of enoding algorithm id |
| _b = (id & 0x3F) << 2; |
| |
| _encodingBufferOutputStream.reset(); |
| ea.encodeToOutputStream(data, _encodingBufferOutputStream); |
| encodeNonZeroOctetStringLengthOnSenventhBit(_encodingBufferIndex); |
| write(_encodingBuffer, _encodingBufferIndex); |
| } |
| |
| /** |
| * Encode a chunk of Character Information Items using |
| * using an encoding algorithm. |
| * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param id the built in encoding algorithm identifier. |
| * @param data the data to be encoded using an encoding algorithm. The data |
| * represents an array of items specified by the encoding algorithm |
| * identifier |
| * @param offset the offset into the array of bytes. |
| * @param length the length of bytes. |
| */ |
| protected final void encodeCIIBuiltInAlgorithmData(int id, Object data, int offset, int length) throws FastInfosetException, IOException { |
| // Encode identification and top two bits of encoding algorithm id |
| write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG | |
| ((id & 0xC0) >> 6)); |
| |
| // Encode bottom 6 bits of enoding algorithm id |
| _b = (id & 0x3F) << 2; |
| |
| final int octetLength = BuiltInEncodingAlgorithmFactory.getAlgorithm(id). |
| getOctetLengthFromPrimitiveLength(length); |
| |
| encodeNonZeroOctetStringLengthOnSenventhBit(octetLength); |
| |
| ensureSize(octetLength); |
| BuiltInEncodingAlgorithmFactory.getAlgorithm(id). |
| encodeToBytes(data, offset, length, _octetBuffer, _octetBufferIndex); |
| _octetBufferIndex += octetLength; |
| } |
| |
| /** |
| * Encode a chunk of Character Information Items using |
| * using the CDATA built in encoding algorithm. |
| * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| */ |
| protected final void encodeCIIBuiltInAlgorithmDataAsCDATA(char[] ch, int offset, int length) throws FastInfosetException, IOException { |
| // Encode identification and top two bits of encoding algorithm id |
| write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG); |
| |
| // Encode bottom 6 bits of enoding algorithm id |
| _b = EncodingAlgorithmIndexes.CDATA << 2; |
| |
| |
| length = encodeUTF8String(ch, offset, length); |
| encodeNonZeroOctetStringLengthOnSenventhBit(length); |
| write(_encodingBuffer, length); |
| } |
| |
| /** |
| * Encode a non empty identifying string on the first bit of an octet. |
| * Implementation of clause C.13 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param s the identifying string. |
| * @param map the vocabulary table to use to determin the index of the |
| * identifying string |
| */ |
| protected final void encodeIdentifyingNonEmptyStringOnFirstBit(String s, StringIntMap map) throws IOException { |
| int index = map.obtainIndex(s); |
| if (index == KeyIntMap.NOT_PRESENT) { |
| // _b = 0; |
| encodeNonEmptyOctetStringOnSecondBit(s); |
| } else { |
| // _b = 0x80; |
| encodeNonZeroIntegerOnSecondBitFirstBitOne(index); |
| } |
| } |
| |
| /** |
| * Encode a non empty string on the second bit of an octet using the UTF-8 |
| * encoding. |
| * Implementation of clause C.22 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param s the string. |
| */ |
| protected final void encodeNonEmptyOctetStringOnSecondBit(String s) throws IOException { |
| final int length = encodeUTF8String(s); |
| encodeNonZeroOctetStringLengthOnSecondBit(length); |
| write(_encodingBuffer, length); |
| } |
| |
| /** |
| * Encode the length of a UTF-8 encoded string on the second bit of an octet. |
| * Implementation of clause C.22 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param length the length to encode. |
| */ |
| protected final void encodeNonZeroOctetStringLengthOnSecondBit(int length) throws IOException { |
| if (length < EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT) { |
| // [1, 64] |
| write(length - 1); |
| } else if (length < EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT) { |
| // [65, 320] |
| write(EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_FLAG); // 010 00000 |
| write(length - EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT); |
| } else { |
| // [321, 4294967296] |
| write(EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_LARGE_FLAG); // 0110 0000 |
| length -= EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT; |
| write(length >>> 24); |
| write((length >> 16) & 0xFF); |
| write((length >> 8) & 0xFF); |
| write(length & 0xFF); |
| } |
| } |
| |
| /** |
| * Encode a non empty string on the fifth bit of an octet using the UTF-8 |
| * or UTF-16 encoding. |
| * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param s the string. |
| */ |
| protected final void encodeNonEmptyCharacterStringOnFifthBit(String s) throws IOException { |
| final int length = (_encodingStringsAsUtf8) ? encodeUTF8String(s) : encodeUtf16String(s); |
| encodeNonZeroOctetStringLengthOnFifthBit(length); |
| write(_encodingBuffer, length); |
| } |
| |
| /** |
| * Encode a non empty string on the fifth bit of an octet using the UTF-8 |
| * or UTF-16 encoding. |
| * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| */ |
| protected final void encodeNonEmptyCharacterStringOnFifthBit(char[] ch, int offset, int length) throws IOException { |
| length = (_encodingStringsAsUtf8) ? encodeUTF8String(ch, offset, length) : encodeUtf16String(ch, offset, length); |
| encodeNonZeroOctetStringLengthOnFifthBit(length); |
| write(_encodingBuffer, length); |
| } |
| |
| /** |
| * Encode the length of a UTF-8 or UTF-16 encoded string on the fifth bit |
| * of an octet. |
| * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param length the length to encode. |
| */ |
| protected final void encodeNonZeroOctetStringLengthOnFifthBit(int length) throws IOException { |
| if (length < EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT) { |
| // [1, 8] |
| write(_b | (length - 1)); |
| } else if (length < EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT) { |
| // [9, 264] |
| write(_b | EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_FLAG); // 000010 00 |
| write(length - EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT); |
| } else { |
| // [265, 4294967296] |
| write(_b | EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_LARGE_FLAG); // 000011 00 |
| length -= EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT; |
| write(length >>> 24); |
| write((length >> 16) & 0xFF); |
| write((length >> 8) & 0xFF); |
| write(length & 0xFF); |
| } |
| } |
| |
| /** |
| * Encode a non empty string on the seventh bit of an octet using the UTF-8 |
| * or UTF-16 encoding. |
| * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| */ |
| protected final void encodeNonEmptyCharacterStringOnSeventhBit(char[] ch, int offset, int length) throws IOException { |
| length = (_encodingStringsAsUtf8) ? encodeUTF8String(ch, offset, length) : encodeUtf16String(ch, offset, length); |
| encodeNonZeroOctetStringLengthOnSenventhBit(length); |
| write(_encodingBuffer, length); |
| } |
| |
| /** |
| * Encode a non empty string on the seventh bit of an octet using a restricted |
| * alphabet that results in the encoding of a character in 4 bits |
| * (or two characters per octet). |
| * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param table the table mapping characters to 4 bit values. |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| */ |
| protected final void encodeNonEmptyFourBitCharacterStringOnSeventhBit(int[] table, char[] ch, int offset, int length) throws FastInfosetException, IOException { |
| final int octetPairLength = length / 2; |
| final int octetSingleLength = length % 2; |
| |
| // Encode the length |
| encodeNonZeroOctetStringLengthOnSenventhBit(octetPairLength + octetSingleLength); |
| encodeNonEmptyFourBitCharacterString(table, ch, offset, octetPairLength, octetSingleLength); |
| } |
| |
| protected final void encodeNonEmptyFourBitCharacterString(int[] table, char[] ch, int offset, |
| int octetPairLength, int octetSingleLength) throws FastInfosetException, IOException { |
| ensureSize(octetPairLength + octetSingleLength); |
| // Encode all pairs |
| int v = 0; |
| for (int i = 0; i < octetPairLength; i++) { |
| v = (table[ch[offset++]] << 4) | table[ch[offset++]]; |
| if (v < 0) { |
| throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange")); |
| } |
| _octetBuffer[_octetBufferIndex++] = (byte)v; |
| } |
| // Encode single character at end with termination bits |
| if (octetSingleLength == 1) { |
| v = (table[ch[offset]] << 4) | 0x0F; |
| if (v < 0) { |
| throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange")); |
| } |
| _octetBuffer[_octetBufferIndex++] = (byte)v; |
| } |
| } |
| |
| /** |
| * Encode a non empty string on the seventh bit of an octet using a restricted |
| * alphabet table. |
| * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param alphabet the alphabet defining the mapping between characters and |
| * integer values. |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| */ |
| protected final void encodeNonEmptyNBitCharacterStringOnSeventhBit(String alphabet, char[] ch, int offset, int length) throws FastInfosetException, IOException { |
| int bitsPerCharacter = 1; |
| while ((1 << bitsPerCharacter) <= alphabet.length()) { |
| bitsPerCharacter++; |
| } |
| |
| final int bits = length * bitsPerCharacter; |
| final int octets = bits / 8; |
| final int bitsOfLastOctet = bits % 8; |
| final int totalOctets = octets + ((bitsOfLastOctet > 0) ? 1 : 0); |
| |
| // Encode the length |
| encodeNonZeroOctetStringLengthOnSenventhBit(totalOctets); |
| |
| resetBits(); |
| ensureSize(totalOctets); |
| int v = 0; |
| for (int i = 0; i < length; i++) { |
| final char c = ch[offset + i]; |
| // This is grotesquely slow, need to use hash table of character to int value |
| for (v = 0; v < alphabet.length(); v++) { |
| if (c == alphabet.charAt(v)) { |
| break; |
| } |
| } |
| if (v == alphabet.length()) { |
| throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange")); |
| } |
| writeBits(bitsPerCharacter, v); |
| } |
| |
| if (bitsOfLastOctet > 0) { |
| _b |= (1 << (8 - bitsOfLastOctet)) - 1; |
| write(_b); |
| } |
| } |
| |
| private int _bitsLeftInOctet; |
| |
| private final void resetBits() { |
| _bitsLeftInOctet = 8; |
| _b = 0; |
| } |
| |
| private final void writeBits(int bits, int v) throws IOException { |
| while (bits > 0) { |
| final int bit = (v & (1 << --bits)) > 0 ? 1 : 0; |
| _b |= bit << (--_bitsLeftInOctet); |
| if (_bitsLeftInOctet == 0) { |
| write(_b); |
| _bitsLeftInOctet = 8; |
| _b = 0; |
| } |
| } |
| } |
| |
| /** |
| * Encode the length of a encoded string on the seventh bit |
| * of an octet. |
| * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param length the length to encode. |
| */ |
| protected final void encodeNonZeroOctetStringLengthOnSenventhBit(int length) throws IOException { |
| if (length < EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT) { |
| // [1, 2] |
| write(_b | (length - 1)); |
| } else if (length < EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT) { |
| // [3, 258] |
| write(_b | EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_FLAG); // 00000010 |
| write(length - EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT); |
| } else { |
| // [259, 4294967296] |
| write(_b | EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_LARGE_FLAG); // 00000011 |
| length -= EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT; |
| write(length >>> 24); |
| write((length >> 16) & 0xFF); |
| write((length >> 8) & 0xFF); |
| write(length & 0xFF); |
| } |
| } |
| |
| /** |
| * Encode a non zero integer on the second bit of an octet, setting |
| * the first bit to 1. |
| * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * <p> |
| * The first bit of the first octet is set, as specified in clause C.13 of |
| * ITU-T Rec. X.891 | ISO/IEC 24824-1 |
| * |
| * @param i The integer to encode, which is a member of the interval |
| * [0, 1048575]. In the specification the interval is [1, 1048576] |
| * |
| */ |
| protected final void encodeNonZeroIntegerOnSecondBitFirstBitOne(int i) throws IOException { |
| if (i < EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT) { |
| // [1, 64] ( [0, 63] ) 6 bits |
| write(0x80 | i); |
| } else if (i < EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT) { |
| // [65, 8256] ( [64, 8255] ) 13 bits |
| i -= EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT; |
| _b = (0x80 | EncodingConstants.INTEGER_2ND_BIT_MEDIUM_FLAG) | (i >> 8); // 010 00000 |
| // _b = 0xC0 | (i >> 8); // 010 00000 |
| write(_b); |
| write(i & 0xFF); |
| } else if (i < EncodingConstants.INTEGER_2ND_BIT_LARGE_LIMIT) { |
| // [8257, 1048576] ( [8256, 1048575] ) 20 bits |
| i -= EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT; |
| _b = (0x80 | EncodingConstants.INTEGER_2ND_BIT_LARGE_FLAG) | (i >> 16); // 0110 0000 |
| // _b = 0xE0 | (i >> 16); // 0110 0000 |
| write(_b); |
| write((i >> 8) & 0xFF); |
| write(i & 0xFF); |
| } else { |
| throw new IOException( |
| CommonResourceBundle.getInstance().getString("message.integerMaxSize", |
| new Object[]{Integer.valueOf(EncodingConstants.INTEGER_2ND_BIT_LARGE_LIMIT)})); |
| } |
| } |
| |
| /** |
| * Encode a non zero integer on the second bit of an octet, setting |
| * the first bit to 0. |
| * Implementation of clause C.25 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * <p> |
| * The first bit of the first octet is set, as specified in clause C.13 of |
| * ITU-T Rec. X.891 | ISO/IEC 24824-1 |
| * |
| * @param i The integer to encode, which is a member of the interval |
| * [0, 1048575]. In the specification the interval is [1, 1048576] |
| * |
| */ |
| protected final void encodeNonZeroIntegerOnSecondBitFirstBitZero(int i) throws IOException { |
| if (i < EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT) { |
| // [1, 64] ( [0, 63] ) 6 bits |
| write(i); |
| } else if (i < EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT) { |
| // [65, 8256] ( [64, 8255] ) 13 bits |
| i -= EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT; |
| _b = EncodingConstants.INTEGER_2ND_BIT_MEDIUM_FLAG | (i >> 8); // 010 00000 |
| write(_b); |
| write(i & 0xFF); |
| } else { |
| // [8257, 1048576] ( [8256, 1048575] ) 20 bits |
| i -= EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT; |
| _b = EncodingConstants.INTEGER_2ND_BIT_LARGE_FLAG | (i >> 16); // 0110 0000 |
| write(_b); |
| write((i >> 8) & 0xFF); |
| write(i & 0xFF); |
| } |
| } |
| |
| /** |
| * Encode a non zero integer on the third bit of an octet. |
| * Implementation of clause C.27 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param i The integer to encode, which is a member of the interval |
| * [0, 1048575]. In the specification the interval is [1, 1048576] |
| * |
| */ |
| protected final void encodeNonZeroIntegerOnThirdBit(int i) throws IOException { |
| if (i < EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT) { |
| // [1, 32] ( [0, 31] ) 5 bits |
| write(_b | i); |
| } else if (i < EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT) { |
| // [33, 2080] ( [32, 2079] ) 11 bits |
| i -= EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT; |
| _b |= EncodingConstants.INTEGER_3RD_BIT_MEDIUM_FLAG | (i >> 8); // 00100 000 |
| write(_b); |
| write(i & 0xFF); |
| } else if (i < EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT) { |
| // [2081, 526368] ( [2080, 526367] ) 19 bits |
| i -= EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT; |
| _b |= EncodingConstants.INTEGER_3RD_BIT_LARGE_FLAG | (i >> 16); // 00101 000 |
| write(_b); |
| write((i >> 8) & 0xFF); |
| write(i & 0xFF); |
| } else { |
| // [526369, 1048576] ( [526368, 1048575] ) 20 bits |
| i -= EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT; |
| _b |= EncodingConstants.INTEGER_3RD_BIT_LARGE_LARGE_FLAG; // 00110 000 |
| write(_b); |
| write(i >> 16); |
| write((i >> 8) & 0xFF); |
| write(i & 0xFF); |
| } |
| } |
| |
| /** |
| * Encode a non zero integer on the fourth bit of an octet. |
| * Implementation of clause C.28 of ITU-T Rec. X.891 | ISO/IEC 24824-1. |
| * |
| * @param i The integer to encode, which is a member of the interval |
| * [0, 1048575]. In the specification the interval is [1, 1048576] |
| * |
| */ |
| protected final void encodeNonZeroIntegerOnFourthBit(int i) throws IOException { |
| if (i < EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT) { |
| // [1, 16] ( [0, 15] ) 4 bits |
| write(_b | i); |
| } else if (i < EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT) { |
| // [17, 1040] ( [16, 1039] ) 10 bits |
| i -= EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT; |
| _b |= EncodingConstants.INTEGER_4TH_BIT_MEDIUM_FLAG | (i >> 8); // 000 100 00 |
| write(_b); |
| write(i & 0xFF); |
| } else if (i < EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT) { |
| // [1041, 263184] ( [1040, 263183] ) 18 bits |
| i -= EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT; |
| _b |= EncodingConstants.INTEGER_4TH_BIT_LARGE_FLAG | (i >> 16); // 000 101 00 |
| write(_b); |
| write((i >> 8) & 0xFF); |
| write(i & 0xFF); |
| } else { |
| // [263185, 1048576] ( [263184, 1048575] ) 20 bits |
| i -= EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT; |
| _b |= EncodingConstants.INTEGER_4TH_BIT_LARGE_LARGE_FLAG; // 000 110 00 |
| write(_b); |
| write(i >> 16); |
| write((i >> 8) & 0xFF); |
| write(i & 0xFF); |
| } |
| } |
| |
| /** |
| * Encode a non empty string using the UTF-8 encoding. |
| * |
| * @param b the current octet that is being written. |
| * @param s the string to be UTF-8 encoded. |
| * @param constants the array of constants to use when encoding to determin |
| * how the length of the UTF-8 encoded string is encoded. |
| */ |
| protected final void encodeNonEmptyUTF8StringAsOctetString(int b, String s, int[] constants) throws IOException { |
| final char[] ch = s.toCharArray(); |
| encodeNonEmptyUTF8StringAsOctetString(b, ch, 0, ch.length, constants); |
| } |
| |
| /** |
| * Encode a non empty string using the UTF-8 encoding. |
| * |
| * @param b the current octet that is being written. |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| * how the length of the UTF-8 encoded string is encoded. |
| * @param constants the array of constants to use when encoding to determin |
| * how the length of the UTF-8 encoded string is encoded. |
| */ |
| protected final void encodeNonEmptyUTF8StringAsOctetString(int b, char ch[], int offset, int length, int[] constants) throws IOException { |
| length = encodeUTF8String(ch, offset, length); |
| encodeNonZeroOctetStringLength(b, length, constants); |
| write(_encodingBuffer, length); |
| } |
| |
| /** |
| * Encode the length of non empty UTF-8 encoded string. |
| * |
| * @param b the current octet that is being written. |
| * @param length the length of the UTF-8 encoded string. |
| * how the length of the UTF-8 encoded string is encoded. |
| * @param constants the array of constants to use when encoding to determin |
| * how the length of the UTF-8 encoded string is encoded. |
| */ |
| protected final void encodeNonZeroOctetStringLength(int b, int length, int[] constants) throws IOException { |
| if (length < constants[EncodingConstants.OCTET_STRING_LENGTH_SMALL_LIMIT]) { |
| write(b | (length - 1)); |
| } else if (length < constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_LIMIT]) { |
| write(b | constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_FLAG]); |
| write(length - constants[EncodingConstants.OCTET_STRING_LENGTH_SMALL_LIMIT]); |
| } else { |
| write(b | constants[EncodingConstants.OCTET_STRING_LENGTH_LARGE_FLAG]); |
| length -= constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_LIMIT]; |
| write(length >>> 24); |
| write((length >> 16) & 0xFF); |
| write((length >> 8) & 0xFF); |
| write(length & 0xFF); |
| } |
| } |
| |
| /** |
| * Encode a non zero integer. |
| * |
| * @param b the current octet that is being written. |
| * @param i the non zero integer. |
| * @param constants the array of constants to use when encoding to determin |
| * how the non zero integer is encoded. |
| */ |
| protected final void encodeNonZeroInteger(int b, int i, int[] constants) throws IOException { |
| if (i < constants[EncodingConstants.INTEGER_SMALL_LIMIT]) { |
| write(b | i); |
| } else if (i < constants[EncodingConstants.INTEGER_MEDIUM_LIMIT]) { |
| i -= constants[EncodingConstants.INTEGER_SMALL_LIMIT]; |
| write(b | constants[EncodingConstants.INTEGER_MEDIUM_FLAG] | (i >> 8)); |
| write(i & 0xFF); |
| } else if (i < constants[EncodingConstants.INTEGER_LARGE_LIMIT]) { |
| i -= constants[EncodingConstants.INTEGER_MEDIUM_LIMIT]; |
| write(b | constants[EncodingConstants.INTEGER_LARGE_FLAG] | (i >> 16)); |
| write((i >> 8) & 0xFF); |
| write(i & 0xFF); |
| } else if (i < EncodingConstants.INTEGER_MAXIMUM_SIZE) { |
| i -= constants[EncodingConstants.INTEGER_LARGE_LIMIT]; |
| write(b | constants[EncodingConstants.INTEGER_LARGE_LARGE_FLAG]); |
| write(i >> 16); |
| write((i >> 8) & 0xFF); |
| write(i & 0xFF); |
| } else { |
| throw new IOException(CommonResourceBundle.getInstance().getString("message.integerMaxSize", new Object[]{Integer.valueOf(EncodingConstants.INTEGER_MAXIMUM_SIZE)})); |
| } |
| } |
| |
| /** |
| * Mark the current position in the buffered stream. |
| */ |
| protected final void mark() { |
| _markIndex = _octetBufferIndex; |
| } |
| |
| /** |
| * Reset the marked position in the buffered stream. |
| */ |
| protected final void resetMark() { |
| _markIndex = -1; |
| } |
| |
| /** |
| * @return true if the mark has been set, otherwise false if the mark |
| * has not been set. |
| */ |
| protected final boolean hasMark() { |
| return _markIndex != -1; |
| } |
| |
| /** |
| * Write a byte to the buffered stream. |
| */ |
| protected final void write(int i) throws IOException { |
| if (_octetBufferIndex < _octetBuffer.length) { |
| _octetBuffer[_octetBufferIndex++] = (byte)i; |
| } else { |
| if (_markIndex == -1) { |
| _s.write(_octetBuffer); |
| _octetBufferIndex = 1; |
| _octetBuffer[0] = (byte)i; |
| } else { |
| resize(_octetBuffer.length * 3 / 2); |
| _octetBuffer[_octetBufferIndex++] = (byte)i; |
| } |
| } |
| } |
| |
| /** |
| * Write an array of bytes to the buffered stream. |
| * |
| * @param b the array of bytes. |
| * @param length the length of bytes. |
| */ |
| protected final void write(byte[] b, int length) throws IOException { |
| write(b, 0, length); |
| } |
| |
| /** |
| * Write an array of bytes to the buffered stream. |
| * |
| * @param b the array of bytes. |
| * @param offset the offset into the array of bytes. |
| * @param length the length of bytes. |
| */ |
| protected final void write(byte[] b, int offset, int length) throws IOException { |
| if ((_octetBufferIndex + length) < _octetBuffer.length) { |
| System.arraycopy(b, offset, _octetBuffer, _octetBufferIndex, length); |
| _octetBufferIndex += length; |
| } else { |
| if (_markIndex == -1) { |
| _s.write(_octetBuffer, 0, _octetBufferIndex); |
| _s.write(b, offset, length); |
| _octetBufferIndex = 0; |
| } else { |
| resize((_octetBuffer.length + length) * 3 / 2 + 1); |
| System.arraycopy(b, offset, _octetBuffer, _octetBufferIndex, length); |
| _octetBufferIndex += length; |
| } |
| } |
| } |
| |
| private void ensureSize(int length) { |
| if ((_octetBufferIndex + length) > _octetBuffer.length) { |
| resize((_octetBufferIndex + length) * 3 / 2 + 1); |
| } |
| } |
| |
| private void resize(int length) { |
| byte[] b = new byte[length]; |
| System.arraycopy(_octetBuffer, 0, b, 0, _octetBufferIndex); |
| _octetBuffer = b; |
| } |
| |
| private void _flush() throws IOException { |
| if (_octetBufferIndex > 0) { |
| _s.write(_octetBuffer, 0, _octetBufferIndex); |
| _octetBufferIndex = 0; |
| } |
| } |
| |
| |
| private EncodingBufferOutputStream _encodingBufferOutputStream = new EncodingBufferOutputStream(); |
| |
| private byte[] _encodingBuffer = new byte[512]; |
| |
| private int _encodingBufferIndex; |
| |
| private class EncodingBufferOutputStream extends OutputStream { |
| |
| public void write(int b) throws IOException { |
| if (_encodingBufferIndex < _encodingBuffer.length) { |
| _encodingBuffer[_encodingBufferIndex++] = (byte)b; |
| } else { |
| byte newbuf[] = new byte[Math.max(_encodingBuffer.length << 1, _encodingBufferIndex)]; |
| System.arraycopy(_encodingBuffer, 0, newbuf, 0, _encodingBufferIndex); |
| _encodingBuffer = newbuf; |
| |
| _encodingBuffer[_encodingBufferIndex++] = (byte)b; |
| } |
| } |
| |
| public void write(byte b[], int off, int len) throws IOException { |
| if ((off < 0) || (off > b.length) || (len < 0) || |
| ((off + len) > b.length) || ((off + len) < 0)) { |
| throw new IndexOutOfBoundsException(); |
| } else if (len == 0) { |
| return; |
| } |
| final int newoffset = _encodingBufferIndex + len; |
| if (newoffset > _encodingBuffer.length) { |
| byte newbuf[] = new byte[Math.max(_encodingBuffer.length << 1, newoffset)]; |
| System.arraycopy(_encodingBuffer, 0, newbuf, 0, _encodingBufferIndex); |
| _encodingBuffer = newbuf; |
| } |
| System.arraycopy(b, off, _encodingBuffer, _encodingBufferIndex, len); |
| _encodingBufferIndex = newoffset; |
| } |
| |
| public int getLength() { |
| return _encodingBufferIndex; |
| } |
| |
| public void reset() { |
| _encodingBufferIndex = 0; |
| } |
| } |
| |
| /** |
| * Encode a string using the UTF-8 encoding. |
| * |
| * @param s the string to encode. |
| */ |
| protected final int encodeUTF8String(String s) throws IOException { |
| final int length = s.length(); |
| if (length < _charBuffer.length) { |
| s.getChars(0, length, _charBuffer, 0); |
| return encodeUTF8String(_charBuffer, 0, length); |
| } else { |
| char[] ch = s.toCharArray(); |
| return encodeUTF8String(ch, 0, length); |
| } |
| } |
| |
| private void ensureEncodingBufferSizeForUtf8String(int length) { |
| final int newLength = 4 * length; |
| if (_encodingBuffer.length < newLength) { |
| _encodingBuffer = new byte[newLength]; |
| } |
| } |
| |
| /** |
| * Encode a string using the UTF-8 encoding. |
| * |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| */ |
| protected final int encodeUTF8String(char[] ch, int offset, int length) throws IOException { |
| int bpos = 0; |
| |
| // Make sure buffer is large enough |
| ensureEncodingBufferSizeForUtf8String(length); |
| |
| final int end = offset + length; |
| int c; |
| while (end != offset) { |
| c = ch[offset++]; |
| if (c < 0x80) { |
| // 1 byte, 7 bits |
| _encodingBuffer[bpos++] = (byte) c; |
| } else if (c < 0x800) { |
| // 2 bytes, 11 bits |
| _encodingBuffer[bpos++] = |
| (byte) (0xC0 | (c >> 6)); // first 5 |
| _encodingBuffer[bpos++] = |
| (byte) (0x80 | (c & 0x3F)); // second 6 |
| } else if (c <= '\uFFFF') { |
| if (!XMLChar.isHighSurrogate(c) && !XMLChar.isLowSurrogate(c)) { |
| // 3 bytes, 16 bits |
| _encodingBuffer[bpos++] = |
| (byte) (0xE0 | (c >> 12)); // first 4 |
| _encodingBuffer[bpos++] = |
| (byte) (0x80 | ((c >> 6) & 0x3F)); // second 6 |
| _encodingBuffer[bpos++] = |
| (byte) (0x80 | (c & 0x3F)); // third 6 |
| } else { |
| // 4 bytes, high and low surrogate |
| encodeCharacterAsUtf8FourByte(c, ch, offset, end, bpos); |
| bpos += 4; |
| offset++; |
| } |
| } |
| } |
| |
| return bpos; |
| } |
| |
| private void encodeCharacterAsUtf8FourByte(int c, char[] ch, int chpos, int chend, int bpos) throws IOException { |
| if (chpos == chend) { |
| throw new IOException(""); |
| } |
| |
| final char d = ch[chpos]; |
| if (!XMLChar.isLowSurrogate(d)) { |
| throw new IOException(""); |
| } |
| |
| final int uc = (((c & 0x3ff) << 10) | (d & 0x3ff)) + 0x10000; |
| if (uc < 0 || uc >= 0x200000) { |
| throw new IOException(""); |
| } |
| |
| _encodingBuffer[bpos++] = (byte)(0xF0 | ((uc >> 18))); |
| _encodingBuffer[bpos++] = (byte)(0x80 | ((uc >> 12) & 0x3F)); |
| _encodingBuffer[bpos++] = (byte)(0x80 | ((uc >> 6) & 0x3F)); |
| _encodingBuffer[bpos++] = (byte)(0x80 | (uc & 0x3F)); |
| } |
| |
| /** |
| * Encode a string using the UTF-16 encoding. |
| * |
| * @param s the string to encode. |
| */ |
| protected final int encodeUtf16String(String s) throws IOException { |
| final int length = s.length(); |
| if (length < _charBuffer.length) { |
| s.getChars(0, length, _charBuffer, 0); |
| return encodeUtf16String(_charBuffer, 0, length); |
| } else { |
| char[] ch = s.toCharArray(); |
| return encodeUtf16String(ch, 0, length); |
| } |
| } |
| |
| private void ensureEncodingBufferSizeForUtf16String(int length) { |
| final int newLength = 2 * length; |
| if (_encodingBuffer.length < newLength) { |
| _encodingBuffer = new byte[newLength]; |
| } |
| } |
| |
| /** |
| * Encode a string using the UTF-16 encoding. |
| * |
| * @param ch the array of characters. |
| * @param offset the offset into the array of characters. |
| * @param length the length of characters. |
| */ |
| protected final int encodeUtf16String(char[] ch, int offset, int length) throws IOException { |
| int byteLength = 0; |
| |
| // Make sure buffer is large enough |
| ensureEncodingBufferSizeForUtf16String(length); |
| |
| final int n = offset + length; |
| for (int i = offset; i < n; i++) { |
| final int c = (int) ch[i]; |
| _encodingBuffer[byteLength++] = (byte)(c >> 8); |
| _encodingBuffer[byteLength++] = (byte)(c & 0xFF); |
| } |
| |
| return byteLength; |
| } |
| |
| /** |
| * Obtain the prefix from a qualified name. |
| * |
| * @param qName the qualified name |
| * @return the prefix, or "" if there is no prefix. |
| */ |
| public static String getPrefixFromQualifiedName(String qName) { |
| int i = qName.indexOf(':'); |
| String prefix = ""; |
| if (i != -1) { |
| prefix = qName.substring(0, i); |
| } |
| return prefix; |
| } |
| |
| /** |
| * Check if character array contains characters that are all white space. |
| * |
| * @param ch the character array |
| * @param start the starting character index into the array to check from |
| * @param length the number of characters to check |
| * @return true if all characters are white space, false otherwise |
| */ |
| public static boolean isWhiteSpace(final char[] ch, int start, final int length) { |
| if (!XMLChar.isSpace(ch[start])) return false; |
| |
| final int end = start + length; |
| while(++start < end && XMLChar.isSpace(ch[start])); |
| |
| return start == end; |
| } |
| |
| /** |
| * Check if a String contains characters that are all white space. |
| * |
| * @param s the string |
| * @return true if all characters are white space, false otherwise |
| */ |
| public static boolean isWhiteSpace(String s) { |
| if (!XMLChar.isSpace(s.charAt(0))) return false; |
| |
| final int end = s.length(); |
| int start = 1; |
| while(start < end && XMLChar.isSpace(s.charAt(start++))); |
| return start == end; |
| } |
| } |