src/share/jaxws_classes/com/sun/xml/internal/fastinfoset/Encoder.java

Thu, 12 Oct 2017 19:44:07 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:44:07 +0800
changeset 760
e530533619ec
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  *
    25  * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
    26  */
    28 package com.sun.xml.internal.fastinfoset;
    30 import com.sun.xml.internal.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory;
    31 import com.sun.xml.internal.fastinfoset.org.apache.xerces.util.XMLChar;
    32 import com.sun.xml.internal.fastinfoset.util.CharArrayIntMap;
    33 import com.sun.xml.internal.fastinfoset.util.KeyIntMap;
    34 import com.sun.xml.internal.fastinfoset.util.LocalNameQualifiedNamesMap;
    35 import com.sun.xml.internal.fastinfoset.util.StringIntMap;
    36 import com.sun.xml.internal.fastinfoset.vocab.SerializerVocabulary;
    37 import java.io.IOException;
    38 import java.io.OutputStream;
    39 import java.util.HashMap;
    40 import java.util.Map;
    41 import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm;
    42 import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmException;
    43 import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes;
    44 import com.sun.xml.internal.org.jvnet.fastinfoset.ExternalVocabulary;
    45 import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException;
    46 import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetSerializer;
    47 import com.sun.xml.internal.org.jvnet.fastinfoset.RestrictedAlphabet;
    48 import com.sun.xml.internal.org.jvnet.fastinfoset.VocabularyApplicationData;
    49 import org.xml.sax.helpers.DefaultHandler;
    51 /**
    52  * Abstract encoder for developing concrete encoders.
    53  *
    54  * Concrete implementations extending Encoder will utilize methods on Encoder
    55  * to encode XML infoset according to the Fast Infoset standard. It is the
    56  * responsibility of the concrete implementation to ensure that methods are
    57  * invoked in the correct order to produce a valid fast infoset document.
    58  *
    59  * <p>
    60  * This class extends org.sax.xml.DefaultHandler so that concrete SAX
    61  * implementations can be used with javax.xml.parsers.SAXParser and the parse
    62  * methods that take org.sax.xml.DefaultHandler as a parameter.
    63  *
    64  * <p>
    65  * Buffering of octets that are written to an {@link java.io.OutputStream} is
    66  * supported in a similar manner to a {@link java.io.BufferedOutputStream}.
    67  * Combining buffering with encoding enables better performance.
    68  *
    69  * <p>
    70  * More than one fast infoset document may be encoded to the
    71  * {@link java.io.OutputStream}.
    72  *
    73  */
    74 public abstract class Encoder extends DefaultHandler implements FastInfosetSerializer {
    76     /**
    77      * Character encoding scheme system property for the encoding
    78      * of content and attribute values.
    79      */
    80     public static final String CHARACTER_ENCODING_SCHEME_SYSTEM_PROPERTY =
    81         "com.sun.xml.internal.fastinfoset.serializer.character-encoding-scheme";
    83     /**
    84      * Default character encoding scheme system property for the encoding
    85      * of content and attribute values.
    86      */
    87     protected static final String _characterEncodingSchemeSystemDefault = getDefaultEncodingScheme();
    89     private static String getDefaultEncodingScheme() {
    90         String p = System.getProperty(CHARACTER_ENCODING_SCHEME_SYSTEM_PROPERTY,
    91             UTF_8);
    92         if (p.equals(UTF_16BE)) {
    93             return UTF_16BE;
    94         } else {
    95             return UTF_8;
    96         }
    97     }
    99     private static int[] NUMERIC_CHARACTERS_TABLE;
   101     private static int[] DATE_TIME_CHARACTERS_TABLE;
   103     static {
   104         NUMERIC_CHARACTERS_TABLE = new int[maxCharacter(RestrictedAlphabet.NUMERIC_CHARACTERS) + 1];
   105         DATE_TIME_CHARACTERS_TABLE = new int[maxCharacter(RestrictedAlphabet.DATE_TIME_CHARACTERS) + 1];
   107         for (int i = 0; i < NUMERIC_CHARACTERS_TABLE.length ; i++) {
   108             NUMERIC_CHARACTERS_TABLE[i] = -1;
   109         }
   110         for (int i = 0; i < DATE_TIME_CHARACTERS_TABLE.length ; i++) {
   111             DATE_TIME_CHARACTERS_TABLE[i] = -1;
   112         }
   114         for (int i = 0; i < RestrictedAlphabet.NUMERIC_CHARACTERS.length() ; i++) {
   115             NUMERIC_CHARACTERS_TABLE[RestrictedAlphabet.NUMERIC_CHARACTERS.charAt(i)] = i;
   116         }
   117         for (int i = 0; i < RestrictedAlphabet.DATE_TIME_CHARACTERS.length() ; i++) {
   118             DATE_TIME_CHARACTERS_TABLE[RestrictedAlphabet.DATE_TIME_CHARACTERS.charAt(i)] = i;
   119         }
   120     }
   122     private static int maxCharacter(String alphabet) {
   123         int c = 0;
   124         for (int i = 0; i < alphabet.length() ; i++) {
   125             if (c < alphabet.charAt(i)) {
   126                 c = alphabet.charAt(i);
   127             }
   128         }
   130         return c;
   131     }
   133     /**
   134      * True if DTD and internal subset shall be ignored.
   135      */
   136     private boolean _ignoreDTD;
   138     /**
   139      * True if comments shall be ignored.
   140      */
   141     private boolean _ignoreComments;
   143     /**
   144      * True if procesing instructions shall be ignored.
   145      */
   146     private boolean _ignoreProcessingInstructions;
   148     /**
   149      * True if white space characters for text content shall be ignored.
   150      */
   151     private boolean _ignoreWhiteSpaceTextContent;
   153     /**
   154      * True, if the local name string is used as the key to find the
   155      * associated set of qualified names.
   156      * <p>
   157      * False,  if the <prefix>:<local name> string is used as the key
   158      * to find the associated set of qualified names.
   159      */
   160     private boolean _useLocalNameAsKeyForQualifiedNameLookup;
   162     /**
   163      * True if strings for text content and attribute values will be
   164      * UTF-8 encoded otherwise they will be UTF-16 encoded.
   165      */
   166     private boolean _encodingStringsAsUtf8 = true;
   168     /**
   169      * Encoding constant generated from the string encoding.
   170      */
   171     private int _nonIdentifyingStringOnThirdBitCES;
   173     /**
   174      * Encoding constant generated from the string encoding.
   175      */
   176     private int _nonIdentifyingStringOnFirstBitCES;
   178     /**
   179      * The map of URIs to algorithms.
   180      */
   181     private Map _registeredEncodingAlgorithms = new HashMap();
   183     /**
   184      * The vocabulary that is used by the encoder
   185      */
   186     protected SerializerVocabulary _v;
   188     /**
   189      * The vocabulary application data that is used by the encoder
   190      */
   191     protected VocabularyApplicationData _vData;
   193     /**
   194      * True if the vocubulary is internal to the encoder
   195      */
   196     private boolean _vIsInternal;
   198     /**
   199      * True if terminatation of an information item is required
   200      */
   201     protected boolean _terminate = false;
   203     /**
   204      * The current octet that is to be written.
   205      */
   206     protected int _b;
   208     /**
   209      * The {@link java.io.OutputStream} that the encoded XML infoset (the
   210      * fast infoset document) is written to.
   211      */
   212     protected OutputStream _s;
   214     /**
   215      * The internal buffer of characters used for the UTF-8 or UTF-16 encoding
   216      * of characters.
   217      */
   218     protected char[] _charBuffer = new char[512];
   220     /**
   221      * The internal buffer of bytes.
   222      */
   223     protected byte[] _octetBuffer = new byte[1024];
   225     /**
   226      * The current position in the internal buffer.
   227      */
   228     protected int _octetBufferIndex;
   230     /**
   231      * The current mark in the internal buffer.
   232      *
   233      * <p>
   234      * If the value of the mark is < 0 then the mark is not set.
   235      */
   236     protected int _markIndex = -1;
   238     /**
   239      * The minimum size of [normalized value] of Attribute Information
   240      * Items that will be indexed.
   241      */
   242     protected int minAttributeValueSize = FastInfosetSerializer.MIN_ATTRIBUTE_VALUE_SIZE;
   244     /**
   245      * The maximum size of [normalized value] of Attribute Information
   246      * Items that will be indexed.
   247      */
   248     protected int maxAttributeValueSize = FastInfosetSerializer.MAX_ATTRIBUTE_VALUE_SIZE;
   250     /**
   251      * The limit on the size of indexed Map for attribute values
   252      * Limit is measured in characters number
   253      */
   254     protected int attributeValueMapTotalCharactersConstraint = FastInfosetSerializer.ATTRIBUTE_VALUE_MAP_MEMORY_CONSTRAINT / 2;
   256     /**
   257      * The minimum size of character content chunks
   258      * of Character Information Items or Comment Information Items that
   259      * will be indexed.
   260      */
   261     protected int minCharacterContentChunkSize = FastInfosetSerializer.MIN_CHARACTER_CONTENT_CHUNK_SIZE;
   263     /**
   264      * The maximum size of character content chunks
   265      * of Character Information Items or Comment Information Items that
   266      * will be indexed.
   267      */
   268     protected int maxCharacterContentChunkSize = FastInfosetSerializer.MAX_CHARACTER_CONTENT_CHUNK_SIZE;
   270     /**
   271      * The limit on the size of indexed Map for character content chunks
   272      * Limit is measured in characters number
   273      */
   274     protected int characterContentChunkMapTotalCharactersConstraint = FastInfosetSerializer.CHARACTER_CONTENT_CHUNK_MAP_MEMORY_CONSTRAINT / 2;
   276     /**
   277      * Default constructor for the Encoder.
   278      */
   279     protected Encoder() {
   280         setCharacterEncodingScheme(_characterEncodingSchemeSystemDefault);
   281     }
   283     protected Encoder(boolean useLocalNameAsKeyForQualifiedNameLookup) {
   284         setCharacterEncodingScheme(_characterEncodingSchemeSystemDefault);
   285         _useLocalNameAsKeyForQualifiedNameLookup = useLocalNameAsKeyForQualifiedNameLookup;
   286     }
   289     // FastInfosetSerializer interface
   291     /**
   292      * {@inheritDoc}
   293      */
   294     public final void setIgnoreDTD(boolean ignoreDTD) {
   295         _ignoreDTD = ignoreDTD;
   296     }
   298     /**
   299      * {@inheritDoc}
   300      */
   301     public final boolean getIgnoreDTD() {
   302         return _ignoreDTD;
   303     }
   305     /**
   306      * {@inheritDoc}
   307      */
   308     public final void setIgnoreComments(boolean ignoreComments) {
   309         _ignoreComments = ignoreComments;
   310     }
   312     /**
   313      * {@inheritDoc}
   314      */
   315     public final boolean getIgnoreComments() {
   316         return _ignoreComments;
   317     }
   319     /**
   320      * {@inheritDoc}
   321      */
   322     public final void setIgnoreProcesingInstructions(boolean
   323             ignoreProcesingInstructions) {
   324         _ignoreProcessingInstructions = ignoreProcesingInstructions;
   325     }
   327     /**
   328      * {@inheritDoc}
   329      */
   330     public final boolean getIgnoreProcesingInstructions() {
   331         return _ignoreProcessingInstructions;
   332     }
   334     /**
   335      * {@inheritDoc}
   336      */
   337     public final void setIgnoreWhiteSpaceTextContent(boolean ignoreWhiteSpaceTextContent) {
   338         _ignoreWhiteSpaceTextContent = ignoreWhiteSpaceTextContent;
   339     }
   341     /**
   342      * {@inheritDoc}
   343      */
   344     public final boolean getIgnoreWhiteSpaceTextContent() {
   345         return _ignoreWhiteSpaceTextContent;
   346     }
   348     /**
   349      * {@inheritDoc}
   350      */
   351     public void setCharacterEncodingScheme(String characterEncodingScheme) {
   352         if (characterEncodingScheme.equals(UTF_16BE)) {
   353             _encodingStringsAsUtf8 = false;
   354             _nonIdentifyingStringOnThirdBitCES = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_UTF_16_FLAG;
   355             _nonIdentifyingStringOnFirstBitCES = EncodingConstants.NISTRING_UTF_16_FLAG;
   356         } else {
   357             _encodingStringsAsUtf8 = true;
   358             _nonIdentifyingStringOnThirdBitCES = EncodingConstants.CHARACTER_CHUNK;
   359             _nonIdentifyingStringOnFirstBitCES = 0;
   360         }
   361     }
   363     /**
   364      * {@inheritDoc}
   365      */
   366     public String getCharacterEncodingScheme() {
   367         return (_encodingStringsAsUtf8) ? UTF_8 : UTF_16BE;
   368     }
   370     /**
   371      * {@inheritDoc}
   372      */
   373     public void setRegisteredEncodingAlgorithms(Map algorithms) {
   374         _registeredEncodingAlgorithms = algorithms;
   375         if (_registeredEncodingAlgorithms == null) {
   376             _registeredEncodingAlgorithms = new HashMap();
   377         }
   378     }
   380     /**
   381      * {@inheritDoc}
   382      */
   383     public Map getRegisteredEncodingAlgorithms() {
   384         return _registeredEncodingAlgorithms;
   385     }
   387     /**
   388      * {@inheritDoc}
   389      */
   390     public int getMinCharacterContentChunkSize() {
   391         return minCharacterContentChunkSize;
   392     }
   394     /**
   395      * {@inheritDoc}
   396      */
   397     public void setMinCharacterContentChunkSize(int size) {
   398         if (size < 0 ) {
   399             size = 0;
   400         }
   402         minCharacterContentChunkSize = size;
   403     }
   405     /**
   406      * {@inheritDoc}
   407      */
   408     public int getMaxCharacterContentChunkSize() {
   409         return maxCharacterContentChunkSize;
   410     }
   412     /**
   413      * {@inheritDoc}
   414      */
   415     public void setMaxCharacterContentChunkSize(int size) {
   416         if (size < 0 ) {
   417             size = 0;
   418         }
   420         maxCharacterContentChunkSize = size;
   421     }
   423     /**
   424      * {@inheritDoc}
   425      */
   426     public int getCharacterContentChunkMapMemoryLimit() {
   427         return characterContentChunkMapTotalCharactersConstraint * 2;
   428     }
   430     /**
   431      * {@inheritDoc}
   432      */
   433     public void setCharacterContentChunkMapMemoryLimit(int size) {
   434         if (size < 0 ) {
   435             size = 0;
   436         }
   438         characterContentChunkMapTotalCharactersConstraint = size / 2;
   439     }
   441     /**
   442      * Checks whether character content chunk (its length) matches length limit
   443      *
   444      * @param length the length of character content chunk is checking to be added to Map.
   445      * @return whether character content chunk length matches limit
   446      */
   447     public boolean isCharacterContentChunkLengthMatchesLimit(int length) {
   448         return length >= minCharacterContentChunkSize &&
   449                 length < maxCharacterContentChunkSize;
   450     }
   452     /**
   453      * Checks whether character content table has enough memory to
   454      * store character content chunk with the given length
   455      *
   456      * @param length the length of character content chunk is checking to be added to Map.
   457      * @param map the custom CharArrayIntMap, which memory limits will be checked.
   458      * @return whether character content map has enough memory
   459      */
   460     public boolean canAddCharacterContentToTable(int length, CharArrayIntMap map) {
   461         return map.getTotalCharacterCount() + length <
   462                         characterContentChunkMapTotalCharactersConstraint;
   463     }
   465     /**
   466      * {@inheritDoc}
   467      */
   468     public int getMinAttributeValueSize() {
   469         return minAttributeValueSize;
   470     }
   472     /**
   473      * {@inheritDoc}
   474      */
   475     public void setMinAttributeValueSize(int size) {
   476         if (size < 0 ) {
   477             size = 0;
   478         }
   480         minAttributeValueSize = size;
   481     }
   483     /**
   484      * {@inheritDoc}
   485      */
   486     public int getMaxAttributeValueSize() {
   487         return maxAttributeValueSize;
   488     }
   490     /**
   491      * {@inheritDoc}
   492      */
   493     public void setMaxAttributeValueSize(int size) {
   494         if (size < 0 ) {
   495             size = 0;
   496         }
   498         maxAttributeValueSize = size;
   499     }
   501     /**
   502      * {@inheritDoc}
   503      */
   504     public void setAttributeValueMapMemoryLimit(int size) {
   505         if (size < 0 ) {
   506             size = 0;
   507         }
   509         attributeValueMapTotalCharactersConstraint = size / 2;
   511     }
   513     /**
   514      * {@inheritDoc}
   515      */
   516     public int getAttributeValueMapMemoryLimit() {
   517         return attributeValueMapTotalCharactersConstraint * 2;
   518     }
   520     /**
   521      * Checks whether attribute value (its length) matches length limit
   522      *
   523      * @param length the length of attribute
   524      * @return whether attribute value matches limit
   525      */
   526     public boolean isAttributeValueLengthMatchesLimit(int length) {
   527         return length >= minAttributeValueSize &&
   528                 length < maxAttributeValueSize;
   529     }
   531     /**
   532      * Checks whether attribute table has enough memory to
   533      * store attribute value with the given length
   534      *
   535      * @param length the length of attribute value is checking to be added to Map.
   536      * @return whether attribute map has enough memory
   537      */
   538     public boolean canAddAttributeToTable(int length) {
   539         return _v.attributeValue.getTotalCharacterCount() + length <
   540                         attributeValueMapTotalCharactersConstraint;
   541     }
   543     /**
   544      * {@inheritDoc}
   545      */
   546     public void setExternalVocabulary(ExternalVocabulary v) {
   547         // Create internal serializer vocabulary
   548         _v = new SerializerVocabulary();
   549         // Set the external vocabulary
   550         SerializerVocabulary ev = new SerializerVocabulary(v.vocabulary,
   551                 _useLocalNameAsKeyForQualifiedNameLookup);
   552         _v.setExternalVocabulary(v.URI,
   553                 ev, false);
   555         _vIsInternal = true;
   556     }
   558     /**
   559      * {@inheritDoc}
   560      */
   561     public void setVocabularyApplicationData(VocabularyApplicationData data) {
   562         _vData = data;
   563     }
   565     /**
   566      * {@inheritDoc}
   567      */
   568     public VocabularyApplicationData getVocabularyApplicationData() {
   569         return _vData;
   570     }
   572     // End of FastInfosetSerializer interface
   574     /**
   575      * Reset the encoder for reuse encoding another XML infoset.
   576      */
   577     public void reset() {
   578         _terminate = false;
   579     }
   581     /**
   582      * Set the OutputStream to encode the XML infoset to a
   583      * fast infoset document.
   584      *
   585      * @param s the OutputStream where the fast infoset document is written to.
   586      */
   587     public void setOutputStream(OutputStream s) {
   588         _octetBufferIndex = 0;
   589         _markIndex = -1;
   590         _s = s;
   591     }
   593     /**
   594      * Set the SerializerVocabulary to be used for encoding.
   595      *
   596      * @param vocabulary the vocabulary to be used for encoding.
   597      */
   598     public void setVocabulary(SerializerVocabulary vocabulary) {
   599         _v = vocabulary;
   600         _vIsInternal = false;
   601     }
   603     /**
   604      * Encode the header of a fast infoset document.
   605      *
   606      * @param encodeXmlDecl true if the XML declaration should be encoded.
   607      */
   608     protected final void encodeHeader(boolean encodeXmlDecl) throws IOException {
   609         if (encodeXmlDecl) {
   610             _s.write(EncodingConstants.XML_DECLARATION_VALUES[0]);
   611         }
   612         _s.write(EncodingConstants.BINARY_HEADER);
   613     }
   615     /**
   616      * Encode the initial vocabulary of a fast infoset document.
   617      *
   618      */
   619     protected final void encodeInitialVocabulary() throws IOException {
   620         if (_v == null) {
   621             _v = new SerializerVocabulary();
   622             _vIsInternal = true;
   623         } else if (_vIsInternal) {
   624             _v.clear();
   625             if (_vData != null)
   626                 _vData.clear();
   627         }
   629         if (!_v.hasInitialVocabulary() && !_v.hasExternalVocabulary()) {
   630             write(0);
   631         } else if (_v.hasInitialVocabulary()) {
   632             _b = EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG;
   633             write(_b);
   635             SerializerVocabulary initialVocabulary = _v.getReadOnlyVocabulary();
   637             // TODO check for contents of vocabulary to assign bits
   638             if (initialVocabulary.hasExternalVocabulary()) {
   639                 _b = EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG;
   640                 write(_b);
   641                 write(0);
   642             }
   644             if (initialVocabulary.hasExternalVocabulary()) {
   645                 encodeNonEmptyOctetStringOnSecondBit(_v.getExternalVocabularyURI());
   646             }
   648             // TODO check for contents of vocabulary to encode values
   649         } else if (_v.hasExternalVocabulary()) {
   650             _b = EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG;
   651             write(_b);
   653             _b = EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG;
   654             write(_b);
   655             write(0);
   657             encodeNonEmptyOctetStringOnSecondBit(_v.getExternalVocabularyURI());
   658         }
   659     }
   661     /**
   662      * Encode the termination of the Document Information Item.
   663      *
   664      */
   665     protected final void encodeDocumentTermination() throws IOException {
   666         encodeElementTermination();
   667         encodeTermination();
   668         _flush();
   669         _s.flush();
   670     }
   672     /**
   673      * Encode the termination of an Element Information Item.
   674      *
   675      */
   676     protected final void encodeElementTermination() throws IOException {
   677         _terminate = true;
   678         switch (_b) {
   679             case EncodingConstants.TERMINATOR:
   680                 _b = EncodingConstants.DOUBLE_TERMINATOR;
   681                 break;
   682             case EncodingConstants.DOUBLE_TERMINATOR:
   683                 write(EncodingConstants.DOUBLE_TERMINATOR);
   684             default:
   685                 _b = EncodingConstants.TERMINATOR;
   686         }
   687     }
   689     /**
   690      * Encode a termination if required.
   691      *
   692      */
   693     protected final void encodeTermination() throws IOException {
   694         if (_terminate) {
   695             write(_b);
   696             _b = 0;
   697             _terminate = false;
   698         }
   699     }
   701     /**
   702      * Encode a Attribute Information Item that is a namespace declaration.
   703      *
   704      * @param prefix the prefix of the namespace declaration,
   705      * if "" then there is no prefix for the namespace declaration.
   706      * @param uri the URI of the namespace declaration,
   707      * if "" then there is no URI for the namespace declaration.
   708      */
   709     protected final void encodeNamespaceAttribute(String prefix, String uri) throws IOException {
   710         _b = EncodingConstants.NAMESPACE_ATTRIBUTE;
   711         if (prefix.length() > 0) {
   712             _b |= EncodingConstants.NAMESPACE_ATTRIBUTE_PREFIX_FLAG;
   713         }
   714         if (uri.length() > 0) {
   715             _b |= EncodingConstants.NAMESPACE_ATTRIBUTE_NAME_FLAG;
   716         }
   718         // NOTE a prefix with out a namespace name is an undeclaration
   719         // of the namespace bound to the prefix
   720         // TODO needs to investigate how the startPrefixMapping works in
   721         // relation to undeclaration
   723         write(_b);
   725         if (prefix.length() > 0) {
   726             encodeIdentifyingNonEmptyStringOnFirstBit(prefix, _v.prefix);
   727         }
   728         if (uri.length() > 0) {
   729             encodeIdentifyingNonEmptyStringOnFirstBit(uri, _v.namespaceName);
   730         }
   731     }
   733     /**
   734      * Encode a chunk of Character Information Items.
   735      *
   736      * @param ch the array of characters.
   737      * @param offset the offset into the array of characters.
   738      * @param length the length of characters.
   739      * @throws ArrayIndexOutOfBoundsException.
   740      */
   741     protected final void encodeCharacters(char[] ch, int offset, int length) throws IOException {
   742         final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
   743         encodeNonIdentifyingStringOnThirdBit(ch, offset, length, _v.characterContentChunk, addToTable, true);
   744     }
   746     /**
   747      * Encode a chunk of Character Information Items.
   748      *
   749      * If the array of characters is to be indexed (as determined by
   750      * {@link Encoder#characterContentChunkSizeContraint}) then the array is not cloned
   751      * when adding the array to the vocabulary.
   752      *
   753      * @param ch the array of characters.
   754      * @param offset the offset into the array of characters.
   755      * @param length the length of characters.
   756      * @throws ArrayIndexOutOfBoundsException.
   757      */
   758     protected final void encodeCharactersNoClone(char[] ch, int offset, int length) throws IOException {
   759         final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
   760         encodeNonIdentifyingStringOnThirdBit(ch, offset, length, _v.characterContentChunk, addToTable, false);
   761     }
   763     /**
   764      * Encode a chunk of Character Information Items using a numeric
   765      * alphabet that results in the encoding of a character in 4 bits
   766      * (or two characters per octet).
   767      *
   768      * @param id the restricted alphabet identifier.
   769      * @param table the table mapping characters to 4 bit values.
   770      * @param ch the array of characters.
   771      * @param offset the offset into the array of characters.
   772      * @param length the length of characters.
   773      * @param addToTable if characters should be added to table.
   774      * @throws ArrayIndexOutOfBoundsException.
   775      */
   776     protected final void encodeNumericFourBitCharacters(char[] ch, int offset, int length,
   777             boolean addToTable) throws FastInfosetException, IOException {
   778         encodeFourBitCharacters(RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX,
   779                 NUMERIC_CHARACTERS_TABLE, ch, offset, length, addToTable);
   780     }
   782     /**
   783      * Encode a chunk of Character Information Items using a date-time
   784      * alphabet that results in the encoding of a character in 4 bits
   785      * (or two characters per octet).
   786      *
   787      * @param id the restricted alphabet identifier.
   788      * @param table the table mapping characters to 4 bit values.
   789      * @param ch the array of characters.
   790      * @param offset the offset into the array of characters.
   791      * @param length the length of characters.
   792      * @param addToTable if characters should be added to table.
   793      * @throws ArrayIndexOutOfBoundsException.
   794      */
   795     protected final void encodeDateTimeFourBitCharacters(char[] ch, int offset, int length,
   796             boolean addToTable) throws FastInfosetException, IOException {
   797         encodeFourBitCharacters(RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX,
   798                 DATE_TIME_CHARACTERS_TABLE, ch, offset, length, addToTable);
   799     }
   801     /**
   802      * Encode a chunk of Character Information Items using a restricted
   803      * alphabet that results in the encoding of a character in 4 bits
   804      * (or two characters per octet).
   805      *
   806      * @param id the restricted alphabet identifier.
   807      * @param table the table mapping characters to 4 bit values.
   808      * @param ch the array of characters.
   809      * @param offset the offset into the array of characters.
   810      * @param length the length of characters.
   811      * @param addToTable if characters should be added to table.
   812      * @throws ArrayIndexOutOfBoundsException.
   813      */
   814     protected final void encodeFourBitCharacters(int id, int[] table, char[] ch, int offset, int length,
   815             boolean addToTable) throws FastInfosetException, IOException {
   816         if (addToTable) {
   817             // if char array could be added to table
   818             boolean canAddCharacterContentToTable =
   819                     canAddCharacterContentToTable(length, _v.characterContentChunk);
   821             // obtain/get index
   822             int index = canAddCharacterContentToTable ?
   823                 _v.characterContentChunk.obtainIndex(ch, offset, length, true) :
   824                 _v.characterContentChunk.get(ch, offset, length);
   826             if (index != KeyIntMap.NOT_PRESENT) {
   827                 // if char array is in table
   828                 _b = EncodingConstants.CHARACTER_CHUNK | 0x20;
   829                 encodeNonZeroIntegerOnFourthBit(index);
   830                 return;
   831             } else if (canAddCharacterContentToTable) {
   832                 // if char array is not in table, but could be added
   833                 _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG | EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG;
   834             } else {
   835                 // if char array is not in table and could not be added
   836                 _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
   837             }
   838         } else {
   839             _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
   840         }
   842         write (_b);
   844         // Encode bottom 6 bits of enoding algorithm id
   845         _b = id << 2;
   847         encodeNonEmptyFourBitCharacterStringOnSeventhBit(table, ch, offset, length);
   848     }
   850     /**
   851      * Encode a chunk of Character Information Items using a restricted
   852      * alphabet table.
   853      *
   854      * @param alphabet the alphabet defining the mapping between characters and
   855      *        integer values.
   856      * @param ch the array of characters.
   857      * @param offset the offset into the array of characters.
   858      * @param length the length of characters.
   859      * @param addToTable if characters should be added to table
   860      * @throws ArrayIndexOutOfBoundsException.
   861      * @throws FastInfosetException if the alphabet is not present in the
   862      *         vocabulary.
   863      */
   864     protected final void encodeAlphabetCharacters(String alphabet, char[] ch, int offset, int length,
   865             boolean addToTable) throws FastInfosetException, IOException {
   866         if (addToTable) {
   867             // if char array could be added to table
   868             boolean canAddCharacterContentToTable =
   869                     canAddCharacterContentToTable(length, _v.characterContentChunk);
   871             // obtain/get index
   872             int index = canAddCharacterContentToTable ?
   873                 _v.characterContentChunk.obtainIndex(ch, offset, length, true) :
   874                 _v.characterContentChunk.get(ch, offset, length);
   876             if (index != KeyIntMap.NOT_PRESENT) {
   877                 // if char array is in table
   878                 _b = EncodingConstants.CHARACTER_CHUNK | 0x20;
   879                 encodeNonZeroIntegerOnFourthBit(index);
   880                 return;
   881             } else if (canAddCharacterContentToTable) {
   882                 // if char array is not in table, but could be added
   883                 _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG | EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG;
   884             } else {
   885                 // if char array is not in table and could not be added
   886                 _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
   887             }
   888         } else {
   889             _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
   890         }
   892         int id = _v.restrictedAlphabet.get(alphabet);
   893         if (id == KeyIntMap.NOT_PRESENT) {
   894             throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.restrictedAlphabetNotPresent"));
   895         }
   896         id += EncodingConstants.RESTRICTED_ALPHABET_APPLICATION_START;
   898         _b |= (id & 0xC0) >> 6;
   899         write(_b);
   901         // Encode bottom 6 bits of enoding algorithm id
   902         _b = (id & 0x3F) << 2;
   904         encodeNonEmptyNBitCharacterStringOnSeventhBit(alphabet, ch, offset, length);
   905     }
   907     /**
   908      * Encode a Processing Instruction Information Item.
   909      *
   910      * @param target the target of the processing instruction.
   911      * @param data the data of the processing instruction.
   912      */
   913     protected final void encodeProcessingInstruction(String target, String data) throws IOException {
   914         write(EncodingConstants.PROCESSING_INSTRUCTION);
   916         // Target
   917         encodeIdentifyingNonEmptyStringOnFirstBit(target, _v.otherNCName);
   919         // Data
   920         boolean addToTable = isCharacterContentChunkLengthMatchesLimit(data.length());
   921         encodeNonIdentifyingStringOnFirstBit(data, _v.otherString, addToTable);
   922     }
   924     /**
   925      * Encode a Document Type Declaration.
   926      *
   927      * @param systemId the system identifier of the external subset.
   928      * @param publicId the public identifier of the external subset.
   929      */
   930     protected final void encodeDocumentTypeDeclaration(String systemId, String publicId) throws IOException {
   931         _b = EncodingConstants.DOCUMENT_TYPE_DECLARATION;
   932         if (systemId != null && systemId.length() > 0) {
   933             _b |= EncodingConstants.DOCUMENT_TYPE_SYSTEM_IDENTIFIER_FLAG;
   934         }
   935         if (publicId != null && publicId.length() > 0) {
   936             _b |= EncodingConstants.DOCUMENT_TYPE_PUBLIC_IDENTIFIER_FLAG;
   937         }
   938         write(_b);
   940         if (systemId != null && systemId.length() > 0) {
   941             encodeIdentifyingNonEmptyStringOnFirstBit(systemId, _v.otherURI);
   942         }
   943         if (publicId != null && publicId.length() > 0) {
   944             encodeIdentifyingNonEmptyStringOnFirstBit(publicId, _v.otherURI);
   945         }
   946     }
   948     /**
   949      * Encode a Comment Information Item.
   950      *
   951      * @param ch the array of characters that is as comment.
   952      * @param offset the offset into the array of characters.
   953      * @param length the length of characters.
   954      * @throws ArrayIndexOutOfBoundsException.
   955      */
   956     protected final void encodeComment(char[] ch, int offset, int length) throws IOException {
   957         write(EncodingConstants.COMMENT);
   959         boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
   960         encodeNonIdentifyingStringOnFirstBit(ch, offset, length, _v.otherString, addToTable, true);
   961     }
   963     /**
   964      * Encode a Comment Information Item.
   965      *
   966      * If the array of characters that is a comment is to be indexed (as
   967      * determined by {@link Encoder#characterContentChunkSizeContraint}) then
   968      * the array is not cloned when adding the array to the vocabulary.
   969      *
   970      * @param ch the array of characters.
   971      * @param offset the offset into the array of characters.
   972      * @param length the length of characters.
   973      * @throws ArrayIndexOutOfBoundsException.
   974      */
   975     protected final void encodeCommentNoClone(char[] ch, int offset, int length) throws IOException {
   976         write(EncodingConstants.COMMENT);
   978         boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
   979         encodeNonIdentifyingStringOnFirstBit(ch, offset, length, _v.otherString, addToTable, false);
   980     }
   982     /**
   983      * Encode a qualified name of an Element Informaiton Item on the third bit
   984      * of an octet.
   985      * Implementation of clause C.18 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
   986      *
   987      * <p>
   988      * The index of the qualified name will be encoded if the name is present
   989      * in the vocabulary otherwise the qualified name will be encoded literally
   990      * (see {@link #encodeLiteralElementQualifiedNameOnThirdBit}).
   991      *
   992      * @param namespaceURI the namespace URI of the qualified name.
   993      * @param prefix the prefix of the qualified name.
   994      * @param localName the local name of the qualified name.
   995      */
   996     protected final void encodeElementQualifiedNameOnThirdBit(String namespaceURI, String prefix, String localName) throws IOException {
   997         LocalNameQualifiedNamesMap.Entry entry = _v.elementName.obtainEntry(localName);
   998         if (entry._valueIndex > 0) {
   999             QualifiedName[] names = entry._value;
  1000             for (int i = 0; i < entry._valueIndex; i++) {
  1001                 if ((prefix == names[i].prefix || prefix.equals(names[i].prefix))
  1002                         && (namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) {
  1003                     encodeNonZeroIntegerOnThirdBit(names[i].index);
  1004                     return;
  1009         encodeLiteralElementQualifiedNameOnThirdBit(namespaceURI, prefix,
  1010                 localName, entry);
  1013     /**
  1014      * Encode a literal qualified name of an Element Informaiton Item on the
  1015      * third bit of an octet.
  1016      * Implementation of clause C.18 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1018      * @param namespaceURI the namespace URI of the qualified name.
  1019      * @param prefix the prefix of the qualified name.
  1020      * @param localName the local name of the qualified name.
  1021      */
  1022     protected final void encodeLiteralElementQualifiedNameOnThirdBit(String namespaceURI, String prefix, String localName,
  1023             LocalNameQualifiedNamesMap.Entry entry) throws IOException {
  1024         QualifiedName name = new QualifiedName(prefix, namespaceURI, localName, "", _v.elementName.getNextIndex());
  1025         entry.addQualifiedName(name);
  1027         int namespaceURIIndex = KeyIntMap.NOT_PRESENT;
  1028         int prefixIndex = KeyIntMap.NOT_PRESENT;
  1029         if (namespaceURI.length() > 0) {
  1030             namespaceURIIndex = _v.namespaceName.get(namespaceURI);
  1031             if (namespaceURIIndex == KeyIntMap.NOT_PRESENT) {
  1032                 throw new IOException(CommonResourceBundle.getInstance().getString("message.namespaceURINotIndexed", new Object[]{namespaceURI}));
  1035             if (prefix.length() > 0) {
  1036                 prefixIndex = _v.prefix.get(prefix);
  1037                 if (prefixIndex == KeyIntMap.NOT_PRESENT) {
  1038                     throw new IOException(CommonResourceBundle.getInstance().getString("message.prefixNotIndexed", new Object[]{prefix}));
  1043         int localNameIndex = _v.localName.obtainIndex(localName);
  1045         _b |= EncodingConstants.ELEMENT_LITERAL_QNAME_FLAG;
  1046         if (namespaceURIIndex >= 0) {
  1047             _b |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG;
  1048             if (prefixIndex >= 0) {
  1049                 _b |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG;
  1052         write(_b);
  1054         if (namespaceURIIndex >= 0) {
  1055             if (prefixIndex >= 0) {
  1056                 encodeNonZeroIntegerOnSecondBitFirstBitOne(prefixIndex);
  1058             encodeNonZeroIntegerOnSecondBitFirstBitOne(namespaceURIIndex);
  1061         if (localNameIndex >= 0) {
  1062             encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex);
  1063         } else {
  1064             encodeNonEmptyOctetStringOnSecondBit(localName);
  1068     /**
  1069      * Encode a qualified name of an Attribute Informaiton Item on the third bit
  1070      * of an octet.
  1071      * Implementation of clause C.17 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1073      * <p>
  1074      * The index of the qualified name will be encoded if the name is present
  1075      * in the vocabulary otherwise the qualified name will be encoded literally
  1076      * (see {@link #encodeLiteralAttributeQualifiedNameOnSecondBit}).
  1078      * @param namespaceURI the namespace URI of the qualified name.
  1079      * @param prefix the prefix of the qualified name.
  1080      * @param localName the local name of the qualified name.
  1081      */
  1082     protected final void encodeAttributeQualifiedNameOnSecondBit(String namespaceURI, String prefix, String localName) throws IOException {
  1083         LocalNameQualifiedNamesMap.Entry entry = _v.attributeName.obtainEntry(localName);
  1084         if (entry._valueIndex > 0) {
  1085             QualifiedName[] names = entry._value;
  1086             for (int i = 0; i < entry._valueIndex; i++) {
  1087                 if ((prefix == names[i].prefix || prefix.equals(names[i].prefix))
  1088                         && (namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) {
  1089                     encodeNonZeroIntegerOnSecondBitFirstBitZero(names[i].index);
  1090                     return;
  1095         encodeLiteralAttributeQualifiedNameOnSecondBit(namespaceURI, prefix,
  1096                 localName, entry);
  1099     /**
  1100      * Encode a literal qualified name of an Attribute Informaiton Item on the
  1101      * third bit of an octet.
  1102      * Implementation of clause C.17 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1104      * @param namespaceURI the namespace URI of the qualified name.
  1105      * @param prefix the prefix of the qualified name.
  1106      * @param localName the local name of the qualified name.
  1107      */
  1108     protected final boolean encodeLiteralAttributeQualifiedNameOnSecondBit(String namespaceURI, String prefix, String localName,
  1109                 LocalNameQualifiedNamesMap.Entry entry) throws IOException {
  1110         int namespaceURIIndex = KeyIntMap.NOT_PRESENT;
  1111         int prefixIndex = KeyIntMap.NOT_PRESENT;
  1112         if (namespaceURI.length() > 0) {
  1113             namespaceURIIndex = _v.namespaceName.get(namespaceURI);
  1114             if (namespaceURIIndex == KeyIntMap.NOT_PRESENT) {
  1115                 if (namespaceURI == EncodingConstants.XMLNS_NAMESPACE_NAME ||
  1116                         namespaceURI.equals(EncodingConstants.XMLNS_NAMESPACE_NAME)) {
  1117                     return false;
  1118                 } else {
  1119                     throw new IOException(CommonResourceBundle.getInstance().getString("message.namespaceURINotIndexed", new Object[]{namespaceURI}));
  1123             if (prefix.length() > 0) {
  1124                 prefixIndex = _v.prefix.get(prefix);
  1125                 if (prefixIndex == KeyIntMap.NOT_PRESENT) {
  1126                     throw new IOException(CommonResourceBundle.getInstance().getString("message.prefixNotIndexed", new Object[]{prefix}));
  1131         int localNameIndex = _v.localName.obtainIndex(localName);
  1133         QualifiedName name = new QualifiedName(prefix, namespaceURI, localName, "", _v.attributeName.getNextIndex());
  1134         entry.addQualifiedName(name);
  1136         _b = EncodingConstants.ATTRIBUTE_LITERAL_QNAME_FLAG;
  1137         if (namespaceURI.length() > 0) {
  1138             _b |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG;
  1139             if (prefix.length() > 0) {
  1140                 _b |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG;
  1144         write(_b);
  1146         if (namespaceURIIndex >= 0) {
  1147             if (prefixIndex >= 0) {
  1148                 encodeNonZeroIntegerOnSecondBitFirstBitOne(prefixIndex);
  1150             encodeNonZeroIntegerOnSecondBitFirstBitOne(namespaceURIIndex);
  1151         } else if (namespaceURI != "") {
  1152             // XML prefix and namespace name
  1153             encodeNonEmptyOctetStringOnSecondBit("xml");
  1154             encodeNonEmptyOctetStringOnSecondBit("http://www.w3.org/XML/1998/namespace");
  1157         if (localNameIndex >= 0) {
  1158             encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex);
  1159         } else {
  1160             encodeNonEmptyOctetStringOnSecondBit(localName);
  1163         return true;
  1166     /**
  1167      * Encode a non identifying string on the first bit of an octet.
  1168      * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1170      * @param s the string to encode
  1171      * @param map the vocabulary table of strings to indexes.
  1172      * @param addToTable true if the string could be added to the vocabulary
  1173      *                   table (if table has enough memory)
  1174      * @param mustBeAddedToTable true if the string must be added to the vocabulary
  1175      *                   table (if not already present in the table).
  1176      */
  1177     protected final void encodeNonIdentifyingStringOnFirstBit(String s, StringIntMap map,
  1178             boolean addToTable, boolean mustBeAddedToTable) throws IOException {
  1179         if (s == null || s.length() == 0) {
  1180             // C.26 an index (first bit '1') with seven '1' bits for an empty string
  1181             write(0xFF);
  1182         } else {
  1183             if (addToTable || mustBeAddedToTable) {
  1184                 // if attribute value could be added to table
  1185                 boolean canAddAttributeToTable = mustBeAddedToTable ||
  1186                         canAddAttributeToTable(s.length());
  1188                 // obtain/get index
  1189                 int index = canAddAttributeToTable ?
  1190                     map.obtainIndex(s) :
  1191                     map.get(s);
  1193                 if (index != KeyIntMap.NOT_PRESENT) {
  1194                     // if attribute value is in table
  1195                     encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
  1196                 } else if (canAddAttributeToTable) {
  1197                     // if attribute value is not in table, but could be added
  1198                     _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG |
  1199                             _nonIdentifyingStringOnFirstBitCES;
  1200                     encodeNonEmptyCharacterStringOnFifthBit(s);
  1201                 } else {
  1202                     // if attribute value is not in table and could not be added
  1203                     _b = _nonIdentifyingStringOnFirstBitCES;
  1204                     encodeNonEmptyCharacterStringOnFifthBit(s);
  1206             } else {
  1207                 _b = _nonIdentifyingStringOnFirstBitCES;
  1208                 encodeNonEmptyCharacterStringOnFifthBit(s);
  1213     /**
  1214      * Encode a non identifying string on the first bit of an octet.
  1215      * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1217      * @param s the string to encode
  1218      * @param map the vocabulary table of character arrays to indexes.
  1219      * @param addToTable true if the string should be added to the vocabulary
  1220      *                   table (if not already present in the table).
  1221      */
  1222     protected final void encodeNonIdentifyingStringOnFirstBit(String s, CharArrayIntMap map, boolean addToTable) throws IOException {
  1223         if (s == null || s.length() == 0) {
  1224             // C.26 an index (first bit '1') with seven '1' bits for an empty string
  1225             write(0xFF);
  1226         } else {
  1227             if (addToTable) {
  1228                 final char[] ch = s.toCharArray();
  1229                 final int length = s.length();
  1231                 // if char array could be added to table
  1232                 boolean canAddCharacterContentToTable =
  1233                         canAddCharacterContentToTable(length, map);
  1235                 // obtain/get index
  1236                 int index = canAddCharacterContentToTable ?
  1237                     map.obtainIndex(ch, 0, length, false) :
  1238                     map.get(ch, 0, length);
  1240                 if (index != KeyIntMap.NOT_PRESENT) {
  1241                     // if char array is in table
  1242                     encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
  1243                 } else if (canAddCharacterContentToTable) {
  1244                     // if char array is not in table, but could be added
  1245                     _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG |
  1246                             _nonIdentifyingStringOnFirstBitCES;
  1247                     encodeNonEmptyCharacterStringOnFifthBit(ch, 0, length);
  1248                 } else {
  1249                     // if char array is not in table and could not be added
  1250                     _b = _nonIdentifyingStringOnFirstBitCES;
  1251                     encodeNonEmptyCharacterStringOnFifthBit(s);
  1253             } else {
  1254                 _b = _nonIdentifyingStringOnFirstBitCES;
  1255                 encodeNonEmptyCharacterStringOnFifthBit(s);
  1260     /**
  1261      * Encode a non identifying string on the first bit of an octet.
  1262      * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1264      * @param ch the array of characters.
  1265      * @param offset the offset into the array of characters.
  1266      * @param length the length of characters.
  1267      * @param map the vocabulary table of character arrays to indexes.
  1268      * @param addToTable true if the string should be added to the vocabulary
  1269      *                   table (if not already present in the table).
  1270      * @param clone true if the array of characters should be cloned if added
  1271      *              to the vocabulary table.
  1272      */
  1273     protected final void encodeNonIdentifyingStringOnFirstBit(char[] ch, int offset, int length, CharArrayIntMap map,
  1274             boolean addToTable, boolean clone) throws IOException {
  1275         if (length == 0) {
  1276             // C.26 an index (first bit '1') with seven '1' bits for an empty string
  1277             write(0xFF);
  1278         } else {
  1279             if (addToTable) {
  1280                 // if char array could be added to table
  1281                 boolean canAddCharacterContentToTable =
  1282                         canAddCharacterContentToTable(length, map);
  1284                 // obtain/get index
  1285                 int index = canAddCharacterContentToTable ?
  1286                     map.obtainIndex(ch, offset, length, clone) :
  1287                     map.get(ch, offset, length);
  1289                 if (index != KeyIntMap.NOT_PRESENT) {
  1290                     // if char array is in table
  1291                     encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
  1292                 } else if (canAddCharacterContentToTable) {
  1293                     // if char array is not in table, but could be added
  1294                     _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG |
  1295                             _nonIdentifyingStringOnFirstBitCES;
  1296                     encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length);
  1297                 } else {
  1298                     // if char array is not in table and could not be added
  1299                     _b = _nonIdentifyingStringOnFirstBitCES;
  1300                     encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length);
  1302             } else {
  1303                 _b = _nonIdentifyingStringOnFirstBitCES;
  1304                 encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length);
  1309     protected final void encodeNumericNonIdentifyingStringOnFirstBit(
  1310             String s, boolean addToTable, boolean mustBeAddedToTable)
  1311             throws IOException, FastInfosetException {
  1312         encodeNonIdentifyingStringOnFirstBit(
  1313                                     RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX,
  1314                                     NUMERIC_CHARACTERS_TABLE, s, addToTable,
  1315                                     mustBeAddedToTable);
  1318     protected final void encodeDateTimeNonIdentifyingStringOnFirstBit(
  1319             String s, boolean addToTable, boolean mustBeAddedToTable)
  1320             throws IOException, FastInfosetException {
  1321         encodeNonIdentifyingStringOnFirstBit(
  1322                                     RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX,
  1323                                     DATE_TIME_CHARACTERS_TABLE, s, addToTable,
  1324                                     mustBeAddedToTable);
  1327     protected final void encodeNonIdentifyingStringOnFirstBit(int id, int[] table,
  1328             String s, boolean addToTable, boolean mustBeAddedToTable)
  1329             throws IOException, FastInfosetException {
  1330         if (s == null || s.length() == 0) {
  1331             // C.26 an index (first bit '1') with seven '1' bits for an empty string
  1332             write(0xFF);
  1333             return;
  1336         if (addToTable || mustBeAddedToTable) {
  1337             // if attribute value could be added to table
  1338             boolean canAddAttributeToTable = mustBeAddedToTable ||
  1339                     canAddAttributeToTable(s.length());
  1341             // obtain/get index
  1342             int index = canAddAttributeToTable ?
  1343                 _v.attributeValue.obtainIndex(s) :
  1344                 _v.attributeValue.get(s);
  1346             if (index != KeyIntMap.NOT_PRESENT) {
  1347                 // if attribute value is in table
  1348                 encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
  1349                 return;
  1350             } else if (canAddAttributeToTable) {
  1351                 // if attribute value is not in table, but could be added
  1352                 _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG |
  1353                         EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG;
  1354             } else {
  1355                 // if attribute value is not in table and could not be added
  1356                 _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG;
  1358         } else {
  1359             _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG;
  1362         // Encode identification and top four bits of alphabet id
  1363         write (_b | ((id & 0xF0) >> 4));
  1364         // Encode bottom 4 bits of alphabet id
  1365         _b = (id & 0x0F) << 4;
  1367         final int length = s.length();
  1368         final int octetPairLength = length / 2;
  1369         final int octetSingleLength = length % 2;
  1370         encodeNonZeroOctetStringLengthOnFifthBit(octetPairLength + octetSingleLength);
  1371         encodeNonEmptyFourBitCharacterString(table, s.toCharArray(), 0, octetPairLength, octetSingleLength);
  1374     /**
  1375      * Encode a non identifying string on the first bit of an octet as binary
  1376      * data using an encoding algorithm.
  1377      * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1379      * @param URI the encoding algorithm URI. If the URI == null then the
  1380      *            encoding algorithm identifier takes precendence.
  1381      * @param id the encoding algorithm identifier.
  1382      * @param data the data to be encoded using an encoding algorithm.
  1383      * @throws EncodingAlgorithmException if the encoding algorithm URI is not
  1384      *         present in the vocabulary, or the encoding algorithm identifier
  1385      *         is not with the required range.
  1386      */
  1387     protected final void encodeNonIdentifyingStringOnFirstBit(String URI, int id, Object data) throws FastInfosetException, IOException {
  1388         if (URI != null) {
  1389             id = _v.encodingAlgorithm.get(URI);
  1390             if (id == KeyIntMap.NOT_PRESENT) {
  1391                 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI}));
  1393             id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START;
  1395             EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI);
  1396             if (ea != null) {
  1397                 encodeAIIObjectAlgorithmData(id, data, ea);
  1398             } else {
  1399                 if (data instanceof byte[]) {
  1400                     byte[] d = (byte[])data;
  1401                     encodeAIIOctetAlgorithmData(id, d, 0, d.length);
  1402                 } else {
  1403                     throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
  1406         } else if (id <= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) {
  1407             int length = 0;
  1408             switch(id) {
  1409                 case EncodingAlgorithmIndexes.HEXADECIMAL:
  1410                 case EncodingAlgorithmIndexes.BASE64:
  1411                     length = ((byte[])data).length;
  1412                     break;
  1413                 case EncodingAlgorithmIndexes.SHORT:
  1414                     length = ((short[])data).length;
  1415                     break;
  1416                 case EncodingAlgorithmIndexes.INT:
  1417                     length = ((int[])data).length;
  1418                     break;
  1419                 case EncodingAlgorithmIndexes.LONG:
  1420                 case EncodingAlgorithmIndexes.UUID:
  1421                     length = ((long[])data).length;
  1422                     break;
  1423                 case EncodingAlgorithmIndexes.BOOLEAN:
  1424                     length = ((boolean[])data).length;
  1425                     break;
  1426                 case EncodingAlgorithmIndexes.FLOAT:
  1427                     length = ((float[])data).length;
  1428                     break;
  1429                 case EncodingAlgorithmIndexes.DOUBLE:
  1430                     length = ((double[])data).length;
  1431                     break;
  1432                 case EncodingAlgorithmIndexes.CDATA:
  1433                     throw new UnsupportedOperationException(CommonResourceBundle.getInstance().getString("message.CDATA"));
  1434                 default:
  1435                     throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.UnsupportedBuiltInAlgorithm", new Object[]{Integer.valueOf(id)}));
  1437             encodeAIIBuiltInAlgorithmData(id, data, 0, length);
  1438         } else if (id >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) {
  1439             if (data instanceof byte[]) {
  1440                 byte[] d = (byte[])data;
  1441                 encodeAIIOctetAlgorithmData(id, d, 0, d.length);
  1442             } else {
  1443                 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
  1445         } else {
  1446             throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved"));
  1450     /**
  1451      * Encode the [normalized value] of an Attribute Information Item using
  1452      * using an encoding algorithm.
  1453      * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1455      * @param id the encoding algorithm identifier.
  1456      * @param d the data, as an array of bytes, to be encoded.
  1457      * @param offset the offset into the array of bytes.
  1458      * @param length the length of bytes.
  1459      */
  1460     protected final void encodeAIIOctetAlgorithmData(int id, byte[] d, int offset, int length) throws IOException {
  1461         // Encode identification and top four bits of encoding algorithm id
  1462         write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG |
  1463                 ((id & 0xF0) >> 4));
  1465         // Encode bottom 4 bits of enoding algorithm id
  1466         _b = (id & 0x0F) << 4;
  1468         // Encode the length
  1469         encodeNonZeroOctetStringLengthOnFifthBit(length);
  1471         write(d, offset, length);
  1474     /**
  1475      * Encode the [normalized value] of an Attribute Information Item using
  1476      * using an encoding algorithm.
  1477      * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1479      * @param id the encoding algorithm identifier.
  1480      * @param data the data to be encoded using an encoding algorithm.
  1481      * @param ea the encoding algorithm to use to encode the data into an
  1482      *           array of bytes.
  1483      */
  1484     protected final void encodeAIIObjectAlgorithmData(int id, Object data, EncodingAlgorithm ea) throws FastInfosetException, IOException {
  1485         // Encode identification and top four bits of encoding algorithm id
  1486         write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG |
  1487                 ((id & 0xF0) >> 4));
  1489         // Encode bottom 4 bits of enoding algorithm id
  1490         _b = (id & 0x0F) << 4;
  1492         _encodingBufferOutputStream.reset();
  1493         ea.encodeToOutputStream(data, _encodingBufferOutputStream);
  1494         encodeNonZeroOctetStringLengthOnFifthBit(_encodingBufferIndex);
  1495         write(_encodingBuffer, _encodingBufferIndex);
  1498     /**
  1499      * Encode the [normalized value] of an Attribute Information Item using
  1500      * using a built in encoding algorithm.
  1501      * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1503      * @param id the built in encoding algorithm identifier.
  1504      * @param data the data to be encoded using an encoding algorithm. The data
  1505      *        represents an array of items specified by the encoding algorithm
  1506      *        identifier
  1507      * @param offset the offset into the array of bytes.
  1508      * @param length the length of bytes.
  1509      */
  1510     protected final void encodeAIIBuiltInAlgorithmData(int id, Object data, int offset, int length) throws IOException {
  1511         // Encode identification and top four bits of encoding algorithm id
  1512         write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG |
  1513                 ((id & 0xF0) >> 4));
  1515         // Encode bottom 4 bits of enoding algorithm id
  1516         _b = (id & 0x0F) << 4;
  1518         final int octetLength = BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
  1519                     getOctetLengthFromPrimitiveLength(length);
  1521         encodeNonZeroOctetStringLengthOnFifthBit(octetLength);
  1523         ensureSize(octetLength);
  1524         BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
  1525                 encodeToBytes(data, offset, length, _octetBuffer, _octetBufferIndex);
  1526         _octetBufferIndex += octetLength;
  1529     /**
  1530      * Encode a non identifying string on the third bit of an octet.
  1531      * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1533      * @param ch the array of characters.
  1534      * @param offset the offset into the array of characters.
  1535      * @param length the length of characters.
  1536      * @param map the vocabulary table of character arrays to indexes.
  1537      * @param addToTable true if the array of characters should be added to the vocabulary
  1538      *                   table (if not already present in the table).
  1539      * @param clone true if the array of characters should be cloned if added
  1540      *              to the vocabulary table.
  1541      */
  1542     protected final void encodeNonIdentifyingStringOnThirdBit(char[] ch, int offset, int length,
  1543             CharArrayIntMap map, boolean addToTable, boolean clone) throws IOException {
  1544         // length cannot be zero since sequence of CIIs has to be > 0
  1546         if (addToTable) {
  1547             // if char array could be added to table
  1548             boolean canAddCharacterContentToTable =
  1549                     canAddCharacterContentToTable(length, map);
  1551             // obtain/get index
  1552             int index = canAddCharacterContentToTable ?
  1553                 map.obtainIndex(ch, offset, length, clone) :
  1554                 map.get(ch, offset, length);
  1556             if (index != KeyIntMap.NOT_PRESENT) {
  1557                 // if char array is in table
  1558                 _b = EncodingConstants.CHARACTER_CHUNK | 0x20;
  1559                 encodeNonZeroIntegerOnFourthBit(index);
  1560             } else if (canAddCharacterContentToTable) {
  1561                 // if char array is not in table, but could be added
  1562                 _b = EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG |
  1563                         _nonIdentifyingStringOnThirdBitCES;
  1564                 encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length);
  1565             } else {
  1566                 // if char array is not in table and could not be added
  1567                     _b = _nonIdentifyingStringOnThirdBitCES;
  1568                     encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length);
  1570         } else {
  1571             // char array will not be added to map
  1572             _b = _nonIdentifyingStringOnThirdBitCES;
  1573             encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length);
  1577     /**
  1578      * Encode a non identifying string on the third bit of an octet as binary
  1579      * data using an encoding algorithm.
  1580      * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1582      * @param URI the encoding algorithm URI. If the URI == null then the
  1583      *            encoding algorithm identifier takes precendence.
  1584      * @param id the encoding algorithm identifier.
  1585      * @param data the data to be encoded using an encoding algorithm.
  1586      * @throws EncodingAlgorithmException if the encoding algorithm URI is not
  1587      *         present in the vocabulary, or the encoding algorithm identifier
  1588      *         is not with the required range.
  1589      */
  1590     protected final void encodeNonIdentifyingStringOnThirdBit(String URI, int id, Object data) throws FastInfosetException, IOException {
  1591         if (URI != null) {
  1592             id = _v.encodingAlgorithm.get(URI);
  1593             if (id == KeyIntMap.NOT_PRESENT) {
  1594                 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI}));
  1596             id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START;
  1598             EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI);
  1599             if (ea != null) {
  1600                 encodeCIIObjectAlgorithmData(id, data, ea);
  1601             } else {
  1602                 if (data instanceof byte[]) {
  1603                     byte[] d = (byte[])data;
  1604                     encodeCIIOctetAlgorithmData(id, d, 0, d.length);
  1605                 } else {
  1606                     throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
  1609         } else if (id <= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) {
  1610             int length = 0;
  1611             switch(id) {
  1612                 case EncodingAlgorithmIndexes.HEXADECIMAL:
  1613                 case EncodingAlgorithmIndexes.BASE64:
  1614                     length = ((byte[])data).length;
  1615                     break;
  1616                 case EncodingAlgorithmIndexes.SHORT:
  1617                     length = ((short[])data).length;
  1618                     break;
  1619                 case EncodingAlgorithmIndexes.INT:
  1620                     length = ((int[])data).length;
  1621                     break;
  1622                 case EncodingAlgorithmIndexes.LONG:
  1623                 case EncodingAlgorithmIndexes.UUID:
  1624                     length = ((long[])data).length;
  1625                     break;
  1626                 case EncodingAlgorithmIndexes.BOOLEAN:
  1627                     length = ((boolean[])data).length;
  1628                     break;
  1629                 case EncodingAlgorithmIndexes.FLOAT:
  1630                     length = ((float[])data).length;
  1631                     break;
  1632                 case EncodingAlgorithmIndexes.DOUBLE:
  1633                     length = ((double[])data).length;
  1634                     break;
  1635                 case EncodingAlgorithmIndexes.CDATA:
  1636                     throw new UnsupportedOperationException(CommonResourceBundle.getInstance().getString("message.CDATA"));
  1637                 default:
  1638                     throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.UnsupportedBuiltInAlgorithm", new Object[]{Integer.valueOf(id)}));
  1640             encodeCIIBuiltInAlgorithmData(id, data, 0, length);
  1641         } else if (id >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) {
  1642             if (data instanceof byte[]) {
  1643                 byte[] d = (byte[])data;
  1644                 encodeCIIOctetAlgorithmData(id, d, 0, d.length);
  1645             } else {
  1646                 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
  1648         } else {
  1649             throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved"));
  1653     /**
  1654      * Encode a non identifying string on the third bit of an octet as binary
  1655      * data using an encoding algorithm.
  1656      * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1658      * @param URI the encoding algorithm URI. If the URI == null then the
  1659      *            encoding algorithm identifier takes precendence.
  1660      * @param id the encoding algorithm identifier.
  1661      * @param d the data, as an array of bytes, to be encoded.
  1662      * @param offset the offset into the array of bytes.
  1663      * @param length the length of bytes.
  1664      * @throws EncodingAlgorithmException if the encoding algorithm URI is not
  1665      *         present in the vocabulary.
  1666      */
  1667     protected final void encodeNonIdentifyingStringOnThirdBit(String URI, int id, byte[] d, int offset, int length) throws FastInfosetException, IOException {
  1668         if (URI != null) {
  1669             id = _v.encodingAlgorithm.get(URI);
  1670             if (id == KeyIntMap.NOT_PRESENT) {
  1671                 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI}));
  1673             id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START;
  1676         encodeCIIOctetAlgorithmData(id, d, offset, length);
  1679     /**
  1680      * Encode a chunk of Character Information Items using
  1681      * using an encoding algorithm.
  1682      * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1684      * @param id the encoding algorithm identifier.
  1685      * @param d the data, as an array of bytes, to be encoded.
  1686      * @param offset the offset into the array of bytes.
  1687      * @param length the length of bytes.
  1688      */
  1689     protected final void encodeCIIOctetAlgorithmData(int id, byte[] d, int offset, int length) throws IOException {
  1690         // Encode identification and top two bits of encoding algorithm id
  1691         write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG |
  1692                 ((id & 0xC0) >> 6));
  1694         // Encode bottom 6 bits of enoding algorithm id
  1695         _b = (id & 0x3F) << 2;
  1697         // Encode the length
  1698         encodeNonZeroOctetStringLengthOnSenventhBit(length);
  1700         write(d, offset, length);
  1703     /**
  1704      * Encode a chunk of Character Information Items using
  1705      * using an encoding algorithm.
  1706      * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1708      * @param id the encoding algorithm identifier.
  1709      * @param data the data to be encoded using an encoding algorithm.
  1710      * @param ea the encoding algorithm to use to encode the data into an
  1711      *           array of bytes.
  1712      */
  1713     protected final void encodeCIIObjectAlgorithmData(int id, Object data, EncodingAlgorithm ea) throws FastInfosetException, IOException {
  1714         // Encode identification and top two bits of encoding algorithm id
  1715         write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG |
  1716                 ((id & 0xC0) >> 6));
  1718         // Encode bottom 6 bits of enoding algorithm id
  1719         _b = (id & 0x3F) << 2;
  1721         _encodingBufferOutputStream.reset();
  1722         ea.encodeToOutputStream(data, _encodingBufferOutputStream);
  1723         encodeNonZeroOctetStringLengthOnSenventhBit(_encodingBufferIndex);
  1724         write(_encodingBuffer, _encodingBufferIndex);
  1727     /**
  1728      * Encode a chunk of Character Information Items using
  1729      * using an encoding algorithm.
  1730      * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1732      * @param id the built in encoding algorithm identifier.
  1733      * @param data the data to be encoded using an encoding algorithm. The data
  1734      *        represents an array of items specified by the encoding algorithm
  1735      *        identifier
  1736      * @param offset the offset into the array of bytes.
  1737      * @param length the length of bytes.
  1738      */
  1739     protected final void encodeCIIBuiltInAlgorithmData(int id, Object data, int offset, int length) throws FastInfosetException, IOException {
  1740         // Encode identification and top two bits of encoding algorithm id
  1741         write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG |
  1742                 ((id & 0xC0) >> 6));
  1744         // Encode bottom 6 bits of enoding algorithm id
  1745         _b = (id & 0x3F) << 2;
  1747         final int octetLength = BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
  1748                     getOctetLengthFromPrimitiveLength(length);
  1750         encodeNonZeroOctetStringLengthOnSenventhBit(octetLength);
  1752         ensureSize(octetLength);
  1753         BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
  1754                 encodeToBytes(data, offset, length, _octetBuffer, _octetBufferIndex);
  1755         _octetBufferIndex += octetLength;
  1758     /**
  1759      * Encode a chunk of Character Information Items using
  1760      * using the CDATA built in encoding algorithm.
  1761      * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1763      * @param ch the array of characters.
  1764      * @param offset the offset into the array of characters.
  1765      * @param length the length of characters.
  1766      */
  1767     protected final void encodeCIIBuiltInAlgorithmDataAsCDATA(char[] ch, int offset, int length) throws FastInfosetException, IOException {
  1768         // Encode identification and top two bits of encoding algorithm id
  1769         write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG);
  1771         // Encode bottom 6 bits of enoding algorithm id
  1772         _b = EncodingAlgorithmIndexes.CDATA << 2;
  1775         length = encodeUTF8String(ch, offset, length);
  1776         encodeNonZeroOctetStringLengthOnSenventhBit(length);
  1777         write(_encodingBuffer, length);
  1780     /**
  1781      * Encode a non empty identifying string on the first bit of an octet.
  1782      * Implementation of clause C.13 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1784      * @param s the identifying string.
  1785      * @param map the vocabulary table to use to determin the index of the
  1786      *        identifying string
  1787      */
  1788     protected final void encodeIdentifyingNonEmptyStringOnFirstBit(String s, StringIntMap map) throws IOException {
  1789         int index = map.obtainIndex(s);
  1790         if (index == KeyIntMap.NOT_PRESENT) {
  1791             // _b = 0;
  1792             encodeNonEmptyOctetStringOnSecondBit(s);
  1793         } else {
  1794             // _b = 0x80;
  1795             encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
  1799     /**
  1800      * Encode a non empty string on the second bit of an octet using the UTF-8
  1801      * encoding.
  1802      * Implementation of clause C.22 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1804      * @param s the string.
  1805      */
  1806     protected final void encodeNonEmptyOctetStringOnSecondBit(String s) throws IOException {
  1807         final int length = encodeUTF8String(s);
  1808         encodeNonZeroOctetStringLengthOnSecondBit(length);
  1809         write(_encodingBuffer, length);
  1812     /**
  1813      * Encode the length of a UTF-8 encoded string on the second bit of an octet.
  1814      * Implementation of clause C.22 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1816      * @param length the length to encode.
  1817      */
  1818     protected final void encodeNonZeroOctetStringLengthOnSecondBit(int length) throws IOException {
  1819         if (length < EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT) {
  1820             // [1, 64]
  1821             write(length - 1);
  1822         } else if (length < EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT) {
  1823             // [65, 320]
  1824             write(EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_FLAG); // 010 00000
  1825             write(length - EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT);
  1826         } else {
  1827             // [321, 4294967296]
  1828             write(EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_LARGE_FLAG); // 0110 0000
  1829             length -= EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT;
  1830             write(length >>> 24);
  1831             write((length >> 16) & 0xFF);
  1832             write((length >> 8) & 0xFF);
  1833             write(length & 0xFF);
  1837     /**
  1838      * Encode a non empty string on the fifth bit of an octet using the UTF-8
  1839      * or UTF-16 encoding.
  1840      * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1842      * @param s the string.
  1843      */
  1844     protected final void encodeNonEmptyCharacterStringOnFifthBit(String s) throws IOException {
  1845         final int length = (_encodingStringsAsUtf8) ? encodeUTF8String(s) : encodeUtf16String(s);
  1846         encodeNonZeroOctetStringLengthOnFifthBit(length);
  1847         write(_encodingBuffer, length);
  1850     /**
  1851      * Encode a non empty string on the fifth bit of an octet using the UTF-8
  1852      * or UTF-16 encoding.
  1853      * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1855      * @param ch the array of characters.
  1856      * @param offset the offset into the array of characters.
  1857      * @param length the length of characters.
  1858      */
  1859     protected final void encodeNonEmptyCharacterStringOnFifthBit(char[] ch, int offset, int length) throws IOException {
  1860         length = (_encodingStringsAsUtf8) ? encodeUTF8String(ch, offset, length) : encodeUtf16String(ch, offset, length);
  1861         encodeNonZeroOctetStringLengthOnFifthBit(length);
  1862         write(_encodingBuffer, length);
  1865     /**
  1866      * Encode the length of a UTF-8 or UTF-16 encoded string on the fifth bit
  1867      * of an octet.
  1868      * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1870      * @param length the length to encode.
  1871      */
  1872     protected final void encodeNonZeroOctetStringLengthOnFifthBit(int length) throws IOException {
  1873         if (length < EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT) {
  1874             // [1, 8]
  1875             write(_b | (length - 1));
  1876         } else if (length < EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT) {
  1877             // [9, 264]
  1878             write(_b | EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_FLAG); // 000010 00
  1879             write(length - EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT);
  1880         } else {
  1881             // [265, 4294967296]
  1882             write(_b | EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_LARGE_FLAG); // 000011 00
  1883             length -= EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT;
  1884             write(length >>> 24);
  1885             write((length >> 16) & 0xFF);
  1886             write((length >> 8) & 0xFF);
  1887             write(length & 0xFF);
  1891     /**
  1892      * Encode a non empty string on the seventh bit of an octet using the UTF-8
  1893      * or UTF-16 encoding.
  1894      * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1896      * @param ch the array of characters.
  1897      * @param offset the offset into the array of characters.
  1898      * @param length the length of characters.
  1899      */
  1900     protected final void encodeNonEmptyCharacterStringOnSeventhBit(char[] ch, int offset, int length) throws IOException {
  1901         length = (_encodingStringsAsUtf8) ? encodeUTF8String(ch, offset, length) : encodeUtf16String(ch, offset, length);
  1902         encodeNonZeroOctetStringLengthOnSenventhBit(length);
  1903         write(_encodingBuffer, length);
  1906     /**
  1907      * Encode a non empty string on the seventh bit of an octet using a restricted
  1908      * alphabet that results in the encoding of a character in 4 bits
  1909      * (or two characters per octet).
  1910      * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1912      * @param table the table mapping characters to 4 bit values.
  1913      * @param ch the array of characters.
  1914      * @param offset the offset into the array of characters.
  1915      * @param length the length of characters.
  1916      */
  1917     protected final void encodeNonEmptyFourBitCharacterStringOnSeventhBit(int[] table, char[] ch, int offset, int length) throws FastInfosetException, IOException {
  1918         final int octetPairLength = length / 2;
  1919         final int octetSingleLength = length % 2;
  1921         // Encode the length
  1922         encodeNonZeroOctetStringLengthOnSenventhBit(octetPairLength + octetSingleLength);
  1923         encodeNonEmptyFourBitCharacterString(table, ch, offset, octetPairLength, octetSingleLength);
  1926     protected final void encodeNonEmptyFourBitCharacterString(int[] table, char[] ch, int offset,
  1927             int octetPairLength, int octetSingleLength) throws FastInfosetException, IOException {
  1928         ensureSize(octetPairLength + octetSingleLength);
  1929         // Encode all pairs
  1930         int v = 0;
  1931         for (int i = 0; i < octetPairLength; i++) {
  1932             v = (table[ch[offset++]] << 4) | table[ch[offset++]];
  1933             if (v < 0) {
  1934                 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange"));
  1936             _octetBuffer[_octetBufferIndex++] = (byte)v;
  1938         // Encode single character at end with termination bits
  1939         if (octetSingleLength == 1) {
  1940             v = (table[ch[offset]] << 4) | 0x0F;
  1941             if (v < 0) {
  1942                 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange"));
  1944             _octetBuffer[_octetBufferIndex++] = (byte)v;
  1948     /**
  1949      * Encode a non empty string on the seventh bit of an octet using a restricted
  1950      * alphabet table.
  1951      * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1953      * @param alphabet the alphabet defining the mapping between characters and
  1954      *        integer values.
  1955      * @param ch the array of characters.
  1956      * @param offset the offset into the array of characters.
  1957      * @param length the length of characters.
  1958      */
  1959     protected final void encodeNonEmptyNBitCharacterStringOnSeventhBit(String alphabet, char[] ch, int offset, int length) throws FastInfosetException, IOException {
  1960         int bitsPerCharacter = 1;
  1961         while ((1 << bitsPerCharacter) <= alphabet.length()) {
  1962             bitsPerCharacter++;
  1965         final int bits = length * bitsPerCharacter;
  1966         final int octets = bits / 8;
  1967         final int bitsOfLastOctet = bits % 8;
  1968         final int totalOctets = octets + ((bitsOfLastOctet > 0) ? 1 : 0);
  1970         // Encode the length
  1971         encodeNonZeroOctetStringLengthOnSenventhBit(totalOctets);
  1973         resetBits();
  1974         ensureSize(totalOctets);
  1975         int v = 0;
  1976         for (int i = 0; i < length; i++) {
  1977             final char c = ch[offset + i];
  1978             // This is grotesquely slow, need to use hash table of character to int value
  1979             for (v = 0; v < alphabet.length(); v++) {
  1980                 if (c == alphabet.charAt(v)) {
  1981                     break;
  1984             if (v == alphabet.length()) {
  1985                 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange"));
  1987             writeBits(bitsPerCharacter, v);
  1990         if (bitsOfLastOctet > 0) {
  1991             _b |= (1 << (8 - bitsOfLastOctet)) - 1;
  1992             write(_b);
  1996     private int _bitsLeftInOctet;
  1998     private final void resetBits() {
  1999         _bitsLeftInOctet = 8;
  2000         _b = 0;
  2003     private final void writeBits(int bits, int v) throws IOException {
  2004         while (bits > 0) {
  2005             final int bit = (v & (1 << --bits)) > 0 ? 1 : 0;
  2006             _b |= bit << (--_bitsLeftInOctet);
  2007             if (_bitsLeftInOctet == 0) {
  2008                 write(_b);
  2009                 _bitsLeftInOctet = 8;
  2010                 _b = 0;
  2015     /**
  2016      * Encode the length of a encoded string on the seventh bit
  2017      * of an octet.
  2018      * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  2020      * @param length the length to encode.
  2021      */
  2022     protected final void encodeNonZeroOctetStringLengthOnSenventhBit(int length) throws IOException {
  2023         if (length < EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT) {
  2024             // [1, 2]
  2025             write(_b | (length - 1));
  2026         } else if (length < EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT) {
  2027             // [3, 258]
  2028             write(_b | EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_FLAG); // 00000010
  2029             write(length - EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT);
  2030         } else {
  2031             // [259, 4294967296]
  2032             write(_b | EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_LARGE_FLAG); // 00000011
  2033             length -= EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT;
  2034             write(length >>> 24);
  2035             write((length >> 16) & 0xFF);
  2036             write((length >> 8) & 0xFF);
  2037             write(length & 0xFF);
  2041     /**
  2042      * Encode a non zero integer on the second bit of an octet, setting
  2043      * the first bit to 1.
  2044      * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  2046      * <p>
  2047      * The first bit of the first octet is set, as specified in clause C.13 of
  2048      * ITU-T Rec. X.891 | ISO/IEC 24824-1
  2050      * @param i The integer to encode, which is a member of the interval
  2051      *          [0, 1048575]. In the specification the interval is [1, 1048576]
  2053      */
  2054     protected final void encodeNonZeroIntegerOnSecondBitFirstBitOne(int i) throws IOException {
  2055         if (i < EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT) {
  2056             // [1, 64] ( [0, 63] ) 6 bits
  2057             write(0x80 | i);
  2058         } else if (i < EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT) {
  2059             // [65, 8256] ( [64, 8255] ) 13 bits
  2060             i -= EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
  2061             _b = (0x80 | EncodingConstants.INTEGER_2ND_BIT_MEDIUM_FLAG) | (i >> 8); // 010 00000
  2062             // _b = 0xC0 | (i >> 8); // 010 00000
  2063             write(_b);
  2064             write(i & 0xFF);
  2065         } else if (i < EncodingConstants.INTEGER_2ND_BIT_LARGE_LIMIT) {
  2066             // [8257, 1048576] ( [8256, 1048575] ) 20 bits
  2067             i -= EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
  2068             _b = (0x80 | EncodingConstants.INTEGER_2ND_BIT_LARGE_FLAG) | (i >> 16); // 0110 0000
  2069             // _b = 0xE0 | (i >> 16); // 0110 0000
  2070             write(_b);
  2071             write((i >> 8) & 0xFF);
  2072             write(i & 0xFF);
  2073         } else {
  2074             throw new IOException(
  2075                     CommonResourceBundle.getInstance().getString("message.integerMaxSize",
  2076                     new Object[]{Integer.valueOf(EncodingConstants.INTEGER_2ND_BIT_LARGE_LIMIT)}));
  2080     /**
  2081      * Encode a non zero integer on the second bit of an octet, setting
  2082      * the first bit to 0.
  2083      * Implementation of clause C.25 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  2085      * <p>
  2086      * The first bit of the first octet is set, as specified in clause C.13 of
  2087      * ITU-T Rec. X.891 | ISO/IEC 24824-1
  2089      * @param i The integer to encode, which is a member of the interval
  2090      *          [0, 1048575]. In the specification the interval is [1, 1048576]
  2092      */
  2093     protected final void encodeNonZeroIntegerOnSecondBitFirstBitZero(int i) throws IOException {
  2094         if (i < EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT) {
  2095             // [1, 64] ( [0, 63] ) 6 bits
  2096             write(i);
  2097         } else if (i < EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT) {
  2098             // [65, 8256] ( [64, 8255] ) 13 bits
  2099             i -= EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
  2100             _b = EncodingConstants.INTEGER_2ND_BIT_MEDIUM_FLAG | (i >> 8); // 010 00000
  2101             write(_b);
  2102             write(i & 0xFF);
  2103         } else {
  2104             // [8257, 1048576] ( [8256, 1048575] ) 20 bits
  2105             i -= EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
  2106             _b = EncodingConstants.INTEGER_2ND_BIT_LARGE_FLAG | (i >> 16); // 0110 0000
  2107             write(_b);
  2108             write((i >> 8) & 0xFF);
  2109             write(i & 0xFF);
  2113     /**
  2114      * Encode a non zero integer on the third bit of an octet.
  2115      * Implementation of clause C.27 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  2117      * @param i The integer to encode, which is a member of the interval
  2118      *          [0, 1048575]. In the specification the interval is [1, 1048576]
  2120      */
  2121     protected final void encodeNonZeroIntegerOnThirdBit(int i) throws IOException {
  2122         if (i < EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT) {
  2123             // [1, 32] ( [0, 31] ) 5 bits
  2124             write(_b | i);
  2125         } else if (i < EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT) {
  2126             // [33, 2080] ( [32, 2079] ) 11 bits
  2127             i -= EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT;
  2128             _b |= EncodingConstants.INTEGER_3RD_BIT_MEDIUM_FLAG | (i >> 8); // 00100 000
  2129             write(_b);
  2130             write(i & 0xFF);
  2131         } else if (i < EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT) {
  2132             // [2081, 526368] ( [2080, 526367] ) 19 bits
  2133             i -= EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT;
  2134             _b |= EncodingConstants.INTEGER_3RD_BIT_LARGE_FLAG | (i >> 16); // 00101 000
  2135             write(_b);
  2136             write((i >> 8) & 0xFF);
  2137             write(i & 0xFF);
  2138         } else {
  2139             // [526369, 1048576] ( [526368, 1048575] ) 20 bits
  2140             i -= EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT;
  2141             _b |= EncodingConstants.INTEGER_3RD_BIT_LARGE_LARGE_FLAG; // 00110 000
  2142             write(_b);
  2143             write(i >> 16);
  2144             write((i >> 8) & 0xFF);
  2145             write(i & 0xFF);
  2149     /**
  2150      * Encode a non zero integer on the fourth bit of an octet.
  2151      * Implementation of clause C.28 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  2153      * @param i The integer to encode, which is a member of the interval
  2154      *          [0, 1048575]. In the specification the interval is [1, 1048576]
  2156      */
  2157     protected final void encodeNonZeroIntegerOnFourthBit(int i) throws IOException {
  2158         if (i < EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT) {
  2159             // [1, 16] ( [0, 15] ) 4 bits
  2160             write(_b | i);
  2161         } else if (i < EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT) {
  2162             // [17, 1040] ( [16, 1039] ) 10 bits
  2163             i -= EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT;
  2164             _b |= EncodingConstants.INTEGER_4TH_BIT_MEDIUM_FLAG | (i >> 8); // 000 100 00
  2165             write(_b);
  2166             write(i & 0xFF);
  2167         } else if (i < EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT) {
  2168             // [1041, 263184] ( [1040, 263183] ) 18 bits
  2169             i -= EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT;
  2170             _b |= EncodingConstants.INTEGER_4TH_BIT_LARGE_FLAG | (i >> 16); // 000 101 00
  2171             write(_b);
  2172             write((i >> 8) & 0xFF);
  2173             write(i & 0xFF);
  2174         } else {
  2175             // [263185, 1048576] ( [263184, 1048575] ) 20 bits
  2176             i -= EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT;
  2177             _b |= EncodingConstants.INTEGER_4TH_BIT_LARGE_LARGE_FLAG; // 000 110 00
  2178             write(_b);
  2179             write(i >> 16);
  2180             write((i >> 8) & 0xFF);
  2181             write(i & 0xFF);
  2185     /**
  2186      * Encode a non empty string using the UTF-8 encoding.
  2188      * @param b the current octet that is being written.
  2189      * @param s the string to be UTF-8 encoded.
  2190      * @param constants the array of constants to use when encoding to determin
  2191      *        how the length of the UTF-8 encoded string is encoded.
  2192      */
  2193     protected final void encodeNonEmptyUTF8StringAsOctetString(int b, String s, int[] constants) throws IOException {
  2194         final char[] ch = s.toCharArray();
  2195         encodeNonEmptyUTF8StringAsOctetString(b, ch, 0, ch.length, constants);
  2198     /**
  2199      * Encode a non empty string using the UTF-8 encoding.
  2201      * @param b the current octet that is being written.
  2202      * @param ch the array of characters.
  2203      * @param offset the offset into the array of characters.
  2204      * @param length the length of characters.
  2205      *        how the length of the UTF-8 encoded string is encoded.
  2206      * @param constants the array of constants to use when encoding to determin
  2207      *        how the length of the UTF-8 encoded string is encoded.
  2208      */
  2209     protected final void encodeNonEmptyUTF8StringAsOctetString(int b, char ch[], int offset, int length, int[] constants) throws IOException {
  2210         length = encodeUTF8String(ch, offset, length);
  2211         encodeNonZeroOctetStringLength(b, length, constants);
  2212         write(_encodingBuffer, length);
  2215     /**
  2216      * Encode the length of non empty UTF-8 encoded string.
  2218      * @param b the current octet that is being written.
  2219      * @param length the length of the UTF-8 encoded string.
  2220      *        how the length of the UTF-8 encoded string is encoded.
  2221      * @param constants the array of constants to use when encoding to determin
  2222      *        how the length of the UTF-8 encoded string is encoded.
  2223      */
  2224     protected final void encodeNonZeroOctetStringLength(int b, int length, int[] constants) throws IOException {
  2225         if (length < constants[EncodingConstants.OCTET_STRING_LENGTH_SMALL_LIMIT]) {
  2226             write(b | (length - 1));
  2227         } else if (length < constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_LIMIT]) {
  2228             write(b | constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_FLAG]);
  2229             write(length - constants[EncodingConstants.OCTET_STRING_LENGTH_SMALL_LIMIT]);
  2230         } else {
  2231             write(b | constants[EncodingConstants.OCTET_STRING_LENGTH_LARGE_FLAG]);
  2232             length -= constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_LIMIT];
  2233             write(length >>> 24);
  2234             write((length >> 16) & 0xFF);
  2235             write((length >> 8) & 0xFF);
  2236             write(length & 0xFF);
  2240     /**
  2241      * Encode a non zero integer.
  2243      * @param b the current octet that is being written.
  2244      * @param i the non zero integer.
  2245      * @param constants the array of constants to use when encoding to determin
  2246      *        how the non zero integer is encoded.
  2247      */
  2248     protected final void encodeNonZeroInteger(int b, int i, int[] constants) throws IOException {
  2249         if (i < constants[EncodingConstants.INTEGER_SMALL_LIMIT]) {
  2250             write(b | i);
  2251         } else if (i < constants[EncodingConstants.INTEGER_MEDIUM_LIMIT]) {
  2252             i -= constants[EncodingConstants.INTEGER_SMALL_LIMIT];
  2253             write(b | constants[EncodingConstants.INTEGER_MEDIUM_FLAG] | (i >> 8));
  2254             write(i & 0xFF);
  2255         } else if (i < constants[EncodingConstants.INTEGER_LARGE_LIMIT]) {
  2256             i -= constants[EncodingConstants.INTEGER_MEDIUM_LIMIT];
  2257             write(b | constants[EncodingConstants.INTEGER_LARGE_FLAG] | (i >> 16));
  2258             write((i >> 8) & 0xFF);
  2259             write(i & 0xFF);
  2260         } else if (i < EncodingConstants.INTEGER_MAXIMUM_SIZE) {
  2261             i -= constants[EncodingConstants.INTEGER_LARGE_LIMIT];
  2262             write(b | constants[EncodingConstants.INTEGER_LARGE_LARGE_FLAG]);
  2263             write(i >> 16);
  2264             write((i >> 8) & 0xFF);
  2265             write(i & 0xFF);
  2266         } else {
  2267             throw new IOException(CommonResourceBundle.getInstance().getString("message.integerMaxSize", new Object[]{Integer.valueOf(EncodingConstants.INTEGER_MAXIMUM_SIZE)}));
  2271     /**
  2272      * Mark the current position in the buffered stream.
  2273      */
  2274     protected final void mark() {
  2275         _markIndex = _octetBufferIndex;
  2278     /**
  2279      * Reset the marked position in the buffered stream.
  2280      */
  2281     protected final void resetMark() {
  2282         _markIndex = -1;
  2285     /**
  2286      * @return true if the mark has been set, otherwise false if the mark
  2287      *         has not been set.
  2288      */
  2289     protected final boolean hasMark() {
  2290         return _markIndex != -1;
  2293     /**
  2294      * Write a byte to the buffered stream.
  2295      */
  2296     protected final void write(int i) throws IOException {
  2297         if (_octetBufferIndex < _octetBuffer.length) {
  2298             _octetBuffer[_octetBufferIndex++] = (byte)i;
  2299         } else {
  2300             if (_markIndex == -1) {
  2301                 _s.write(_octetBuffer);
  2302                 _octetBufferIndex = 1;
  2303                 _octetBuffer[0] = (byte)i;
  2304             } else {
  2305                 resize(_octetBuffer.length * 3 / 2);
  2306                 _octetBuffer[_octetBufferIndex++] = (byte)i;
  2311     /**
  2312      * Write an array of bytes to the buffered stream.
  2314      * @param b the array of bytes.
  2315      * @param length the length of bytes.
  2316      */
  2317     protected final void write(byte[] b, int length) throws IOException {
  2318         write(b, 0,  length);
  2321     /**
  2322      * Write an array of bytes to the buffered stream.
  2324      * @param b the array of bytes.
  2325      * @param offset the offset into the array of bytes.
  2326      * @param length the length of bytes.
  2327      */
  2328     protected final void write(byte[] b, int offset, int length) throws IOException {
  2329         if ((_octetBufferIndex + length) < _octetBuffer.length) {
  2330             System.arraycopy(b, offset, _octetBuffer, _octetBufferIndex, length);
  2331             _octetBufferIndex += length;
  2332         } else {
  2333             if (_markIndex == -1) {
  2334                 _s.write(_octetBuffer, 0, _octetBufferIndex);
  2335                 _s.write(b, offset, length);
  2336                 _octetBufferIndex = 0;
  2337             } else {
  2338                 resize((_octetBuffer.length + length) * 3 / 2 + 1);
  2339                 System.arraycopy(b, offset, _octetBuffer, _octetBufferIndex, length);
  2340                 _octetBufferIndex += length;
  2345     private void ensureSize(int length) {
  2346         if ((_octetBufferIndex + length) > _octetBuffer.length) {
  2347             resize((_octetBufferIndex + length) * 3 / 2 + 1);
  2351     private void resize(int length) {
  2352         byte[] b = new byte[length];
  2353         System.arraycopy(_octetBuffer, 0, b, 0, _octetBufferIndex);
  2354         _octetBuffer = b;
  2357     private void _flush() throws IOException {
  2358         if (_octetBufferIndex > 0) {
  2359             _s.write(_octetBuffer, 0, _octetBufferIndex);
  2360             _octetBufferIndex = 0;
  2365     private EncodingBufferOutputStream _encodingBufferOutputStream = new EncodingBufferOutputStream();
  2367     private byte[] _encodingBuffer = new byte[512];
  2369     private int _encodingBufferIndex;
  2371     private class EncodingBufferOutputStream extends OutputStream {
  2373         public void write(int b) throws IOException {
  2374             if (_encodingBufferIndex < _encodingBuffer.length) {
  2375                 _encodingBuffer[_encodingBufferIndex++] = (byte)b;
  2376             } else {
  2377                 byte newbuf[] = new byte[Math.max(_encodingBuffer.length << 1, _encodingBufferIndex)];
  2378                 System.arraycopy(_encodingBuffer, 0, newbuf, 0, _encodingBufferIndex);
  2379                 _encodingBuffer = newbuf;
  2381                 _encodingBuffer[_encodingBufferIndex++] = (byte)b;
  2385         public void write(byte b[], int off, int len) throws IOException {
  2386             if ((off < 0) || (off > b.length) || (len < 0) ||
  2387                 ((off + len) > b.length) || ((off + len) < 0)) {
  2388                 throw new IndexOutOfBoundsException();
  2389             } else if (len == 0) {
  2390                 return;
  2392             final int newoffset = _encodingBufferIndex + len;
  2393             if (newoffset > _encodingBuffer.length) {
  2394                 byte newbuf[] = new byte[Math.max(_encodingBuffer.length << 1, newoffset)];
  2395                 System.arraycopy(_encodingBuffer, 0, newbuf, 0, _encodingBufferIndex);
  2396                 _encodingBuffer = newbuf;
  2398             System.arraycopy(b, off, _encodingBuffer, _encodingBufferIndex, len);
  2399             _encodingBufferIndex = newoffset;
  2402         public int getLength() {
  2403             return _encodingBufferIndex;
  2406         public void reset() {
  2407             _encodingBufferIndex = 0;
  2411     /**
  2412      * Encode a string using the UTF-8 encoding.
  2414      * @param s the string to encode.
  2415      */
  2416     protected final int encodeUTF8String(String s) throws IOException {
  2417         final int length = s.length();
  2418         if (length < _charBuffer.length) {
  2419             s.getChars(0, length, _charBuffer, 0);
  2420             return encodeUTF8String(_charBuffer, 0, length);
  2421         } else {
  2422             char[] ch = s.toCharArray();
  2423             return encodeUTF8String(ch, 0, length);
  2427     private void ensureEncodingBufferSizeForUtf8String(int length) {
  2428         final int newLength = 4 * length;
  2429         if (_encodingBuffer.length < newLength) {
  2430             _encodingBuffer = new byte[newLength];
  2434     /**
  2435      * Encode a string using the UTF-8 encoding.
  2437      * @param ch the array of characters.
  2438      * @param offset the offset into the array of characters.
  2439      * @param length the length of characters.
  2440      */
  2441     protected final int encodeUTF8String(char[] ch, int offset, int length) throws IOException {
  2442         int bpos = 0;
  2444         // Make sure buffer is large enough
  2445         ensureEncodingBufferSizeForUtf8String(length);
  2447         final int end = offset + length;
  2448         int c;
  2449         while (end != offset) {
  2450             c = ch[offset++];
  2451             if (c < 0x80) {
  2452                 // 1 byte, 7 bits
  2453                 _encodingBuffer[bpos++] = (byte) c;
  2454             } else if (c < 0x800) {
  2455                 // 2 bytes, 11 bits
  2456                 _encodingBuffer[bpos++] =
  2457                     (byte) (0xC0 | (c >> 6));    // first 5
  2458                 _encodingBuffer[bpos++] =
  2459                     (byte) (0x80 | (c & 0x3F));  // second 6
  2460             } else if (c <= '\uFFFF') {
  2461                 if (!XMLChar.isHighSurrogate(c) && !XMLChar.isLowSurrogate(c)) {
  2462                     // 3 bytes, 16 bits
  2463                     _encodingBuffer[bpos++] =
  2464                         (byte) (0xE0 | (c >> 12));   // first 4
  2465                     _encodingBuffer[bpos++] =
  2466                         (byte) (0x80 | ((c >> 6) & 0x3F));  // second 6
  2467                     _encodingBuffer[bpos++] =
  2468                         (byte) (0x80 | (c & 0x3F));  // third 6
  2469                 } else {
  2470                     // 4 bytes, high and low surrogate
  2471                     encodeCharacterAsUtf8FourByte(c, ch, offset, end, bpos);
  2472                     bpos += 4;
  2473                     offset++;
  2478         return bpos;
  2481     private void encodeCharacterAsUtf8FourByte(int c, char[] ch, int chpos, int chend, int bpos) throws IOException {
  2482         if (chpos == chend) {
  2483             throw new IOException("");
  2486         final char d = ch[chpos];
  2487         if (!XMLChar.isLowSurrogate(d)) {
  2488             throw new IOException("");
  2491         final int uc = (((c & 0x3ff) << 10) | (d & 0x3ff)) + 0x10000;
  2492         if (uc < 0 || uc >= 0x200000) {
  2493             throw new IOException("");
  2496         _encodingBuffer[bpos++] = (byte)(0xF0 | ((uc >> 18)));
  2497         _encodingBuffer[bpos++] = (byte)(0x80 | ((uc >> 12) & 0x3F));
  2498         _encodingBuffer[bpos++] = (byte)(0x80 | ((uc >> 6) & 0x3F));
  2499         _encodingBuffer[bpos++] = (byte)(0x80 | (uc & 0x3F));
  2502     /**
  2503      * Encode a string using the UTF-16 encoding.
  2505      * @param s the string to encode.
  2506      */
  2507     protected final int encodeUtf16String(String s) throws IOException {
  2508         final int length = s.length();
  2509         if (length < _charBuffer.length) {
  2510             s.getChars(0, length, _charBuffer, 0);
  2511             return encodeUtf16String(_charBuffer, 0, length);
  2512         } else {
  2513             char[] ch = s.toCharArray();
  2514             return encodeUtf16String(ch, 0, length);
  2518     private void ensureEncodingBufferSizeForUtf16String(int length) {
  2519         final int newLength = 2 * length;
  2520         if (_encodingBuffer.length < newLength) {
  2521             _encodingBuffer = new byte[newLength];
  2525     /**
  2526      * Encode a string using the UTF-16 encoding.
  2528      * @param ch the array of characters.
  2529      * @param offset the offset into the array of characters.
  2530      * @param length the length of characters.
  2531      */
  2532     protected final int encodeUtf16String(char[] ch, int offset, int length) throws IOException {
  2533         int byteLength = 0;
  2535         // Make sure buffer is large enough
  2536         ensureEncodingBufferSizeForUtf16String(length);
  2538         final int n = offset + length;
  2539         for (int i = offset; i < n; i++) {
  2540             final int c = (int) ch[i];
  2541             _encodingBuffer[byteLength++] = (byte)(c >> 8);
  2542             _encodingBuffer[byteLength++] = (byte)(c & 0xFF);
  2545         return byteLength;
  2548     /**
  2549      * Obtain the prefix from a qualified name.
  2551      * @param qName the qualified name
  2552      * @return the prefix, or "" if there is no prefix.
  2553      */
  2554     public static String getPrefixFromQualifiedName(String qName) {
  2555         int i = qName.indexOf(':');
  2556         String prefix = "";
  2557         if (i != -1) {
  2558             prefix = qName.substring(0, i);
  2560         return prefix;
  2563     /**
  2564      * Check if character array contains characters that are all white space.
  2566      * @param ch the character array
  2567      * @param start the starting character index into the array to check from
  2568      * @param length the number of characters to check
  2569      * @return true if all characters are white space, false otherwise
  2570      */
  2571     public static boolean isWhiteSpace(final char[] ch, int start, final int length) {
  2572         if (!XMLChar.isSpace(ch[start])) return false;
  2574         final int end = start + length;
  2575         while(++start < end && XMLChar.isSpace(ch[start]));
  2577         return start == end;
  2580     /**
  2581      * Check if a String contains characters that are all white space.
  2583      * @param s the string
  2584      * @return true if all characters are white space, false otherwise
  2585      */
  2586     public static boolean isWhiteSpace(String s) {
  2587         if (!XMLChar.isSpace(s.charAt(0))) return false;
  2589         final int end = s.length();
  2590         int start = 1;
  2591         while(start < end && XMLChar.isSpace(s.charAt(start++)));
  2592         return start == end;

mercurial