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

changeset 0
373ffda63c9a
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/fastinfoset/Encoder.java	Wed Apr 27 01:27:09 2016 +0800
     1.3 @@ -0,0 +1,2594 @@
     1.4 +/*
     1.5 + * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + *
    1.28 + * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
    1.29 + */
    1.30 +
    1.31 +package com.sun.xml.internal.fastinfoset;
    1.32 +
    1.33 +import com.sun.xml.internal.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory;
    1.34 +import com.sun.xml.internal.fastinfoset.org.apache.xerces.util.XMLChar;
    1.35 +import com.sun.xml.internal.fastinfoset.util.CharArrayIntMap;
    1.36 +import com.sun.xml.internal.fastinfoset.util.KeyIntMap;
    1.37 +import com.sun.xml.internal.fastinfoset.util.LocalNameQualifiedNamesMap;
    1.38 +import com.sun.xml.internal.fastinfoset.util.StringIntMap;
    1.39 +import com.sun.xml.internal.fastinfoset.vocab.SerializerVocabulary;
    1.40 +import java.io.IOException;
    1.41 +import java.io.OutputStream;
    1.42 +import java.util.HashMap;
    1.43 +import java.util.Map;
    1.44 +import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm;
    1.45 +import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmException;
    1.46 +import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes;
    1.47 +import com.sun.xml.internal.org.jvnet.fastinfoset.ExternalVocabulary;
    1.48 +import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException;
    1.49 +import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetSerializer;
    1.50 +import com.sun.xml.internal.org.jvnet.fastinfoset.RestrictedAlphabet;
    1.51 +import com.sun.xml.internal.org.jvnet.fastinfoset.VocabularyApplicationData;
    1.52 +import org.xml.sax.helpers.DefaultHandler;
    1.53 +
    1.54 +/**
    1.55 + * Abstract encoder for developing concrete encoders.
    1.56 + *
    1.57 + * Concrete implementations extending Encoder will utilize methods on Encoder
    1.58 + * to encode XML infoset according to the Fast Infoset standard. It is the
    1.59 + * responsibility of the concrete implementation to ensure that methods are
    1.60 + * invoked in the correct order to produce a valid fast infoset document.
    1.61 + *
    1.62 + * <p>
    1.63 + * This class extends org.sax.xml.DefaultHandler so that concrete SAX
    1.64 + * implementations can be used with javax.xml.parsers.SAXParser and the parse
    1.65 + * methods that take org.sax.xml.DefaultHandler as a parameter.
    1.66 + *
    1.67 + * <p>
    1.68 + * Buffering of octets that are written to an {@link java.io.OutputStream} is
    1.69 + * supported in a similar manner to a {@link java.io.BufferedOutputStream}.
    1.70 + * Combining buffering with encoding enables better performance.
    1.71 + *
    1.72 + * <p>
    1.73 + * More than one fast infoset document may be encoded to the
    1.74 + * {@link java.io.OutputStream}.
    1.75 + *
    1.76 + */
    1.77 +public abstract class Encoder extends DefaultHandler implements FastInfosetSerializer {
    1.78 +
    1.79 +    /**
    1.80 +     * Character encoding scheme system property for the encoding
    1.81 +     * of content and attribute values.
    1.82 +     */
    1.83 +    public static final String CHARACTER_ENCODING_SCHEME_SYSTEM_PROPERTY =
    1.84 +        "com.sun.xml.internal.fastinfoset.serializer.character-encoding-scheme";
    1.85 +
    1.86 +    /**
    1.87 +     * Default character encoding scheme system property for the encoding
    1.88 +     * of content and attribute values.
    1.89 +     */
    1.90 +    protected static final String _characterEncodingSchemeSystemDefault = getDefaultEncodingScheme();
    1.91 +
    1.92 +    private static String getDefaultEncodingScheme() {
    1.93 +        String p = System.getProperty(CHARACTER_ENCODING_SCHEME_SYSTEM_PROPERTY,
    1.94 +            UTF_8);
    1.95 +        if (p.equals(UTF_16BE)) {
    1.96 +            return UTF_16BE;
    1.97 +        } else {
    1.98 +            return UTF_8;
    1.99 +        }
   1.100 +    }
   1.101 +
   1.102 +    private static int[] NUMERIC_CHARACTERS_TABLE;
   1.103 +
   1.104 +    private static int[] DATE_TIME_CHARACTERS_TABLE;
   1.105 +
   1.106 +    static {
   1.107 +        NUMERIC_CHARACTERS_TABLE = new int[maxCharacter(RestrictedAlphabet.NUMERIC_CHARACTERS) + 1];
   1.108 +        DATE_TIME_CHARACTERS_TABLE = new int[maxCharacter(RestrictedAlphabet.DATE_TIME_CHARACTERS) + 1];
   1.109 +
   1.110 +        for (int i = 0; i < NUMERIC_CHARACTERS_TABLE.length ; i++) {
   1.111 +            NUMERIC_CHARACTERS_TABLE[i] = -1;
   1.112 +        }
   1.113 +        for (int i = 0; i < DATE_TIME_CHARACTERS_TABLE.length ; i++) {
   1.114 +            DATE_TIME_CHARACTERS_TABLE[i] = -1;
   1.115 +        }
   1.116 +
   1.117 +        for (int i = 0; i < RestrictedAlphabet.NUMERIC_CHARACTERS.length() ; i++) {
   1.118 +            NUMERIC_CHARACTERS_TABLE[RestrictedAlphabet.NUMERIC_CHARACTERS.charAt(i)] = i;
   1.119 +        }
   1.120 +        for (int i = 0; i < RestrictedAlphabet.DATE_TIME_CHARACTERS.length() ; i++) {
   1.121 +            DATE_TIME_CHARACTERS_TABLE[RestrictedAlphabet.DATE_TIME_CHARACTERS.charAt(i)] = i;
   1.122 +        }
   1.123 +    }
   1.124 +
   1.125 +    private static int maxCharacter(String alphabet) {
   1.126 +        int c = 0;
   1.127 +        for (int i = 0; i < alphabet.length() ; i++) {
   1.128 +            if (c < alphabet.charAt(i)) {
   1.129 +                c = alphabet.charAt(i);
   1.130 +            }
   1.131 +        }
   1.132 +
   1.133 +        return c;
   1.134 +    }
   1.135 +
   1.136 +    /**
   1.137 +     * True if DTD and internal subset shall be ignored.
   1.138 +     */
   1.139 +    private boolean _ignoreDTD;
   1.140 +
   1.141 +    /**
   1.142 +     * True if comments shall be ignored.
   1.143 +     */
   1.144 +    private boolean _ignoreComments;
   1.145 +
   1.146 +    /**
   1.147 +     * True if procesing instructions shall be ignored.
   1.148 +     */
   1.149 +    private boolean _ignoreProcessingInstructions;
   1.150 +
   1.151 +    /**
   1.152 +     * True if white space characters for text content shall be ignored.
   1.153 +     */
   1.154 +    private boolean _ignoreWhiteSpaceTextContent;
   1.155 +
   1.156 +    /**
   1.157 +     * True, if the local name string is used as the key to find the
   1.158 +     * associated set of qualified names.
   1.159 +     * <p>
   1.160 +     * False,  if the <prefix>:<local name> string is used as the key
   1.161 +     * to find the associated set of qualified names.
   1.162 +     */
   1.163 +    private boolean _useLocalNameAsKeyForQualifiedNameLookup;
   1.164 +
   1.165 +    /**
   1.166 +     * True if strings for text content and attribute values will be
   1.167 +     * UTF-8 encoded otherwise they will be UTF-16 encoded.
   1.168 +     */
   1.169 +    private boolean _encodingStringsAsUtf8 = true;
   1.170 +
   1.171 +    /**
   1.172 +     * Encoding constant generated from the string encoding.
   1.173 +     */
   1.174 +    private int _nonIdentifyingStringOnThirdBitCES;
   1.175 +
   1.176 +    /**
   1.177 +     * Encoding constant generated from the string encoding.
   1.178 +     */
   1.179 +    private int _nonIdentifyingStringOnFirstBitCES;
   1.180 +
   1.181 +    /**
   1.182 +     * The map of URIs to algorithms.
   1.183 +     */
   1.184 +    private Map _registeredEncodingAlgorithms = new HashMap();
   1.185 +
   1.186 +    /**
   1.187 +     * The vocabulary that is used by the encoder
   1.188 +     */
   1.189 +    protected SerializerVocabulary _v;
   1.190 +
   1.191 +    /**
   1.192 +     * The vocabulary application data that is used by the encoder
   1.193 +     */
   1.194 +    protected VocabularyApplicationData _vData;
   1.195 +
   1.196 +    /**
   1.197 +     * True if the vocubulary is internal to the encoder
   1.198 +     */
   1.199 +    private boolean _vIsInternal;
   1.200 +
   1.201 +    /**
   1.202 +     * True if terminatation of an information item is required
   1.203 +     */
   1.204 +    protected boolean _terminate = false;
   1.205 +
   1.206 +    /**
   1.207 +     * The current octet that is to be written.
   1.208 +     */
   1.209 +    protected int _b;
   1.210 +
   1.211 +    /**
   1.212 +     * The {@link java.io.OutputStream} that the encoded XML infoset (the
   1.213 +     * fast infoset document) is written to.
   1.214 +     */
   1.215 +    protected OutputStream _s;
   1.216 +
   1.217 +    /**
   1.218 +     * The internal buffer of characters used for the UTF-8 or UTF-16 encoding
   1.219 +     * of characters.
   1.220 +     */
   1.221 +    protected char[] _charBuffer = new char[512];
   1.222 +
   1.223 +    /**
   1.224 +     * The internal buffer of bytes.
   1.225 +     */
   1.226 +    protected byte[] _octetBuffer = new byte[1024];
   1.227 +
   1.228 +    /**
   1.229 +     * The current position in the internal buffer.
   1.230 +     */
   1.231 +    protected int _octetBufferIndex;
   1.232 +
   1.233 +    /**
   1.234 +     * The current mark in the internal buffer.
   1.235 +     *
   1.236 +     * <p>
   1.237 +     * If the value of the mark is < 0 then the mark is not set.
   1.238 +     */
   1.239 +    protected int _markIndex = -1;
   1.240 +
   1.241 +    /**
   1.242 +     * The minimum size of [normalized value] of Attribute Information
   1.243 +     * Items that will be indexed.
   1.244 +     */
   1.245 +    protected int minAttributeValueSize = FastInfosetSerializer.MIN_ATTRIBUTE_VALUE_SIZE;
   1.246 +
   1.247 +    /**
   1.248 +     * The maximum size of [normalized value] of Attribute Information
   1.249 +     * Items that will be indexed.
   1.250 +     */
   1.251 +    protected int maxAttributeValueSize = FastInfosetSerializer.MAX_ATTRIBUTE_VALUE_SIZE;
   1.252 +
   1.253 +    /**
   1.254 +     * The limit on the size of indexed Map for attribute values
   1.255 +     * Limit is measured in characters number
   1.256 +     */
   1.257 +    protected int attributeValueMapTotalCharactersConstraint = FastInfosetSerializer.ATTRIBUTE_VALUE_MAP_MEMORY_CONSTRAINT / 2;
   1.258 +
   1.259 +    /**
   1.260 +     * The minimum size of character content chunks
   1.261 +     * of Character Information Items or Comment Information Items that
   1.262 +     * will be indexed.
   1.263 +     */
   1.264 +    protected int minCharacterContentChunkSize = FastInfosetSerializer.MIN_CHARACTER_CONTENT_CHUNK_SIZE;
   1.265 +
   1.266 +    /**
   1.267 +     * The maximum size of character content chunks
   1.268 +     * of Character Information Items or Comment Information Items that
   1.269 +     * will be indexed.
   1.270 +     */
   1.271 +    protected int maxCharacterContentChunkSize = FastInfosetSerializer.MAX_CHARACTER_CONTENT_CHUNK_SIZE;
   1.272 +
   1.273 +    /**
   1.274 +     * The limit on the size of indexed Map for character content chunks
   1.275 +     * Limit is measured in characters number
   1.276 +     */
   1.277 +    protected int characterContentChunkMapTotalCharactersConstraint = FastInfosetSerializer.CHARACTER_CONTENT_CHUNK_MAP_MEMORY_CONSTRAINT / 2;
   1.278 +
   1.279 +    /**
   1.280 +     * Default constructor for the Encoder.
   1.281 +     */
   1.282 +    protected Encoder() {
   1.283 +        setCharacterEncodingScheme(_characterEncodingSchemeSystemDefault);
   1.284 +    }
   1.285 +
   1.286 +    protected Encoder(boolean useLocalNameAsKeyForQualifiedNameLookup) {
   1.287 +        setCharacterEncodingScheme(_characterEncodingSchemeSystemDefault);
   1.288 +        _useLocalNameAsKeyForQualifiedNameLookup = useLocalNameAsKeyForQualifiedNameLookup;
   1.289 +    }
   1.290 +
   1.291 +
   1.292 +    // FastInfosetSerializer interface
   1.293 +
   1.294 +    /**
   1.295 +     * {@inheritDoc}
   1.296 +     */
   1.297 +    public final void setIgnoreDTD(boolean ignoreDTD) {
   1.298 +        _ignoreDTD = ignoreDTD;
   1.299 +    }
   1.300 +
   1.301 +    /**
   1.302 +     * {@inheritDoc}
   1.303 +     */
   1.304 +    public final boolean getIgnoreDTD() {
   1.305 +        return _ignoreDTD;
   1.306 +    }
   1.307 +
   1.308 +    /**
   1.309 +     * {@inheritDoc}
   1.310 +     */
   1.311 +    public final void setIgnoreComments(boolean ignoreComments) {
   1.312 +        _ignoreComments = ignoreComments;
   1.313 +    }
   1.314 +
   1.315 +    /**
   1.316 +     * {@inheritDoc}
   1.317 +     */
   1.318 +    public final boolean getIgnoreComments() {
   1.319 +        return _ignoreComments;
   1.320 +    }
   1.321 +
   1.322 +    /**
   1.323 +     * {@inheritDoc}
   1.324 +     */
   1.325 +    public final void setIgnoreProcesingInstructions(boolean
   1.326 +            ignoreProcesingInstructions) {
   1.327 +        _ignoreProcessingInstructions = ignoreProcesingInstructions;
   1.328 +    }
   1.329 +
   1.330 +    /**
   1.331 +     * {@inheritDoc}
   1.332 +     */
   1.333 +    public final boolean getIgnoreProcesingInstructions() {
   1.334 +        return _ignoreProcessingInstructions;
   1.335 +    }
   1.336 +
   1.337 +    /**
   1.338 +     * {@inheritDoc}
   1.339 +     */
   1.340 +    public final void setIgnoreWhiteSpaceTextContent(boolean ignoreWhiteSpaceTextContent) {
   1.341 +        _ignoreWhiteSpaceTextContent = ignoreWhiteSpaceTextContent;
   1.342 +    }
   1.343 +
   1.344 +    /**
   1.345 +     * {@inheritDoc}
   1.346 +     */
   1.347 +    public final boolean getIgnoreWhiteSpaceTextContent() {
   1.348 +        return _ignoreWhiteSpaceTextContent;
   1.349 +    }
   1.350 +
   1.351 +    /**
   1.352 +     * {@inheritDoc}
   1.353 +     */
   1.354 +    public void setCharacterEncodingScheme(String characterEncodingScheme) {
   1.355 +        if (characterEncodingScheme.equals(UTF_16BE)) {
   1.356 +            _encodingStringsAsUtf8 = false;
   1.357 +            _nonIdentifyingStringOnThirdBitCES = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_UTF_16_FLAG;
   1.358 +            _nonIdentifyingStringOnFirstBitCES = EncodingConstants.NISTRING_UTF_16_FLAG;
   1.359 +        } else {
   1.360 +            _encodingStringsAsUtf8 = true;
   1.361 +            _nonIdentifyingStringOnThirdBitCES = EncodingConstants.CHARACTER_CHUNK;
   1.362 +            _nonIdentifyingStringOnFirstBitCES = 0;
   1.363 +        }
   1.364 +    }
   1.365 +
   1.366 +    /**
   1.367 +     * {@inheritDoc}
   1.368 +     */
   1.369 +    public String getCharacterEncodingScheme() {
   1.370 +        return (_encodingStringsAsUtf8) ? UTF_8 : UTF_16BE;
   1.371 +    }
   1.372 +
   1.373 +    /**
   1.374 +     * {@inheritDoc}
   1.375 +     */
   1.376 +    public void setRegisteredEncodingAlgorithms(Map algorithms) {
   1.377 +        _registeredEncodingAlgorithms = algorithms;
   1.378 +        if (_registeredEncodingAlgorithms == null) {
   1.379 +            _registeredEncodingAlgorithms = new HashMap();
   1.380 +        }
   1.381 +    }
   1.382 +
   1.383 +    /**
   1.384 +     * {@inheritDoc}
   1.385 +     */
   1.386 +    public Map getRegisteredEncodingAlgorithms() {
   1.387 +        return _registeredEncodingAlgorithms;
   1.388 +    }
   1.389 +
   1.390 +    /**
   1.391 +     * {@inheritDoc}
   1.392 +     */
   1.393 +    public int getMinCharacterContentChunkSize() {
   1.394 +        return minCharacterContentChunkSize;
   1.395 +    }
   1.396 +
   1.397 +    /**
   1.398 +     * {@inheritDoc}
   1.399 +     */
   1.400 +    public void setMinCharacterContentChunkSize(int size) {
   1.401 +        if (size < 0 ) {
   1.402 +            size = 0;
   1.403 +        }
   1.404 +
   1.405 +        minCharacterContentChunkSize = size;
   1.406 +    }
   1.407 +
   1.408 +    /**
   1.409 +     * {@inheritDoc}
   1.410 +     */
   1.411 +    public int getMaxCharacterContentChunkSize() {
   1.412 +        return maxCharacterContentChunkSize;
   1.413 +    }
   1.414 +
   1.415 +    /**
   1.416 +     * {@inheritDoc}
   1.417 +     */
   1.418 +    public void setMaxCharacterContentChunkSize(int size) {
   1.419 +        if (size < 0 ) {
   1.420 +            size = 0;
   1.421 +        }
   1.422 +
   1.423 +        maxCharacterContentChunkSize = size;
   1.424 +    }
   1.425 +
   1.426 +    /**
   1.427 +     * {@inheritDoc}
   1.428 +     */
   1.429 +    public int getCharacterContentChunkMapMemoryLimit() {
   1.430 +        return characterContentChunkMapTotalCharactersConstraint * 2;
   1.431 +    }
   1.432 +
   1.433 +    /**
   1.434 +     * {@inheritDoc}
   1.435 +     */
   1.436 +    public void setCharacterContentChunkMapMemoryLimit(int size) {
   1.437 +        if (size < 0 ) {
   1.438 +            size = 0;
   1.439 +        }
   1.440 +
   1.441 +        characterContentChunkMapTotalCharactersConstraint = size / 2;
   1.442 +    }
   1.443 +
   1.444 +    /**
   1.445 +     * Checks whether character content chunk (its length) matches length limit
   1.446 +     *
   1.447 +     * @param length the length of character content chunk is checking to be added to Map.
   1.448 +     * @return whether character content chunk length matches limit
   1.449 +     */
   1.450 +    public boolean isCharacterContentChunkLengthMatchesLimit(int length) {
   1.451 +        return length >= minCharacterContentChunkSize &&
   1.452 +                length < maxCharacterContentChunkSize;
   1.453 +    }
   1.454 +
   1.455 +    /**
   1.456 +     * Checks whether character content table has enough memory to
   1.457 +     * store character content chunk with the given length
   1.458 +     *
   1.459 +     * @param length the length of character content chunk is checking to be added to Map.
   1.460 +     * @param map the custom CharArrayIntMap, which memory limits will be checked.
   1.461 +     * @return whether character content map has enough memory
   1.462 +     */
   1.463 +    public boolean canAddCharacterContentToTable(int length, CharArrayIntMap map) {
   1.464 +        return map.getTotalCharacterCount() + length <
   1.465 +                        characterContentChunkMapTotalCharactersConstraint;
   1.466 +    }
   1.467 +
   1.468 +    /**
   1.469 +     * {@inheritDoc}
   1.470 +     */
   1.471 +    public int getMinAttributeValueSize() {
   1.472 +        return minAttributeValueSize;
   1.473 +    }
   1.474 +
   1.475 +    /**
   1.476 +     * {@inheritDoc}
   1.477 +     */
   1.478 +    public void setMinAttributeValueSize(int size) {
   1.479 +        if (size < 0 ) {
   1.480 +            size = 0;
   1.481 +        }
   1.482 +
   1.483 +        minAttributeValueSize = size;
   1.484 +    }
   1.485 +
   1.486 +    /**
   1.487 +     * {@inheritDoc}
   1.488 +     */
   1.489 +    public int getMaxAttributeValueSize() {
   1.490 +        return maxAttributeValueSize;
   1.491 +    }
   1.492 +
   1.493 +    /**
   1.494 +     * {@inheritDoc}
   1.495 +     */
   1.496 +    public void setMaxAttributeValueSize(int size) {
   1.497 +        if (size < 0 ) {
   1.498 +            size = 0;
   1.499 +        }
   1.500 +
   1.501 +        maxAttributeValueSize = size;
   1.502 +    }
   1.503 +
   1.504 +    /**
   1.505 +     * {@inheritDoc}
   1.506 +     */
   1.507 +    public void setAttributeValueMapMemoryLimit(int size) {
   1.508 +        if (size < 0 ) {
   1.509 +            size = 0;
   1.510 +        }
   1.511 +
   1.512 +        attributeValueMapTotalCharactersConstraint = size / 2;
   1.513 +
   1.514 +    }
   1.515 +
   1.516 +    /**
   1.517 +     * {@inheritDoc}
   1.518 +     */
   1.519 +    public int getAttributeValueMapMemoryLimit() {
   1.520 +        return attributeValueMapTotalCharactersConstraint * 2;
   1.521 +    }
   1.522 +
   1.523 +    /**
   1.524 +     * Checks whether attribute value (its length) matches length limit
   1.525 +     *
   1.526 +     * @param length the length of attribute
   1.527 +     * @return whether attribute value matches limit
   1.528 +     */
   1.529 +    public boolean isAttributeValueLengthMatchesLimit(int length) {
   1.530 +        return length >= minAttributeValueSize &&
   1.531 +                length < maxAttributeValueSize;
   1.532 +    }
   1.533 +
   1.534 +    /**
   1.535 +     * Checks whether attribute table has enough memory to
   1.536 +     * store attribute value with the given length
   1.537 +     *
   1.538 +     * @param length the length of attribute value is checking to be added to Map.
   1.539 +     * @return whether attribute map has enough memory
   1.540 +     */
   1.541 +    public boolean canAddAttributeToTable(int length) {
   1.542 +        return _v.attributeValue.getTotalCharacterCount() + length <
   1.543 +                        attributeValueMapTotalCharactersConstraint;
   1.544 +    }
   1.545 +
   1.546 +    /**
   1.547 +     * {@inheritDoc}
   1.548 +     */
   1.549 +    public void setExternalVocabulary(ExternalVocabulary v) {
   1.550 +        // Create internal serializer vocabulary
   1.551 +        _v = new SerializerVocabulary();
   1.552 +        // Set the external vocabulary
   1.553 +        SerializerVocabulary ev = new SerializerVocabulary(v.vocabulary,
   1.554 +                _useLocalNameAsKeyForQualifiedNameLookup);
   1.555 +        _v.setExternalVocabulary(v.URI,
   1.556 +                ev, false);
   1.557 +
   1.558 +        _vIsInternal = true;
   1.559 +    }
   1.560 +
   1.561 +    /**
   1.562 +     * {@inheritDoc}
   1.563 +     */
   1.564 +    public void setVocabularyApplicationData(VocabularyApplicationData data) {
   1.565 +        _vData = data;
   1.566 +    }
   1.567 +
   1.568 +    /**
   1.569 +     * {@inheritDoc}
   1.570 +     */
   1.571 +    public VocabularyApplicationData getVocabularyApplicationData() {
   1.572 +        return _vData;
   1.573 +    }
   1.574 +
   1.575 +    // End of FastInfosetSerializer interface
   1.576 +
   1.577 +    /**
   1.578 +     * Reset the encoder for reuse encoding another XML infoset.
   1.579 +     */
   1.580 +    public void reset() {
   1.581 +        _terminate = false;
   1.582 +    }
   1.583 +
   1.584 +    /**
   1.585 +     * Set the OutputStream to encode the XML infoset to a
   1.586 +     * fast infoset document.
   1.587 +     *
   1.588 +     * @param s the OutputStream where the fast infoset document is written to.
   1.589 +     */
   1.590 +    public void setOutputStream(OutputStream s) {
   1.591 +        _octetBufferIndex = 0;
   1.592 +        _markIndex = -1;
   1.593 +        _s = s;
   1.594 +    }
   1.595 +
   1.596 +    /**
   1.597 +     * Set the SerializerVocabulary to be used for encoding.
   1.598 +     *
   1.599 +     * @param vocabulary the vocabulary to be used for encoding.
   1.600 +     */
   1.601 +    public void setVocabulary(SerializerVocabulary vocabulary) {
   1.602 +        _v = vocabulary;
   1.603 +        _vIsInternal = false;
   1.604 +    }
   1.605 +
   1.606 +    /**
   1.607 +     * Encode the header of a fast infoset document.
   1.608 +     *
   1.609 +     * @param encodeXmlDecl true if the XML declaration should be encoded.
   1.610 +     */
   1.611 +    protected final void encodeHeader(boolean encodeXmlDecl) throws IOException {
   1.612 +        if (encodeXmlDecl) {
   1.613 +            _s.write(EncodingConstants.XML_DECLARATION_VALUES[0]);
   1.614 +        }
   1.615 +        _s.write(EncodingConstants.BINARY_HEADER);
   1.616 +    }
   1.617 +
   1.618 +    /**
   1.619 +     * Encode the initial vocabulary of a fast infoset document.
   1.620 +     *
   1.621 +     */
   1.622 +    protected final void encodeInitialVocabulary() throws IOException {
   1.623 +        if (_v == null) {
   1.624 +            _v = new SerializerVocabulary();
   1.625 +            _vIsInternal = true;
   1.626 +        } else if (_vIsInternal) {
   1.627 +            _v.clear();
   1.628 +            if (_vData != null)
   1.629 +                _vData.clear();
   1.630 +        }
   1.631 +
   1.632 +        if (!_v.hasInitialVocabulary() && !_v.hasExternalVocabulary()) {
   1.633 +            write(0);
   1.634 +        } else if (_v.hasInitialVocabulary()) {
   1.635 +            _b = EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG;
   1.636 +            write(_b);
   1.637 +
   1.638 +            SerializerVocabulary initialVocabulary = _v.getReadOnlyVocabulary();
   1.639 +
   1.640 +            // TODO check for contents of vocabulary to assign bits
   1.641 +            if (initialVocabulary.hasExternalVocabulary()) {
   1.642 +                _b = EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG;
   1.643 +                write(_b);
   1.644 +                write(0);
   1.645 +            }
   1.646 +
   1.647 +            if (initialVocabulary.hasExternalVocabulary()) {
   1.648 +                encodeNonEmptyOctetStringOnSecondBit(_v.getExternalVocabularyURI());
   1.649 +            }
   1.650 +
   1.651 +            // TODO check for contents of vocabulary to encode values
   1.652 +        } else if (_v.hasExternalVocabulary()) {
   1.653 +            _b = EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG;
   1.654 +            write(_b);
   1.655 +
   1.656 +            _b = EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG;
   1.657 +            write(_b);
   1.658 +            write(0);
   1.659 +
   1.660 +            encodeNonEmptyOctetStringOnSecondBit(_v.getExternalVocabularyURI());
   1.661 +        }
   1.662 +    }
   1.663 +
   1.664 +    /**
   1.665 +     * Encode the termination of the Document Information Item.
   1.666 +     *
   1.667 +     */
   1.668 +    protected final void encodeDocumentTermination() throws IOException {
   1.669 +        encodeElementTermination();
   1.670 +        encodeTermination();
   1.671 +        _flush();
   1.672 +        _s.flush();
   1.673 +    }
   1.674 +
   1.675 +    /**
   1.676 +     * Encode the termination of an Element Information Item.
   1.677 +     *
   1.678 +     */
   1.679 +    protected final void encodeElementTermination() throws IOException {
   1.680 +        _terminate = true;
   1.681 +        switch (_b) {
   1.682 +            case EncodingConstants.TERMINATOR:
   1.683 +                _b = EncodingConstants.DOUBLE_TERMINATOR;
   1.684 +                break;
   1.685 +            case EncodingConstants.DOUBLE_TERMINATOR:
   1.686 +                write(EncodingConstants.DOUBLE_TERMINATOR);
   1.687 +            default:
   1.688 +                _b = EncodingConstants.TERMINATOR;
   1.689 +        }
   1.690 +    }
   1.691 +
   1.692 +    /**
   1.693 +     * Encode a termination if required.
   1.694 +     *
   1.695 +     */
   1.696 +    protected final void encodeTermination() throws IOException {
   1.697 +        if (_terminate) {
   1.698 +            write(_b);
   1.699 +            _b = 0;
   1.700 +            _terminate = false;
   1.701 +        }
   1.702 +    }
   1.703 +
   1.704 +    /**
   1.705 +     * Encode a Attribute Information Item that is a namespace declaration.
   1.706 +     *
   1.707 +     * @param prefix the prefix of the namespace declaration,
   1.708 +     * if "" then there is no prefix for the namespace declaration.
   1.709 +     * @param uri the URI of the namespace declaration,
   1.710 +     * if "" then there is no URI for the namespace declaration.
   1.711 +     */
   1.712 +    protected final void encodeNamespaceAttribute(String prefix, String uri) throws IOException {
   1.713 +        _b = EncodingConstants.NAMESPACE_ATTRIBUTE;
   1.714 +        if (prefix.length() > 0) {
   1.715 +            _b |= EncodingConstants.NAMESPACE_ATTRIBUTE_PREFIX_FLAG;
   1.716 +        }
   1.717 +        if (uri.length() > 0) {
   1.718 +            _b |= EncodingConstants.NAMESPACE_ATTRIBUTE_NAME_FLAG;
   1.719 +        }
   1.720 +
   1.721 +        // NOTE a prefix with out a namespace name is an undeclaration
   1.722 +        // of the namespace bound to the prefix
   1.723 +        // TODO needs to investigate how the startPrefixMapping works in
   1.724 +        // relation to undeclaration
   1.725 +
   1.726 +        write(_b);
   1.727 +
   1.728 +        if (prefix.length() > 0) {
   1.729 +            encodeIdentifyingNonEmptyStringOnFirstBit(prefix, _v.prefix);
   1.730 +        }
   1.731 +        if (uri.length() > 0) {
   1.732 +            encodeIdentifyingNonEmptyStringOnFirstBit(uri, _v.namespaceName);
   1.733 +        }
   1.734 +    }
   1.735 +
   1.736 +    /**
   1.737 +     * Encode a chunk of Character Information Items.
   1.738 +     *
   1.739 +     * @param ch the array of characters.
   1.740 +     * @param offset the offset into the array of characters.
   1.741 +     * @param length the length of characters.
   1.742 +     * @throws ArrayIndexOutOfBoundsException.
   1.743 +     */
   1.744 +    protected final void encodeCharacters(char[] ch, int offset, int length) throws IOException {
   1.745 +        final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
   1.746 +        encodeNonIdentifyingStringOnThirdBit(ch, offset, length, _v.characterContentChunk, addToTable, true);
   1.747 +    }
   1.748 +
   1.749 +    /**
   1.750 +     * Encode a chunk of Character Information Items.
   1.751 +     *
   1.752 +     * If the array of characters is to be indexed (as determined by
   1.753 +     * {@link Encoder#characterContentChunkSizeContraint}) then the array is not cloned
   1.754 +     * when adding the array to the vocabulary.
   1.755 +     *
   1.756 +     * @param ch the array of characters.
   1.757 +     * @param offset the offset into the array of characters.
   1.758 +     * @param length the length of characters.
   1.759 +     * @throws ArrayIndexOutOfBoundsException.
   1.760 +     */
   1.761 +    protected final void encodeCharactersNoClone(char[] ch, int offset, int length) throws IOException {
   1.762 +        final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
   1.763 +        encodeNonIdentifyingStringOnThirdBit(ch, offset, length, _v.characterContentChunk, addToTable, false);
   1.764 +    }
   1.765 +
   1.766 +    /**
   1.767 +     * Encode a chunk of Character Information Items using a numeric
   1.768 +     * alphabet that results in the encoding of a character in 4 bits
   1.769 +     * (or two characters per octet).
   1.770 +     *
   1.771 +     * @param id the restricted alphabet identifier.
   1.772 +     * @param table the table mapping characters to 4 bit values.
   1.773 +     * @param ch the array of characters.
   1.774 +     * @param offset the offset into the array of characters.
   1.775 +     * @param length the length of characters.
   1.776 +     * @param addToTable if characters should be added to table.
   1.777 +     * @throws ArrayIndexOutOfBoundsException.
   1.778 +     */
   1.779 +    protected final void encodeNumericFourBitCharacters(char[] ch, int offset, int length,
   1.780 +            boolean addToTable) throws FastInfosetException, IOException {
   1.781 +        encodeFourBitCharacters(RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX,
   1.782 +                NUMERIC_CHARACTERS_TABLE, ch, offset, length, addToTable);
   1.783 +    }
   1.784 +
   1.785 +    /**
   1.786 +     * Encode a chunk of Character Information Items using a date-time
   1.787 +     * alphabet that results in the encoding of a character in 4 bits
   1.788 +     * (or two characters per octet).
   1.789 +     *
   1.790 +     * @param id the restricted alphabet identifier.
   1.791 +     * @param table the table mapping characters to 4 bit values.
   1.792 +     * @param ch the array of characters.
   1.793 +     * @param offset the offset into the array of characters.
   1.794 +     * @param length the length of characters.
   1.795 +     * @param addToTable if characters should be added to table.
   1.796 +     * @throws ArrayIndexOutOfBoundsException.
   1.797 +     */
   1.798 +    protected final void encodeDateTimeFourBitCharacters(char[] ch, int offset, int length,
   1.799 +            boolean addToTable) throws FastInfosetException, IOException {
   1.800 +        encodeFourBitCharacters(RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX,
   1.801 +                DATE_TIME_CHARACTERS_TABLE, ch, offset, length, addToTable);
   1.802 +    }
   1.803 +
   1.804 +    /**
   1.805 +     * Encode a chunk of Character Information Items using a restricted
   1.806 +     * alphabet that results in the encoding of a character in 4 bits
   1.807 +     * (or two characters per octet).
   1.808 +     *
   1.809 +     * @param id the restricted alphabet identifier.
   1.810 +     * @param table the table mapping characters to 4 bit values.
   1.811 +     * @param ch the array of characters.
   1.812 +     * @param offset the offset into the array of characters.
   1.813 +     * @param length the length of characters.
   1.814 +     * @param addToTable if characters should be added to table.
   1.815 +     * @throws ArrayIndexOutOfBoundsException.
   1.816 +     */
   1.817 +    protected final void encodeFourBitCharacters(int id, int[] table, char[] ch, int offset, int length,
   1.818 +            boolean addToTable) throws FastInfosetException, IOException {
   1.819 +        if (addToTable) {
   1.820 +            // if char array could be added to table
   1.821 +            boolean canAddCharacterContentToTable =
   1.822 +                    canAddCharacterContentToTable(length, _v.characterContentChunk);
   1.823 +
   1.824 +            // obtain/get index
   1.825 +            int index = canAddCharacterContentToTable ?
   1.826 +                _v.characterContentChunk.obtainIndex(ch, offset, length, true) :
   1.827 +                _v.characterContentChunk.get(ch, offset, length);
   1.828 +
   1.829 +            if (index != KeyIntMap.NOT_PRESENT) {
   1.830 +                // if char array is in table
   1.831 +                _b = EncodingConstants.CHARACTER_CHUNK | 0x20;
   1.832 +                encodeNonZeroIntegerOnFourthBit(index);
   1.833 +                return;
   1.834 +            } else if (canAddCharacterContentToTable) {
   1.835 +                // if char array is not in table, but could be added
   1.836 +                _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG | EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG;
   1.837 +            } else {
   1.838 +                // if char array is not in table and could not be added
   1.839 +                _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
   1.840 +            }
   1.841 +        } else {
   1.842 +            _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
   1.843 +        }
   1.844 +
   1.845 +        write (_b);
   1.846 +
   1.847 +        // Encode bottom 6 bits of enoding algorithm id
   1.848 +        _b = id << 2;
   1.849 +
   1.850 +        encodeNonEmptyFourBitCharacterStringOnSeventhBit(table, ch, offset, length);
   1.851 +    }
   1.852 +
   1.853 +    /**
   1.854 +     * Encode a chunk of Character Information Items using a restricted
   1.855 +     * alphabet table.
   1.856 +     *
   1.857 +     * @param alphabet the alphabet defining the mapping between characters and
   1.858 +     *        integer values.
   1.859 +     * @param ch the array of characters.
   1.860 +     * @param offset the offset into the array of characters.
   1.861 +     * @param length the length of characters.
   1.862 +     * @param addToTable if characters should be added to table
   1.863 +     * @throws ArrayIndexOutOfBoundsException.
   1.864 +     * @throws FastInfosetException if the alphabet is not present in the
   1.865 +     *         vocabulary.
   1.866 +     */
   1.867 +    protected final void encodeAlphabetCharacters(String alphabet, char[] ch, int offset, int length,
   1.868 +            boolean addToTable) throws FastInfosetException, IOException {
   1.869 +        if (addToTable) {
   1.870 +            // if char array could be added to table
   1.871 +            boolean canAddCharacterContentToTable =
   1.872 +                    canAddCharacterContentToTable(length, _v.characterContentChunk);
   1.873 +
   1.874 +            // obtain/get index
   1.875 +            int index = canAddCharacterContentToTable ?
   1.876 +                _v.characterContentChunk.obtainIndex(ch, offset, length, true) :
   1.877 +                _v.characterContentChunk.get(ch, offset, length);
   1.878 +
   1.879 +            if (index != KeyIntMap.NOT_PRESENT) {
   1.880 +                // if char array is in table
   1.881 +                _b = EncodingConstants.CHARACTER_CHUNK | 0x20;
   1.882 +                encodeNonZeroIntegerOnFourthBit(index);
   1.883 +                return;
   1.884 +            } else if (canAddCharacterContentToTable) {
   1.885 +                // if char array is not in table, but could be added
   1.886 +                _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG | EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG;
   1.887 +            } else {
   1.888 +                // if char array is not in table and could not be added
   1.889 +                _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
   1.890 +            }
   1.891 +        } else {
   1.892 +            _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
   1.893 +        }
   1.894 +
   1.895 +        int id = _v.restrictedAlphabet.get(alphabet);
   1.896 +        if (id == KeyIntMap.NOT_PRESENT) {
   1.897 +            throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.restrictedAlphabetNotPresent"));
   1.898 +        }
   1.899 +        id += EncodingConstants.RESTRICTED_ALPHABET_APPLICATION_START;
   1.900 +
   1.901 +        _b |= (id & 0xC0) >> 6;
   1.902 +        write(_b);
   1.903 +
   1.904 +        // Encode bottom 6 bits of enoding algorithm id
   1.905 +        _b = (id & 0x3F) << 2;
   1.906 +
   1.907 +        encodeNonEmptyNBitCharacterStringOnSeventhBit(alphabet, ch, offset, length);
   1.908 +    }
   1.909 +
   1.910 +    /**
   1.911 +     * Encode a Processing Instruction Information Item.
   1.912 +     *
   1.913 +     * @param target the target of the processing instruction.
   1.914 +     * @param data the data of the processing instruction.
   1.915 +     */
   1.916 +    protected final void encodeProcessingInstruction(String target, String data) throws IOException {
   1.917 +        write(EncodingConstants.PROCESSING_INSTRUCTION);
   1.918 +
   1.919 +        // Target
   1.920 +        encodeIdentifyingNonEmptyStringOnFirstBit(target, _v.otherNCName);
   1.921 +
   1.922 +        // Data
   1.923 +        boolean addToTable = isCharacterContentChunkLengthMatchesLimit(data.length());
   1.924 +        encodeNonIdentifyingStringOnFirstBit(data, _v.otherString, addToTable);
   1.925 +    }
   1.926 +
   1.927 +    /**
   1.928 +     * Encode a Document Type Declaration.
   1.929 +     *
   1.930 +     * @param systemId the system identifier of the external subset.
   1.931 +     * @param publicId the public identifier of the external subset.
   1.932 +     */
   1.933 +    protected final void encodeDocumentTypeDeclaration(String systemId, String publicId) throws IOException {
   1.934 +        _b = EncodingConstants.DOCUMENT_TYPE_DECLARATION;
   1.935 +        if (systemId != null && systemId.length() > 0) {
   1.936 +            _b |= EncodingConstants.DOCUMENT_TYPE_SYSTEM_IDENTIFIER_FLAG;
   1.937 +        }
   1.938 +        if (publicId != null && publicId.length() > 0) {
   1.939 +            _b |= EncodingConstants.DOCUMENT_TYPE_PUBLIC_IDENTIFIER_FLAG;
   1.940 +        }
   1.941 +        write(_b);
   1.942 +
   1.943 +        if (systemId != null && systemId.length() > 0) {
   1.944 +            encodeIdentifyingNonEmptyStringOnFirstBit(systemId, _v.otherURI);
   1.945 +        }
   1.946 +        if (publicId != null && publicId.length() > 0) {
   1.947 +            encodeIdentifyingNonEmptyStringOnFirstBit(publicId, _v.otherURI);
   1.948 +        }
   1.949 +    }
   1.950 +
   1.951 +    /**
   1.952 +     * Encode a Comment Information Item.
   1.953 +     *
   1.954 +     * @param ch the array of characters that is as comment.
   1.955 +     * @param offset the offset into the array of characters.
   1.956 +     * @param length the length of characters.
   1.957 +     * @throws ArrayIndexOutOfBoundsException.
   1.958 +     */
   1.959 +    protected final void encodeComment(char[] ch, int offset, int length) throws IOException {
   1.960 +        write(EncodingConstants.COMMENT);
   1.961 +
   1.962 +        boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
   1.963 +        encodeNonIdentifyingStringOnFirstBit(ch, offset, length, _v.otherString, addToTable, true);
   1.964 +    }
   1.965 +
   1.966 +    /**
   1.967 +     * Encode a Comment Information Item.
   1.968 +     *
   1.969 +     * If the array of characters that is a comment is to be indexed (as
   1.970 +     * determined by {@link Encoder#characterContentChunkSizeContraint}) then
   1.971 +     * the array is not cloned when adding the array to the vocabulary.
   1.972 +     *
   1.973 +     * @param ch the array of characters.
   1.974 +     * @param offset the offset into the array of characters.
   1.975 +     * @param length the length of characters.
   1.976 +     * @throws ArrayIndexOutOfBoundsException.
   1.977 +     */
   1.978 +    protected final void encodeCommentNoClone(char[] ch, int offset, int length) throws IOException {
   1.979 +        write(EncodingConstants.COMMENT);
   1.980 +
   1.981 +        boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
   1.982 +        encodeNonIdentifyingStringOnFirstBit(ch, offset, length, _v.otherString, addToTable, false);
   1.983 +    }
   1.984 +
   1.985 +    /**
   1.986 +     * Encode a qualified name of an Element Informaiton Item on the third bit
   1.987 +     * of an octet.
   1.988 +     * Implementation of clause C.18 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
   1.989 +     *
   1.990 +     * <p>
   1.991 +     * The index of the qualified name will be encoded if the name is present
   1.992 +     * in the vocabulary otherwise the qualified name will be encoded literally
   1.993 +     * (see {@link #encodeLiteralElementQualifiedNameOnThirdBit}).
   1.994 +     *
   1.995 +     * @param namespaceURI the namespace URI of the qualified name.
   1.996 +     * @param prefix the prefix of the qualified name.
   1.997 +     * @param localName the local name of the qualified name.
   1.998 +     */
   1.999 +    protected final void encodeElementQualifiedNameOnThirdBit(String namespaceURI, String prefix, String localName) throws IOException {
  1.1000 +        LocalNameQualifiedNamesMap.Entry entry = _v.elementName.obtainEntry(localName);
  1.1001 +        if (entry._valueIndex > 0) {
  1.1002 +            QualifiedName[] names = entry._value;
  1.1003 +            for (int i = 0; i < entry._valueIndex; i++) {
  1.1004 +                if ((prefix == names[i].prefix || prefix.equals(names[i].prefix))
  1.1005 +                        && (namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) {
  1.1006 +                    encodeNonZeroIntegerOnThirdBit(names[i].index);
  1.1007 +                    return;
  1.1008 +                }
  1.1009 +            }
  1.1010 +        }
  1.1011 +
  1.1012 +        encodeLiteralElementQualifiedNameOnThirdBit(namespaceURI, prefix,
  1.1013 +                localName, entry);
  1.1014 +    }
  1.1015 +
  1.1016 +    /**
  1.1017 +     * Encode a literal qualified name of an Element Informaiton Item on the
  1.1018 +     * third bit of an octet.
  1.1019 +     * Implementation of clause C.18 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1020 +     *
  1.1021 +     * @param namespaceURI the namespace URI of the qualified name.
  1.1022 +     * @param prefix the prefix of the qualified name.
  1.1023 +     * @param localName the local name of the qualified name.
  1.1024 +     */
  1.1025 +    protected final void encodeLiteralElementQualifiedNameOnThirdBit(String namespaceURI, String prefix, String localName,
  1.1026 +            LocalNameQualifiedNamesMap.Entry entry) throws IOException {
  1.1027 +        QualifiedName name = new QualifiedName(prefix, namespaceURI, localName, "", _v.elementName.getNextIndex());
  1.1028 +        entry.addQualifiedName(name);
  1.1029 +
  1.1030 +        int namespaceURIIndex = KeyIntMap.NOT_PRESENT;
  1.1031 +        int prefixIndex = KeyIntMap.NOT_PRESENT;
  1.1032 +        if (namespaceURI.length() > 0) {
  1.1033 +            namespaceURIIndex = _v.namespaceName.get(namespaceURI);
  1.1034 +            if (namespaceURIIndex == KeyIntMap.NOT_PRESENT) {
  1.1035 +                throw new IOException(CommonResourceBundle.getInstance().getString("message.namespaceURINotIndexed", new Object[]{namespaceURI}));
  1.1036 +            }
  1.1037 +
  1.1038 +            if (prefix.length() > 0) {
  1.1039 +                prefixIndex = _v.prefix.get(prefix);
  1.1040 +                if (prefixIndex == KeyIntMap.NOT_PRESENT) {
  1.1041 +                    throw new IOException(CommonResourceBundle.getInstance().getString("message.prefixNotIndexed", new Object[]{prefix}));
  1.1042 +                }
  1.1043 +            }
  1.1044 +        }
  1.1045 +
  1.1046 +        int localNameIndex = _v.localName.obtainIndex(localName);
  1.1047 +
  1.1048 +        _b |= EncodingConstants.ELEMENT_LITERAL_QNAME_FLAG;
  1.1049 +        if (namespaceURIIndex >= 0) {
  1.1050 +            _b |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG;
  1.1051 +            if (prefixIndex >= 0) {
  1.1052 +                _b |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG;
  1.1053 +            }
  1.1054 +        }
  1.1055 +        write(_b);
  1.1056 +
  1.1057 +        if (namespaceURIIndex >= 0) {
  1.1058 +            if (prefixIndex >= 0) {
  1.1059 +                encodeNonZeroIntegerOnSecondBitFirstBitOne(prefixIndex);
  1.1060 +            }
  1.1061 +            encodeNonZeroIntegerOnSecondBitFirstBitOne(namespaceURIIndex);
  1.1062 +        }
  1.1063 +
  1.1064 +        if (localNameIndex >= 0) {
  1.1065 +            encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex);
  1.1066 +        } else {
  1.1067 +            encodeNonEmptyOctetStringOnSecondBit(localName);
  1.1068 +        }
  1.1069 +    }
  1.1070 +
  1.1071 +    /**
  1.1072 +     * Encode a qualified name of an Attribute Informaiton Item on the third bit
  1.1073 +     * of an octet.
  1.1074 +     * Implementation of clause C.17 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1075 +     *
  1.1076 +     * <p>
  1.1077 +     * The index of the qualified name will be encoded if the name is present
  1.1078 +     * in the vocabulary otherwise the qualified name will be encoded literally
  1.1079 +     * (see {@link #encodeLiteralAttributeQualifiedNameOnSecondBit}).
  1.1080 +     *
  1.1081 +     * @param namespaceURI the namespace URI of the qualified name.
  1.1082 +     * @param prefix the prefix of the qualified name.
  1.1083 +     * @param localName the local name of the qualified name.
  1.1084 +     */
  1.1085 +    protected final void encodeAttributeQualifiedNameOnSecondBit(String namespaceURI, String prefix, String localName) throws IOException {
  1.1086 +        LocalNameQualifiedNamesMap.Entry entry = _v.attributeName.obtainEntry(localName);
  1.1087 +        if (entry._valueIndex > 0) {
  1.1088 +            QualifiedName[] names = entry._value;
  1.1089 +            for (int i = 0; i < entry._valueIndex; i++) {
  1.1090 +                if ((prefix == names[i].prefix || prefix.equals(names[i].prefix))
  1.1091 +                        && (namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) {
  1.1092 +                    encodeNonZeroIntegerOnSecondBitFirstBitZero(names[i].index);
  1.1093 +                    return;
  1.1094 +                }
  1.1095 +            }
  1.1096 +        }
  1.1097 +
  1.1098 +        encodeLiteralAttributeQualifiedNameOnSecondBit(namespaceURI, prefix,
  1.1099 +                localName, entry);
  1.1100 +    }
  1.1101 +
  1.1102 +    /**
  1.1103 +     * Encode a literal qualified name of an Attribute Informaiton Item on the
  1.1104 +     * third bit of an octet.
  1.1105 +     * Implementation of clause C.17 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1106 +     *
  1.1107 +     * @param namespaceURI the namespace URI of the qualified name.
  1.1108 +     * @param prefix the prefix of the qualified name.
  1.1109 +     * @param localName the local name of the qualified name.
  1.1110 +     */
  1.1111 +    protected final boolean encodeLiteralAttributeQualifiedNameOnSecondBit(String namespaceURI, String prefix, String localName,
  1.1112 +                LocalNameQualifiedNamesMap.Entry entry) throws IOException {
  1.1113 +        int namespaceURIIndex = KeyIntMap.NOT_PRESENT;
  1.1114 +        int prefixIndex = KeyIntMap.NOT_PRESENT;
  1.1115 +        if (namespaceURI.length() > 0) {
  1.1116 +            namespaceURIIndex = _v.namespaceName.get(namespaceURI);
  1.1117 +            if (namespaceURIIndex == KeyIntMap.NOT_PRESENT) {
  1.1118 +                if (namespaceURI == EncodingConstants.XMLNS_NAMESPACE_NAME ||
  1.1119 +                        namespaceURI.equals(EncodingConstants.XMLNS_NAMESPACE_NAME)) {
  1.1120 +                    return false;
  1.1121 +                } else {
  1.1122 +                    throw new IOException(CommonResourceBundle.getInstance().getString("message.namespaceURINotIndexed", new Object[]{namespaceURI}));
  1.1123 +                }
  1.1124 +            }
  1.1125 +
  1.1126 +            if (prefix.length() > 0) {
  1.1127 +                prefixIndex = _v.prefix.get(prefix);
  1.1128 +                if (prefixIndex == KeyIntMap.NOT_PRESENT) {
  1.1129 +                    throw new IOException(CommonResourceBundle.getInstance().getString("message.prefixNotIndexed", new Object[]{prefix}));
  1.1130 +                }
  1.1131 +            }
  1.1132 +        }
  1.1133 +
  1.1134 +        int localNameIndex = _v.localName.obtainIndex(localName);
  1.1135 +
  1.1136 +        QualifiedName name = new QualifiedName(prefix, namespaceURI, localName, "", _v.attributeName.getNextIndex());
  1.1137 +        entry.addQualifiedName(name);
  1.1138 +
  1.1139 +        _b = EncodingConstants.ATTRIBUTE_LITERAL_QNAME_FLAG;
  1.1140 +        if (namespaceURI.length() > 0) {
  1.1141 +            _b |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG;
  1.1142 +            if (prefix.length() > 0) {
  1.1143 +                _b |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG;
  1.1144 +            }
  1.1145 +        }
  1.1146 +
  1.1147 +        write(_b);
  1.1148 +
  1.1149 +        if (namespaceURIIndex >= 0) {
  1.1150 +            if (prefixIndex >= 0) {
  1.1151 +                encodeNonZeroIntegerOnSecondBitFirstBitOne(prefixIndex);
  1.1152 +            }
  1.1153 +            encodeNonZeroIntegerOnSecondBitFirstBitOne(namespaceURIIndex);
  1.1154 +        } else if (namespaceURI != "") {
  1.1155 +            // XML prefix and namespace name
  1.1156 +            encodeNonEmptyOctetStringOnSecondBit("xml");
  1.1157 +            encodeNonEmptyOctetStringOnSecondBit("http://www.w3.org/XML/1998/namespace");
  1.1158 +        }
  1.1159 +
  1.1160 +        if (localNameIndex >= 0) {
  1.1161 +            encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex);
  1.1162 +        } else {
  1.1163 +            encodeNonEmptyOctetStringOnSecondBit(localName);
  1.1164 +        }
  1.1165 +
  1.1166 +        return true;
  1.1167 +    }
  1.1168 +
  1.1169 +    /**
  1.1170 +     * Encode a non identifying string on the first bit of an octet.
  1.1171 +     * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1172 +     *
  1.1173 +     * @param s the string to encode
  1.1174 +     * @param map the vocabulary table of strings to indexes.
  1.1175 +     * @param addToTable true if the string could be added to the vocabulary
  1.1176 +     *                   table (if table has enough memory)
  1.1177 +     * @param mustBeAddedToTable true if the string must be added to the vocabulary
  1.1178 +     *                   table (if not already present in the table).
  1.1179 +     */
  1.1180 +    protected final void encodeNonIdentifyingStringOnFirstBit(String s, StringIntMap map,
  1.1181 +            boolean addToTable, boolean mustBeAddedToTable) throws IOException {
  1.1182 +        if (s == null || s.length() == 0) {
  1.1183 +            // C.26 an index (first bit '1') with seven '1' bits for an empty string
  1.1184 +            write(0xFF);
  1.1185 +        } else {
  1.1186 +            if (addToTable || mustBeAddedToTable) {
  1.1187 +                // if attribute value could be added to table
  1.1188 +                boolean canAddAttributeToTable = mustBeAddedToTable ||
  1.1189 +                        canAddAttributeToTable(s.length());
  1.1190 +
  1.1191 +                // obtain/get index
  1.1192 +                int index = canAddAttributeToTable ?
  1.1193 +                    map.obtainIndex(s) :
  1.1194 +                    map.get(s);
  1.1195 +
  1.1196 +                if (index != KeyIntMap.NOT_PRESENT) {
  1.1197 +                    // if attribute value is in table
  1.1198 +                    encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
  1.1199 +                } else if (canAddAttributeToTable) {
  1.1200 +                    // if attribute value is not in table, but could be added
  1.1201 +                    _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG |
  1.1202 +                            _nonIdentifyingStringOnFirstBitCES;
  1.1203 +                    encodeNonEmptyCharacterStringOnFifthBit(s);
  1.1204 +                } else {
  1.1205 +                    // if attribute value is not in table and could not be added
  1.1206 +                    _b = _nonIdentifyingStringOnFirstBitCES;
  1.1207 +                    encodeNonEmptyCharacterStringOnFifthBit(s);
  1.1208 +                }
  1.1209 +            } else {
  1.1210 +                _b = _nonIdentifyingStringOnFirstBitCES;
  1.1211 +                encodeNonEmptyCharacterStringOnFifthBit(s);
  1.1212 +            }
  1.1213 +        }
  1.1214 +    }
  1.1215 +
  1.1216 +    /**
  1.1217 +     * Encode a non identifying string on the first bit of an octet.
  1.1218 +     * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1219 +     *
  1.1220 +     * @param s the string to encode
  1.1221 +     * @param map the vocabulary table of character arrays to indexes.
  1.1222 +     * @param addToTable true if the string should be added to the vocabulary
  1.1223 +     *                   table (if not already present in the table).
  1.1224 +     */
  1.1225 +    protected final void encodeNonIdentifyingStringOnFirstBit(String s, CharArrayIntMap map, boolean addToTable) throws IOException {
  1.1226 +        if (s == null || s.length() == 0) {
  1.1227 +            // C.26 an index (first bit '1') with seven '1' bits for an empty string
  1.1228 +            write(0xFF);
  1.1229 +        } else {
  1.1230 +            if (addToTable) {
  1.1231 +                final char[] ch = s.toCharArray();
  1.1232 +                final int length = s.length();
  1.1233 +
  1.1234 +                // if char array could be added to table
  1.1235 +                boolean canAddCharacterContentToTable =
  1.1236 +                        canAddCharacterContentToTable(length, map);
  1.1237 +
  1.1238 +                // obtain/get index
  1.1239 +                int index = canAddCharacterContentToTable ?
  1.1240 +                    map.obtainIndex(ch, 0, length, false) :
  1.1241 +                    map.get(ch, 0, length);
  1.1242 +
  1.1243 +                if (index != KeyIntMap.NOT_PRESENT) {
  1.1244 +                    // if char array is in table
  1.1245 +                    encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
  1.1246 +                } else if (canAddCharacterContentToTable) {
  1.1247 +                    // if char array is not in table, but could be added
  1.1248 +                    _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG |
  1.1249 +                            _nonIdentifyingStringOnFirstBitCES;
  1.1250 +                    encodeNonEmptyCharacterStringOnFifthBit(ch, 0, length);
  1.1251 +                } else {
  1.1252 +                    // if char array is not in table and could not be added
  1.1253 +                    _b = _nonIdentifyingStringOnFirstBitCES;
  1.1254 +                    encodeNonEmptyCharacterStringOnFifthBit(s);
  1.1255 +                }
  1.1256 +            } else {
  1.1257 +                _b = _nonIdentifyingStringOnFirstBitCES;
  1.1258 +                encodeNonEmptyCharacterStringOnFifthBit(s);
  1.1259 +            }
  1.1260 +        }
  1.1261 +    }
  1.1262 +
  1.1263 +    /**
  1.1264 +     * Encode a non identifying string on the first bit of an octet.
  1.1265 +     * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1266 +     *
  1.1267 +     * @param ch the array of characters.
  1.1268 +     * @param offset the offset into the array of characters.
  1.1269 +     * @param length the length of characters.
  1.1270 +     * @param map the vocabulary table of character arrays to indexes.
  1.1271 +     * @param addToTable true if the string should be added to the vocabulary
  1.1272 +     *                   table (if not already present in the table).
  1.1273 +     * @param clone true if the array of characters should be cloned if added
  1.1274 +     *              to the vocabulary table.
  1.1275 +     */
  1.1276 +    protected final void encodeNonIdentifyingStringOnFirstBit(char[] ch, int offset, int length, CharArrayIntMap map,
  1.1277 +            boolean addToTable, boolean clone) throws IOException {
  1.1278 +        if (length == 0) {
  1.1279 +            // C.26 an index (first bit '1') with seven '1' bits for an empty string
  1.1280 +            write(0xFF);
  1.1281 +        } else {
  1.1282 +            if (addToTable) {
  1.1283 +                // if char array could be added to table
  1.1284 +                boolean canAddCharacterContentToTable =
  1.1285 +                        canAddCharacterContentToTable(length, map);
  1.1286 +
  1.1287 +                // obtain/get index
  1.1288 +                int index = canAddCharacterContentToTable ?
  1.1289 +                    map.obtainIndex(ch, offset, length, clone) :
  1.1290 +                    map.get(ch, offset, length);
  1.1291 +
  1.1292 +                if (index != KeyIntMap.NOT_PRESENT) {
  1.1293 +                    // if char array is in table
  1.1294 +                    encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
  1.1295 +                } else if (canAddCharacterContentToTable) {
  1.1296 +                    // if char array is not in table, but could be added
  1.1297 +                    _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG |
  1.1298 +                            _nonIdentifyingStringOnFirstBitCES;
  1.1299 +                    encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length);
  1.1300 +                } else {
  1.1301 +                    // if char array is not in table and could not be added
  1.1302 +                    _b = _nonIdentifyingStringOnFirstBitCES;
  1.1303 +                    encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length);
  1.1304 +                }
  1.1305 +            } else {
  1.1306 +                _b = _nonIdentifyingStringOnFirstBitCES;
  1.1307 +                encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length);
  1.1308 +            }
  1.1309 +        }
  1.1310 +    }
  1.1311 +
  1.1312 +    protected final void encodeNumericNonIdentifyingStringOnFirstBit(
  1.1313 +            String s, boolean addToTable, boolean mustBeAddedToTable)
  1.1314 +            throws IOException, FastInfosetException {
  1.1315 +        encodeNonIdentifyingStringOnFirstBit(
  1.1316 +                                    RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX,
  1.1317 +                                    NUMERIC_CHARACTERS_TABLE, s, addToTable,
  1.1318 +                                    mustBeAddedToTable);
  1.1319 +    }
  1.1320 +
  1.1321 +    protected final void encodeDateTimeNonIdentifyingStringOnFirstBit(
  1.1322 +            String s, boolean addToTable, boolean mustBeAddedToTable)
  1.1323 +            throws IOException, FastInfosetException {
  1.1324 +        encodeNonIdentifyingStringOnFirstBit(
  1.1325 +                                    RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX,
  1.1326 +                                    DATE_TIME_CHARACTERS_TABLE, s, addToTable,
  1.1327 +                                    mustBeAddedToTable);
  1.1328 +    }
  1.1329 +
  1.1330 +    protected final void encodeNonIdentifyingStringOnFirstBit(int id, int[] table,
  1.1331 +            String s, boolean addToTable, boolean mustBeAddedToTable)
  1.1332 +            throws IOException, FastInfosetException {
  1.1333 +        if (s == null || s.length() == 0) {
  1.1334 +            // C.26 an index (first bit '1') with seven '1' bits for an empty string
  1.1335 +            write(0xFF);
  1.1336 +            return;
  1.1337 +        }
  1.1338 +
  1.1339 +        if (addToTable || mustBeAddedToTable) {
  1.1340 +            // if attribute value could be added to table
  1.1341 +            boolean canAddAttributeToTable = mustBeAddedToTable ||
  1.1342 +                    canAddAttributeToTable(s.length());
  1.1343 +
  1.1344 +            // obtain/get index
  1.1345 +            int index = canAddAttributeToTable ?
  1.1346 +                _v.attributeValue.obtainIndex(s) :
  1.1347 +                _v.attributeValue.get(s);
  1.1348 +
  1.1349 +            if (index != KeyIntMap.NOT_PRESENT) {
  1.1350 +                // if attribute value is in table
  1.1351 +                encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
  1.1352 +                return;
  1.1353 +            } else if (canAddAttributeToTable) {
  1.1354 +                // if attribute value is not in table, but could be added
  1.1355 +                _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG |
  1.1356 +                        EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG;
  1.1357 +            } else {
  1.1358 +                // if attribute value is not in table and could not be added
  1.1359 +                _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG;
  1.1360 +            }
  1.1361 +        } else {
  1.1362 +            _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG;
  1.1363 +        }
  1.1364 +
  1.1365 +        // Encode identification and top four bits of alphabet id
  1.1366 +        write (_b | ((id & 0xF0) >> 4));
  1.1367 +        // Encode bottom 4 bits of alphabet id
  1.1368 +        _b = (id & 0x0F) << 4;
  1.1369 +
  1.1370 +        final int length = s.length();
  1.1371 +        final int octetPairLength = length / 2;
  1.1372 +        final int octetSingleLength = length % 2;
  1.1373 +        encodeNonZeroOctetStringLengthOnFifthBit(octetPairLength + octetSingleLength);
  1.1374 +        encodeNonEmptyFourBitCharacterString(table, s.toCharArray(), 0, octetPairLength, octetSingleLength);
  1.1375 +    }
  1.1376 +
  1.1377 +    /**
  1.1378 +     * Encode a non identifying string on the first bit of an octet as binary
  1.1379 +     * data using an encoding algorithm.
  1.1380 +     * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1381 +     *
  1.1382 +     * @param URI the encoding algorithm URI. If the URI == null then the
  1.1383 +     *            encoding algorithm identifier takes precendence.
  1.1384 +     * @param id the encoding algorithm identifier.
  1.1385 +     * @param data the data to be encoded using an encoding algorithm.
  1.1386 +     * @throws EncodingAlgorithmException if the encoding algorithm URI is not
  1.1387 +     *         present in the vocabulary, or the encoding algorithm identifier
  1.1388 +     *         is not with the required range.
  1.1389 +     */
  1.1390 +    protected final void encodeNonIdentifyingStringOnFirstBit(String URI, int id, Object data) throws FastInfosetException, IOException {
  1.1391 +        if (URI != null) {
  1.1392 +            id = _v.encodingAlgorithm.get(URI);
  1.1393 +            if (id == KeyIntMap.NOT_PRESENT) {
  1.1394 +                throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI}));
  1.1395 +            }
  1.1396 +            id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START;
  1.1397 +
  1.1398 +            EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI);
  1.1399 +            if (ea != null) {
  1.1400 +                encodeAIIObjectAlgorithmData(id, data, ea);
  1.1401 +            } else {
  1.1402 +                if (data instanceof byte[]) {
  1.1403 +                    byte[] d = (byte[])data;
  1.1404 +                    encodeAIIOctetAlgorithmData(id, d, 0, d.length);
  1.1405 +                } else {
  1.1406 +                    throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
  1.1407 +                }
  1.1408 +            }
  1.1409 +        } else if (id <= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) {
  1.1410 +            int length = 0;
  1.1411 +            switch(id) {
  1.1412 +                case EncodingAlgorithmIndexes.HEXADECIMAL:
  1.1413 +                case EncodingAlgorithmIndexes.BASE64:
  1.1414 +                    length = ((byte[])data).length;
  1.1415 +                    break;
  1.1416 +                case EncodingAlgorithmIndexes.SHORT:
  1.1417 +                    length = ((short[])data).length;
  1.1418 +                    break;
  1.1419 +                case EncodingAlgorithmIndexes.INT:
  1.1420 +                    length = ((int[])data).length;
  1.1421 +                    break;
  1.1422 +                case EncodingAlgorithmIndexes.LONG:
  1.1423 +                case EncodingAlgorithmIndexes.UUID:
  1.1424 +                    length = ((long[])data).length;
  1.1425 +                    break;
  1.1426 +                case EncodingAlgorithmIndexes.BOOLEAN:
  1.1427 +                    length = ((boolean[])data).length;
  1.1428 +                    break;
  1.1429 +                case EncodingAlgorithmIndexes.FLOAT:
  1.1430 +                    length = ((float[])data).length;
  1.1431 +                    break;
  1.1432 +                case EncodingAlgorithmIndexes.DOUBLE:
  1.1433 +                    length = ((double[])data).length;
  1.1434 +                    break;
  1.1435 +                case EncodingAlgorithmIndexes.CDATA:
  1.1436 +                    throw new UnsupportedOperationException(CommonResourceBundle.getInstance().getString("message.CDATA"));
  1.1437 +                default:
  1.1438 +                    throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.UnsupportedBuiltInAlgorithm", new Object[]{Integer.valueOf(id)}));
  1.1439 +            }
  1.1440 +            encodeAIIBuiltInAlgorithmData(id, data, 0, length);
  1.1441 +        } else if (id >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) {
  1.1442 +            if (data instanceof byte[]) {
  1.1443 +                byte[] d = (byte[])data;
  1.1444 +                encodeAIIOctetAlgorithmData(id, d, 0, d.length);
  1.1445 +            } else {
  1.1446 +                throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
  1.1447 +            }
  1.1448 +        } else {
  1.1449 +            throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved"));
  1.1450 +        }
  1.1451 +    }
  1.1452 +
  1.1453 +    /**
  1.1454 +     * Encode the [normalized value] of an Attribute Information Item using
  1.1455 +     * using an encoding algorithm.
  1.1456 +     * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1457 +     *
  1.1458 +     * @param id the encoding algorithm identifier.
  1.1459 +     * @param d the data, as an array of bytes, to be encoded.
  1.1460 +     * @param offset the offset into the array of bytes.
  1.1461 +     * @param length the length of bytes.
  1.1462 +     */
  1.1463 +    protected final void encodeAIIOctetAlgorithmData(int id, byte[] d, int offset, int length) throws IOException {
  1.1464 +        // Encode identification and top four bits of encoding algorithm id
  1.1465 +        write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG |
  1.1466 +                ((id & 0xF0) >> 4));
  1.1467 +
  1.1468 +        // Encode bottom 4 bits of enoding algorithm id
  1.1469 +        _b = (id & 0x0F) << 4;
  1.1470 +
  1.1471 +        // Encode the length
  1.1472 +        encodeNonZeroOctetStringLengthOnFifthBit(length);
  1.1473 +
  1.1474 +        write(d, offset, length);
  1.1475 +    }
  1.1476 +
  1.1477 +    /**
  1.1478 +     * Encode the [normalized value] of an Attribute Information Item using
  1.1479 +     * using an encoding algorithm.
  1.1480 +     * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1481 +     *
  1.1482 +     * @param id the encoding algorithm identifier.
  1.1483 +     * @param data the data to be encoded using an encoding algorithm.
  1.1484 +     * @param ea the encoding algorithm to use to encode the data into an
  1.1485 +     *           array of bytes.
  1.1486 +     */
  1.1487 +    protected final void encodeAIIObjectAlgorithmData(int id, Object data, EncodingAlgorithm ea) throws FastInfosetException, IOException {
  1.1488 +        // Encode identification and top four bits of encoding algorithm id
  1.1489 +        write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG |
  1.1490 +                ((id & 0xF0) >> 4));
  1.1491 +
  1.1492 +        // Encode bottom 4 bits of enoding algorithm id
  1.1493 +        _b = (id & 0x0F) << 4;
  1.1494 +
  1.1495 +        _encodingBufferOutputStream.reset();
  1.1496 +        ea.encodeToOutputStream(data, _encodingBufferOutputStream);
  1.1497 +        encodeNonZeroOctetStringLengthOnFifthBit(_encodingBufferIndex);
  1.1498 +        write(_encodingBuffer, _encodingBufferIndex);
  1.1499 +    }
  1.1500 +
  1.1501 +    /**
  1.1502 +     * Encode the [normalized value] of an Attribute Information Item using
  1.1503 +     * using a built in encoding algorithm.
  1.1504 +     * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1505 +     *
  1.1506 +     * @param id the built in encoding algorithm identifier.
  1.1507 +     * @param data the data to be encoded using an encoding algorithm. The data
  1.1508 +     *        represents an array of items specified by the encoding algorithm
  1.1509 +     *        identifier
  1.1510 +     * @param offset the offset into the array of bytes.
  1.1511 +     * @param length the length of bytes.
  1.1512 +     */
  1.1513 +    protected final void encodeAIIBuiltInAlgorithmData(int id, Object data, int offset, int length) throws IOException {
  1.1514 +        // Encode identification and top four bits of encoding algorithm id
  1.1515 +        write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG |
  1.1516 +                ((id & 0xF0) >> 4));
  1.1517 +
  1.1518 +        // Encode bottom 4 bits of enoding algorithm id
  1.1519 +        _b = (id & 0x0F) << 4;
  1.1520 +
  1.1521 +        final int octetLength = BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
  1.1522 +                    getOctetLengthFromPrimitiveLength(length);
  1.1523 +
  1.1524 +        encodeNonZeroOctetStringLengthOnFifthBit(octetLength);
  1.1525 +
  1.1526 +        ensureSize(octetLength);
  1.1527 +        BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
  1.1528 +                encodeToBytes(data, offset, length, _octetBuffer, _octetBufferIndex);
  1.1529 +        _octetBufferIndex += octetLength;
  1.1530 +    }
  1.1531 +
  1.1532 +    /**
  1.1533 +     * Encode a non identifying string on the third bit of an octet.
  1.1534 +     * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1535 +     *
  1.1536 +     * @param ch the array of characters.
  1.1537 +     * @param offset the offset into the array of characters.
  1.1538 +     * @param length the length of characters.
  1.1539 +     * @param map the vocabulary table of character arrays to indexes.
  1.1540 +     * @param addToTable true if the array of characters should be added to the vocabulary
  1.1541 +     *                   table (if not already present in the table).
  1.1542 +     * @param clone true if the array of characters should be cloned if added
  1.1543 +     *              to the vocabulary table.
  1.1544 +     */
  1.1545 +    protected final void encodeNonIdentifyingStringOnThirdBit(char[] ch, int offset, int length,
  1.1546 +            CharArrayIntMap map, boolean addToTable, boolean clone) throws IOException {
  1.1547 +        // length cannot be zero since sequence of CIIs has to be > 0
  1.1548 +
  1.1549 +        if (addToTable) {
  1.1550 +            // if char array could be added to table
  1.1551 +            boolean canAddCharacterContentToTable =
  1.1552 +                    canAddCharacterContentToTable(length, map);
  1.1553 +
  1.1554 +            // obtain/get index
  1.1555 +            int index = canAddCharacterContentToTable ?
  1.1556 +                map.obtainIndex(ch, offset, length, clone) :
  1.1557 +                map.get(ch, offset, length);
  1.1558 +
  1.1559 +            if (index != KeyIntMap.NOT_PRESENT) {
  1.1560 +                // if char array is in table
  1.1561 +                _b = EncodingConstants.CHARACTER_CHUNK | 0x20;
  1.1562 +                encodeNonZeroIntegerOnFourthBit(index);
  1.1563 +            } else if (canAddCharacterContentToTable) {
  1.1564 +                // if char array is not in table, but could be added
  1.1565 +                _b = EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG |
  1.1566 +                        _nonIdentifyingStringOnThirdBitCES;
  1.1567 +                encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length);
  1.1568 +            } else {
  1.1569 +                // if char array is not in table and could not be added
  1.1570 +                    _b = _nonIdentifyingStringOnThirdBitCES;
  1.1571 +                    encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length);
  1.1572 +            }
  1.1573 +        } else {
  1.1574 +            // char array will not be added to map
  1.1575 +            _b = _nonIdentifyingStringOnThirdBitCES;
  1.1576 +            encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length);
  1.1577 +        }
  1.1578 +    }
  1.1579 +
  1.1580 +    /**
  1.1581 +     * Encode a non identifying string on the third bit of an octet as binary
  1.1582 +     * data using an encoding algorithm.
  1.1583 +     * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1584 +     *
  1.1585 +     * @param URI the encoding algorithm URI. If the URI == null then the
  1.1586 +     *            encoding algorithm identifier takes precendence.
  1.1587 +     * @param id the encoding algorithm identifier.
  1.1588 +     * @param data the data to be encoded using an encoding algorithm.
  1.1589 +     * @throws EncodingAlgorithmException if the encoding algorithm URI is not
  1.1590 +     *         present in the vocabulary, or the encoding algorithm identifier
  1.1591 +     *         is not with the required range.
  1.1592 +     */
  1.1593 +    protected final void encodeNonIdentifyingStringOnThirdBit(String URI, int id, Object data) throws FastInfosetException, IOException {
  1.1594 +        if (URI != null) {
  1.1595 +            id = _v.encodingAlgorithm.get(URI);
  1.1596 +            if (id == KeyIntMap.NOT_PRESENT) {
  1.1597 +                throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI}));
  1.1598 +            }
  1.1599 +            id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START;
  1.1600 +
  1.1601 +            EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI);
  1.1602 +            if (ea != null) {
  1.1603 +                encodeCIIObjectAlgorithmData(id, data, ea);
  1.1604 +            } else {
  1.1605 +                if (data instanceof byte[]) {
  1.1606 +                    byte[] d = (byte[])data;
  1.1607 +                    encodeCIIOctetAlgorithmData(id, d, 0, d.length);
  1.1608 +                } else {
  1.1609 +                    throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
  1.1610 +                }
  1.1611 +            }
  1.1612 +        } else if (id <= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) {
  1.1613 +            int length = 0;
  1.1614 +            switch(id) {
  1.1615 +                case EncodingAlgorithmIndexes.HEXADECIMAL:
  1.1616 +                case EncodingAlgorithmIndexes.BASE64:
  1.1617 +                    length = ((byte[])data).length;
  1.1618 +                    break;
  1.1619 +                case EncodingAlgorithmIndexes.SHORT:
  1.1620 +                    length = ((short[])data).length;
  1.1621 +                    break;
  1.1622 +                case EncodingAlgorithmIndexes.INT:
  1.1623 +                    length = ((int[])data).length;
  1.1624 +                    break;
  1.1625 +                case EncodingAlgorithmIndexes.LONG:
  1.1626 +                case EncodingAlgorithmIndexes.UUID:
  1.1627 +                    length = ((long[])data).length;
  1.1628 +                    break;
  1.1629 +                case EncodingAlgorithmIndexes.BOOLEAN:
  1.1630 +                    length = ((boolean[])data).length;
  1.1631 +                    break;
  1.1632 +                case EncodingAlgorithmIndexes.FLOAT:
  1.1633 +                    length = ((float[])data).length;
  1.1634 +                    break;
  1.1635 +                case EncodingAlgorithmIndexes.DOUBLE:
  1.1636 +                    length = ((double[])data).length;
  1.1637 +                    break;
  1.1638 +                case EncodingAlgorithmIndexes.CDATA:
  1.1639 +                    throw new UnsupportedOperationException(CommonResourceBundle.getInstance().getString("message.CDATA"));
  1.1640 +                default:
  1.1641 +                    throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.UnsupportedBuiltInAlgorithm", new Object[]{Integer.valueOf(id)}));
  1.1642 +            }
  1.1643 +            encodeCIIBuiltInAlgorithmData(id, data, 0, length);
  1.1644 +        } else if (id >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) {
  1.1645 +            if (data instanceof byte[]) {
  1.1646 +                byte[] d = (byte[])data;
  1.1647 +                encodeCIIOctetAlgorithmData(id, d, 0, d.length);
  1.1648 +            } else {
  1.1649 +                throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
  1.1650 +            }
  1.1651 +        } else {
  1.1652 +            throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved"));
  1.1653 +        }
  1.1654 +    }
  1.1655 +
  1.1656 +    /**
  1.1657 +     * Encode a non identifying string on the third bit of an octet as binary
  1.1658 +     * data using an encoding algorithm.
  1.1659 +     * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1660 +     *
  1.1661 +     * @param URI the encoding algorithm URI. If the URI == null then the
  1.1662 +     *            encoding algorithm identifier takes precendence.
  1.1663 +     * @param id the encoding algorithm identifier.
  1.1664 +     * @param d the data, as an array of bytes, to be encoded.
  1.1665 +     * @param offset the offset into the array of bytes.
  1.1666 +     * @param length the length of bytes.
  1.1667 +     * @throws EncodingAlgorithmException if the encoding algorithm URI is not
  1.1668 +     *         present in the vocabulary.
  1.1669 +     */
  1.1670 +    protected final void encodeNonIdentifyingStringOnThirdBit(String URI, int id, byte[] d, int offset, int length) throws FastInfosetException, IOException {
  1.1671 +        if (URI != null) {
  1.1672 +            id = _v.encodingAlgorithm.get(URI);
  1.1673 +            if (id == KeyIntMap.NOT_PRESENT) {
  1.1674 +                throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI}));
  1.1675 +            }
  1.1676 +            id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START;
  1.1677 +        }
  1.1678 +
  1.1679 +        encodeCIIOctetAlgorithmData(id, d, offset, length);
  1.1680 +    }
  1.1681 +
  1.1682 +    /**
  1.1683 +     * Encode a chunk of Character Information Items using
  1.1684 +     * using an encoding algorithm.
  1.1685 +     * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1686 +     *
  1.1687 +     * @param id the encoding algorithm identifier.
  1.1688 +     * @param d the data, as an array of bytes, to be encoded.
  1.1689 +     * @param offset the offset into the array of bytes.
  1.1690 +     * @param length the length of bytes.
  1.1691 +     */
  1.1692 +    protected final void encodeCIIOctetAlgorithmData(int id, byte[] d, int offset, int length) throws IOException {
  1.1693 +        // Encode identification and top two bits of encoding algorithm id
  1.1694 +        write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG |
  1.1695 +                ((id & 0xC0) >> 6));
  1.1696 +
  1.1697 +        // Encode bottom 6 bits of enoding algorithm id
  1.1698 +        _b = (id & 0x3F) << 2;
  1.1699 +
  1.1700 +        // Encode the length
  1.1701 +        encodeNonZeroOctetStringLengthOnSenventhBit(length);
  1.1702 +
  1.1703 +        write(d, offset, length);
  1.1704 +    }
  1.1705 +
  1.1706 +    /**
  1.1707 +     * Encode a chunk of Character Information Items using
  1.1708 +     * using an encoding algorithm.
  1.1709 +     * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1710 +     *
  1.1711 +     * @param id the encoding algorithm identifier.
  1.1712 +     * @param data the data to be encoded using an encoding algorithm.
  1.1713 +     * @param ea the encoding algorithm to use to encode the data into an
  1.1714 +     *           array of bytes.
  1.1715 +     */
  1.1716 +    protected final void encodeCIIObjectAlgorithmData(int id, Object data, EncodingAlgorithm ea) throws FastInfosetException, IOException {
  1.1717 +        // Encode identification and top two bits of encoding algorithm id
  1.1718 +        write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG |
  1.1719 +                ((id & 0xC0) >> 6));
  1.1720 +
  1.1721 +        // Encode bottom 6 bits of enoding algorithm id
  1.1722 +        _b = (id & 0x3F) << 2;
  1.1723 +
  1.1724 +        _encodingBufferOutputStream.reset();
  1.1725 +        ea.encodeToOutputStream(data, _encodingBufferOutputStream);
  1.1726 +        encodeNonZeroOctetStringLengthOnSenventhBit(_encodingBufferIndex);
  1.1727 +        write(_encodingBuffer, _encodingBufferIndex);
  1.1728 +    }
  1.1729 +
  1.1730 +    /**
  1.1731 +     * Encode a chunk of Character Information Items using
  1.1732 +     * using an encoding algorithm.
  1.1733 +     * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1734 +     *
  1.1735 +     * @param id the built in encoding algorithm identifier.
  1.1736 +     * @param data the data to be encoded using an encoding algorithm. The data
  1.1737 +     *        represents an array of items specified by the encoding algorithm
  1.1738 +     *        identifier
  1.1739 +     * @param offset the offset into the array of bytes.
  1.1740 +     * @param length the length of bytes.
  1.1741 +     */
  1.1742 +    protected final void encodeCIIBuiltInAlgorithmData(int id, Object data, int offset, int length) throws FastInfosetException, IOException {
  1.1743 +        // Encode identification and top two bits of encoding algorithm id
  1.1744 +        write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG |
  1.1745 +                ((id & 0xC0) >> 6));
  1.1746 +
  1.1747 +        // Encode bottom 6 bits of enoding algorithm id
  1.1748 +        _b = (id & 0x3F) << 2;
  1.1749 +
  1.1750 +        final int octetLength = BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
  1.1751 +                    getOctetLengthFromPrimitiveLength(length);
  1.1752 +
  1.1753 +        encodeNonZeroOctetStringLengthOnSenventhBit(octetLength);
  1.1754 +
  1.1755 +        ensureSize(octetLength);
  1.1756 +        BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
  1.1757 +                encodeToBytes(data, offset, length, _octetBuffer, _octetBufferIndex);
  1.1758 +        _octetBufferIndex += octetLength;
  1.1759 +    }
  1.1760 +
  1.1761 +    /**
  1.1762 +     * Encode a chunk of Character Information Items using
  1.1763 +     * using the CDATA built in encoding algorithm.
  1.1764 +     * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1765 +     *
  1.1766 +     * @param ch the array of characters.
  1.1767 +     * @param offset the offset into the array of characters.
  1.1768 +     * @param length the length of characters.
  1.1769 +     */
  1.1770 +    protected final void encodeCIIBuiltInAlgorithmDataAsCDATA(char[] ch, int offset, int length) throws FastInfosetException, IOException {
  1.1771 +        // Encode identification and top two bits of encoding algorithm id
  1.1772 +        write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG);
  1.1773 +
  1.1774 +        // Encode bottom 6 bits of enoding algorithm id
  1.1775 +        _b = EncodingAlgorithmIndexes.CDATA << 2;
  1.1776 +
  1.1777 +
  1.1778 +        length = encodeUTF8String(ch, offset, length);
  1.1779 +        encodeNonZeroOctetStringLengthOnSenventhBit(length);
  1.1780 +        write(_encodingBuffer, length);
  1.1781 +    }
  1.1782 +
  1.1783 +    /**
  1.1784 +     * Encode a non empty identifying string on the first bit of an octet.
  1.1785 +     * Implementation of clause C.13 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1786 +     *
  1.1787 +     * @param s the identifying string.
  1.1788 +     * @param map the vocabulary table to use to determin the index of the
  1.1789 +     *        identifying string
  1.1790 +     */
  1.1791 +    protected final void encodeIdentifyingNonEmptyStringOnFirstBit(String s, StringIntMap map) throws IOException {
  1.1792 +        int index = map.obtainIndex(s);
  1.1793 +        if (index == KeyIntMap.NOT_PRESENT) {
  1.1794 +            // _b = 0;
  1.1795 +            encodeNonEmptyOctetStringOnSecondBit(s);
  1.1796 +        } else {
  1.1797 +            // _b = 0x80;
  1.1798 +            encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
  1.1799 +        }
  1.1800 +    }
  1.1801 +
  1.1802 +    /**
  1.1803 +     * Encode a non empty string on the second bit of an octet using the UTF-8
  1.1804 +     * encoding.
  1.1805 +     * Implementation of clause C.22 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1806 +     *
  1.1807 +     * @param s the string.
  1.1808 +     */
  1.1809 +    protected final void encodeNonEmptyOctetStringOnSecondBit(String s) throws IOException {
  1.1810 +        final int length = encodeUTF8String(s);
  1.1811 +        encodeNonZeroOctetStringLengthOnSecondBit(length);
  1.1812 +        write(_encodingBuffer, length);
  1.1813 +    }
  1.1814 +
  1.1815 +    /**
  1.1816 +     * Encode the length of a UTF-8 encoded string on the second bit of an octet.
  1.1817 +     * Implementation of clause C.22 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1818 +     *
  1.1819 +     * @param length the length to encode.
  1.1820 +     */
  1.1821 +    protected final void encodeNonZeroOctetStringLengthOnSecondBit(int length) throws IOException {
  1.1822 +        if (length < EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT) {
  1.1823 +            // [1, 64]
  1.1824 +            write(length - 1);
  1.1825 +        } else if (length < EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT) {
  1.1826 +            // [65, 320]
  1.1827 +            write(EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_FLAG); // 010 00000
  1.1828 +            write(length - EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT);
  1.1829 +        } else {
  1.1830 +            // [321, 4294967296]
  1.1831 +            write(EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_LARGE_FLAG); // 0110 0000
  1.1832 +            length -= EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT;
  1.1833 +            write(length >>> 24);
  1.1834 +            write((length >> 16) & 0xFF);
  1.1835 +            write((length >> 8) & 0xFF);
  1.1836 +            write(length & 0xFF);
  1.1837 +        }
  1.1838 +    }
  1.1839 +
  1.1840 +    /**
  1.1841 +     * Encode a non empty string on the fifth bit of an octet using the UTF-8
  1.1842 +     * or UTF-16 encoding.
  1.1843 +     * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1844 +     *
  1.1845 +     * @param s the string.
  1.1846 +     */
  1.1847 +    protected final void encodeNonEmptyCharacterStringOnFifthBit(String s) throws IOException {
  1.1848 +        final int length = (_encodingStringsAsUtf8) ? encodeUTF8String(s) : encodeUtf16String(s);
  1.1849 +        encodeNonZeroOctetStringLengthOnFifthBit(length);
  1.1850 +        write(_encodingBuffer, length);
  1.1851 +    }
  1.1852 +
  1.1853 +    /**
  1.1854 +     * Encode a non empty string on the fifth bit of an octet using the UTF-8
  1.1855 +     * or UTF-16 encoding.
  1.1856 +     * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1857 +     *
  1.1858 +     * @param ch the array of characters.
  1.1859 +     * @param offset the offset into the array of characters.
  1.1860 +     * @param length the length of characters.
  1.1861 +     */
  1.1862 +    protected final void encodeNonEmptyCharacterStringOnFifthBit(char[] ch, int offset, int length) throws IOException {
  1.1863 +        length = (_encodingStringsAsUtf8) ? encodeUTF8String(ch, offset, length) : encodeUtf16String(ch, offset, length);
  1.1864 +        encodeNonZeroOctetStringLengthOnFifthBit(length);
  1.1865 +        write(_encodingBuffer, length);
  1.1866 +    }
  1.1867 +
  1.1868 +    /**
  1.1869 +     * Encode the length of a UTF-8 or UTF-16 encoded string on the fifth bit
  1.1870 +     * of an octet.
  1.1871 +     * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1872 +     *
  1.1873 +     * @param length the length to encode.
  1.1874 +     */
  1.1875 +    protected final void encodeNonZeroOctetStringLengthOnFifthBit(int length) throws IOException {
  1.1876 +        if (length < EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT) {
  1.1877 +            // [1, 8]
  1.1878 +            write(_b | (length - 1));
  1.1879 +        } else if (length < EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT) {
  1.1880 +            // [9, 264]
  1.1881 +            write(_b | EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_FLAG); // 000010 00
  1.1882 +            write(length - EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT);
  1.1883 +        } else {
  1.1884 +            // [265, 4294967296]
  1.1885 +            write(_b | EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_LARGE_FLAG); // 000011 00
  1.1886 +            length -= EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT;
  1.1887 +            write(length >>> 24);
  1.1888 +            write((length >> 16) & 0xFF);
  1.1889 +            write((length >> 8) & 0xFF);
  1.1890 +            write(length & 0xFF);
  1.1891 +        }
  1.1892 +    }
  1.1893 +
  1.1894 +    /**
  1.1895 +     * Encode a non empty string on the seventh bit of an octet using the UTF-8
  1.1896 +     * or UTF-16 encoding.
  1.1897 +     * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1898 +     *
  1.1899 +     * @param ch the array of characters.
  1.1900 +     * @param offset the offset into the array of characters.
  1.1901 +     * @param length the length of characters.
  1.1902 +     */
  1.1903 +    protected final void encodeNonEmptyCharacterStringOnSeventhBit(char[] ch, int offset, int length) throws IOException {
  1.1904 +        length = (_encodingStringsAsUtf8) ? encodeUTF8String(ch, offset, length) : encodeUtf16String(ch, offset, length);
  1.1905 +        encodeNonZeroOctetStringLengthOnSenventhBit(length);
  1.1906 +        write(_encodingBuffer, length);
  1.1907 +    }
  1.1908 +
  1.1909 +    /**
  1.1910 +     * Encode a non empty string on the seventh bit of an octet using a restricted
  1.1911 +     * alphabet that results in the encoding of a character in 4 bits
  1.1912 +     * (or two characters per octet).
  1.1913 +     * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1914 +     *
  1.1915 +     * @param table the table mapping characters to 4 bit values.
  1.1916 +     * @param ch the array of characters.
  1.1917 +     * @param offset the offset into the array of characters.
  1.1918 +     * @param length the length of characters.
  1.1919 +     */
  1.1920 +    protected final void encodeNonEmptyFourBitCharacterStringOnSeventhBit(int[] table, char[] ch, int offset, int length) throws FastInfosetException, IOException {
  1.1921 +        final int octetPairLength = length / 2;
  1.1922 +        final int octetSingleLength = length % 2;
  1.1923 +
  1.1924 +        // Encode the length
  1.1925 +        encodeNonZeroOctetStringLengthOnSenventhBit(octetPairLength + octetSingleLength);
  1.1926 +        encodeNonEmptyFourBitCharacterString(table, ch, offset, octetPairLength, octetSingleLength);
  1.1927 +    }
  1.1928 +
  1.1929 +    protected final void encodeNonEmptyFourBitCharacterString(int[] table, char[] ch, int offset,
  1.1930 +            int octetPairLength, int octetSingleLength) throws FastInfosetException, IOException {
  1.1931 +        ensureSize(octetPairLength + octetSingleLength);
  1.1932 +        // Encode all pairs
  1.1933 +        int v = 0;
  1.1934 +        for (int i = 0; i < octetPairLength; i++) {
  1.1935 +            v = (table[ch[offset++]] << 4) | table[ch[offset++]];
  1.1936 +            if (v < 0) {
  1.1937 +                throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange"));
  1.1938 +            }
  1.1939 +            _octetBuffer[_octetBufferIndex++] = (byte)v;
  1.1940 +        }
  1.1941 +        // Encode single character at end with termination bits
  1.1942 +        if (octetSingleLength == 1) {
  1.1943 +            v = (table[ch[offset]] << 4) | 0x0F;
  1.1944 +            if (v < 0) {
  1.1945 +                throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange"));
  1.1946 +            }
  1.1947 +            _octetBuffer[_octetBufferIndex++] = (byte)v;
  1.1948 +        }
  1.1949 +    }
  1.1950 +
  1.1951 +    /**
  1.1952 +     * Encode a non empty string on the seventh bit of an octet using a restricted
  1.1953 +     * alphabet table.
  1.1954 +     * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.1955 +     *
  1.1956 +     * @param alphabet the alphabet defining the mapping between characters and
  1.1957 +     *        integer values.
  1.1958 +     * @param ch the array of characters.
  1.1959 +     * @param offset the offset into the array of characters.
  1.1960 +     * @param length the length of characters.
  1.1961 +     */
  1.1962 +    protected final void encodeNonEmptyNBitCharacterStringOnSeventhBit(String alphabet, char[] ch, int offset, int length) throws FastInfosetException, IOException {
  1.1963 +        int bitsPerCharacter = 1;
  1.1964 +        while ((1 << bitsPerCharacter) <= alphabet.length()) {
  1.1965 +            bitsPerCharacter++;
  1.1966 +        }
  1.1967 +
  1.1968 +        final int bits = length * bitsPerCharacter;
  1.1969 +        final int octets = bits / 8;
  1.1970 +        final int bitsOfLastOctet = bits % 8;
  1.1971 +        final int totalOctets = octets + ((bitsOfLastOctet > 0) ? 1 : 0);
  1.1972 +
  1.1973 +        // Encode the length
  1.1974 +        encodeNonZeroOctetStringLengthOnSenventhBit(totalOctets);
  1.1975 +
  1.1976 +        resetBits();
  1.1977 +        ensureSize(totalOctets);
  1.1978 +        int v = 0;
  1.1979 +        for (int i = 0; i < length; i++) {
  1.1980 +            final char c = ch[offset + i];
  1.1981 +            // This is grotesquely slow, need to use hash table of character to int value
  1.1982 +            for (v = 0; v < alphabet.length(); v++) {
  1.1983 +                if (c == alphabet.charAt(v)) {
  1.1984 +                    break;
  1.1985 +                }
  1.1986 +            }
  1.1987 +            if (v == alphabet.length()) {
  1.1988 +                throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange"));
  1.1989 +            }
  1.1990 +            writeBits(bitsPerCharacter, v);
  1.1991 +        }
  1.1992 +
  1.1993 +        if (bitsOfLastOctet > 0) {
  1.1994 +            _b |= (1 << (8 - bitsOfLastOctet)) - 1;
  1.1995 +            write(_b);
  1.1996 +        }
  1.1997 +    }
  1.1998 +
  1.1999 +    private int _bitsLeftInOctet;
  1.2000 +
  1.2001 +    private final void resetBits() {
  1.2002 +        _bitsLeftInOctet = 8;
  1.2003 +        _b = 0;
  1.2004 +    }
  1.2005 +
  1.2006 +    private final void writeBits(int bits, int v) throws IOException {
  1.2007 +        while (bits > 0) {
  1.2008 +            final int bit = (v & (1 << --bits)) > 0 ? 1 : 0;
  1.2009 +            _b |= bit << (--_bitsLeftInOctet);
  1.2010 +            if (_bitsLeftInOctet == 0) {
  1.2011 +                write(_b);
  1.2012 +                _bitsLeftInOctet = 8;
  1.2013 +                _b = 0;
  1.2014 +            }
  1.2015 +        }
  1.2016 +    }
  1.2017 +
  1.2018 +    /**
  1.2019 +     * Encode the length of a encoded string on the seventh bit
  1.2020 +     * of an octet.
  1.2021 +     * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.2022 +     *
  1.2023 +     * @param length the length to encode.
  1.2024 +     */
  1.2025 +    protected final void encodeNonZeroOctetStringLengthOnSenventhBit(int length) throws IOException {
  1.2026 +        if (length < EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT) {
  1.2027 +            // [1, 2]
  1.2028 +            write(_b | (length - 1));
  1.2029 +        } else if (length < EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT) {
  1.2030 +            // [3, 258]
  1.2031 +            write(_b | EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_FLAG); // 00000010
  1.2032 +            write(length - EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT);
  1.2033 +        } else {
  1.2034 +            // [259, 4294967296]
  1.2035 +            write(_b | EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_LARGE_FLAG); // 00000011
  1.2036 +            length -= EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT;
  1.2037 +            write(length >>> 24);
  1.2038 +            write((length >> 16) & 0xFF);
  1.2039 +            write((length >> 8) & 0xFF);
  1.2040 +            write(length & 0xFF);
  1.2041 +        }
  1.2042 +    }
  1.2043 +
  1.2044 +    /**
  1.2045 +     * Encode a non zero integer on the second bit of an octet, setting
  1.2046 +     * the first bit to 1.
  1.2047 +     * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.2048 +     *
  1.2049 +     * <p>
  1.2050 +     * The first bit of the first octet is set, as specified in clause C.13 of
  1.2051 +     * ITU-T Rec. X.891 | ISO/IEC 24824-1
  1.2052 +     *
  1.2053 +     * @param i The integer to encode, which is a member of the interval
  1.2054 +     *          [0, 1048575]. In the specification the interval is [1, 1048576]
  1.2055 +     *
  1.2056 +     */
  1.2057 +    protected final void encodeNonZeroIntegerOnSecondBitFirstBitOne(int i) throws IOException {
  1.2058 +        if (i < EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT) {
  1.2059 +            // [1, 64] ( [0, 63] ) 6 bits
  1.2060 +            write(0x80 | i);
  1.2061 +        } else if (i < EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT) {
  1.2062 +            // [65, 8256] ( [64, 8255] ) 13 bits
  1.2063 +            i -= EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
  1.2064 +            _b = (0x80 | EncodingConstants.INTEGER_2ND_BIT_MEDIUM_FLAG) | (i >> 8); // 010 00000
  1.2065 +            // _b = 0xC0 | (i >> 8); // 010 00000
  1.2066 +            write(_b);
  1.2067 +            write(i & 0xFF);
  1.2068 +        } else if (i < EncodingConstants.INTEGER_2ND_BIT_LARGE_LIMIT) {
  1.2069 +            // [8257, 1048576] ( [8256, 1048575] ) 20 bits
  1.2070 +            i -= EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
  1.2071 +            _b = (0x80 | EncodingConstants.INTEGER_2ND_BIT_LARGE_FLAG) | (i >> 16); // 0110 0000
  1.2072 +            // _b = 0xE0 | (i >> 16); // 0110 0000
  1.2073 +            write(_b);
  1.2074 +            write((i >> 8) & 0xFF);
  1.2075 +            write(i & 0xFF);
  1.2076 +        } else {
  1.2077 +            throw new IOException(
  1.2078 +                    CommonResourceBundle.getInstance().getString("message.integerMaxSize",
  1.2079 +                    new Object[]{Integer.valueOf(EncodingConstants.INTEGER_2ND_BIT_LARGE_LIMIT)}));
  1.2080 +        }
  1.2081 +    }
  1.2082 +
  1.2083 +    /**
  1.2084 +     * Encode a non zero integer on the second bit of an octet, setting
  1.2085 +     * the first bit to 0.
  1.2086 +     * Implementation of clause C.25 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.2087 +     *
  1.2088 +     * <p>
  1.2089 +     * The first bit of the first octet is set, as specified in clause C.13 of
  1.2090 +     * ITU-T Rec. X.891 | ISO/IEC 24824-1
  1.2091 +     *
  1.2092 +     * @param i The integer to encode, which is a member of the interval
  1.2093 +     *          [0, 1048575]. In the specification the interval is [1, 1048576]
  1.2094 +     *
  1.2095 +     */
  1.2096 +    protected final void encodeNonZeroIntegerOnSecondBitFirstBitZero(int i) throws IOException {
  1.2097 +        if (i < EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT) {
  1.2098 +            // [1, 64] ( [0, 63] ) 6 bits
  1.2099 +            write(i);
  1.2100 +        } else if (i < EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT) {
  1.2101 +            // [65, 8256] ( [64, 8255] ) 13 bits
  1.2102 +            i -= EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
  1.2103 +            _b = EncodingConstants.INTEGER_2ND_BIT_MEDIUM_FLAG | (i >> 8); // 010 00000
  1.2104 +            write(_b);
  1.2105 +            write(i & 0xFF);
  1.2106 +        } else {
  1.2107 +            // [8257, 1048576] ( [8256, 1048575] ) 20 bits
  1.2108 +            i -= EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
  1.2109 +            _b = EncodingConstants.INTEGER_2ND_BIT_LARGE_FLAG | (i >> 16); // 0110 0000
  1.2110 +            write(_b);
  1.2111 +            write((i >> 8) & 0xFF);
  1.2112 +            write(i & 0xFF);
  1.2113 +        }
  1.2114 +    }
  1.2115 +
  1.2116 +    /**
  1.2117 +     * Encode a non zero integer on the third bit of an octet.
  1.2118 +     * Implementation of clause C.27 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.2119 +     *
  1.2120 +     * @param i The integer to encode, which is a member of the interval
  1.2121 +     *          [0, 1048575]. In the specification the interval is [1, 1048576]
  1.2122 +     *
  1.2123 +     */
  1.2124 +    protected final void encodeNonZeroIntegerOnThirdBit(int i) throws IOException {
  1.2125 +        if (i < EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT) {
  1.2126 +            // [1, 32] ( [0, 31] ) 5 bits
  1.2127 +            write(_b | i);
  1.2128 +        } else if (i < EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT) {
  1.2129 +            // [33, 2080] ( [32, 2079] ) 11 bits
  1.2130 +            i -= EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT;
  1.2131 +            _b |= EncodingConstants.INTEGER_3RD_BIT_MEDIUM_FLAG | (i >> 8); // 00100 000
  1.2132 +            write(_b);
  1.2133 +            write(i & 0xFF);
  1.2134 +        } else if (i < EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT) {
  1.2135 +            // [2081, 526368] ( [2080, 526367] ) 19 bits
  1.2136 +            i -= EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT;
  1.2137 +            _b |= EncodingConstants.INTEGER_3RD_BIT_LARGE_FLAG | (i >> 16); // 00101 000
  1.2138 +            write(_b);
  1.2139 +            write((i >> 8) & 0xFF);
  1.2140 +            write(i & 0xFF);
  1.2141 +        } else {
  1.2142 +            // [526369, 1048576] ( [526368, 1048575] ) 20 bits
  1.2143 +            i -= EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT;
  1.2144 +            _b |= EncodingConstants.INTEGER_3RD_BIT_LARGE_LARGE_FLAG; // 00110 000
  1.2145 +            write(_b);
  1.2146 +            write(i >> 16);
  1.2147 +            write((i >> 8) & 0xFF);
  1.2148 +            write(i & 0xFF);
  1.2149 +        }
  1.2150 +    }
  1.2151 +
  1.2152 +    /**
  1.2153 +     * Encode a non zero integer on the fourth bit of an octet.
  1.2154 +     * Implementation of clause C.28 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
  1.2155 +     *
  1.2156 +     * @param i The integer to encode, which is a member of the interval
  1.2157 +     *          [0, 1048575]. In the specification the interval is [1, 1048576]
  1.2158 +     *
  1.2159 +     */
  1.2160 +    protected final void encodeNonZeroIntegerOnFourthBit(int i) throws IOException {
  1.2161 +        if (i < EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT) {
  1.2162 +            // [1, 16] ( [0, 15] ) 4 bits
  1.2163 +            write(_b | i);
  1.2164 +        } else if (i < EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT) {
  1.2165 +            // [17, 1040] ( [16, 1039] ) 10 bits
  1.2166 +            i -= EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT;
  1.2167 +            _b |= EncodingConstants.INTEGER_4TH_BIT_MEDIUM_FLAG | (i >> 8); // 000 100 00
  1.2168 +            write(_b);
  1.2169 +            write(i & 0xFF);
  1.2170 +        } else if (i < EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT) {
  1.2171 +            // [1041, 263184] ( [1040, 263183] ) 18 bits
  1.2172 +            i -= EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT;
  1.2173 +            _b |= EncodingConstants.INTEGER_4TH_BIT_LARGE_FLAG | (i >> 16); // 000 101 00
  1.2174 +            write(_b);
  1.2175 +            write((i >> 8) & 0xFF);
  1.2176 +            write(i & 0xFF);
  1.2177 +        } else {
  1.2178 +            // [263185, 1048576] ( [263184, 1048575] ) 20 bits
  1.2179 +            i -= EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT;
  1.2180 +            _b |= EncodingConstants.INTEGER_4TH_BIT_LARGE_LARGE_FLAG; // 000 110 00
  1.2181 +            write(_b);
  1.2182 +            write(i >> 16);
  1.2183 +            write((i >> 8) & 0xFF);
  1.2184 +            write(i & 0xFF);
  1.2185 +        }
  1.2186 +    }
  1.2187 +
  1.2188 +    /**
  1.2189 +     * Encode a non empty string using the UTF-8 encoding.
  1.2190 +     *
  1.2191 +     * @param b the current octet that is being written.
  1.2192 +     * @param s the string to be UTF-8 encoded.
  1.2193 +     * @param constants the array of constants to use when encoding to determin
  1.2194 +     *        how the length of the UTF-8 encoded string is encoded.
  1.2195 +     */
  1.2196 +    protected final void encodeNonEmptyUTF8StringAsOctetString(int b, String s, int[] constants) throws IOException {
  1.2197 +        final char[] ch = s.toCharArray();
  1.2198 +        encodeNonEmptyUTF8StringAsOctetString(b, ch, 0, ch.length, constants);
  1.2199 +    }
  1.2200 +
  1.2201 +    /**
  1.2202 +     * Encode a non empty string using the UTF-8 encoding.
  1.2203 +     *
  1.2204 +     * @param b the current octet that is being written.
  1.2205 +     * @param ch the array of characters.
  1.2206 +     * @param offset the offset into the array of characters.
  1.2207 +     * @param length the length of characters.
  1.2208 +     *        how the length of the UTF-8 encoded string is encoded.
  1.2209 +     * @param constants the array of constants to use when encoding to determin
  1.2210 +     *        how the length of the UTF-8 encoded string is encoded.
  1.2211 +     */
  1.2212 +    protected final void encodeNonEmptyUTF8StringAsOctetString(int b, char ch[], int offset, int length, int[] constants) throws IOException {
  1.2213 +        length = encodeUTF8String(ch, offset, length);
  1.2214 +        encodeNonZeroOctetStringLength(b, length, constants);
  1.2215 +        write(_encodingBuffer, length);
  1.2216 +    }
  1.2217 +
  1.2218 +    /**
  1.2219 +     * Encode the length of non empty UTF-8 encoded string.
  1.2220 +     *
  1.2221 +     * @param b the current octet that is being written.
  1.2222 +     * @param length the length of the UTF-8 encoded string.
  1.2223 +     *        how the length of the UTF-8 encoded string is encoded.
  1.2224 +     * @param constants the array of constants to use when encoding to determin
  1.2225 +     *        how the length of the UTF-8 encoded string is encoded.
  1.2226 +     */
  1.2227 +    protected final void encodeNonZeroOctetStringLength(int b, int length, int[] constants) throws IOException {
  1.2228 +        if (length < constants[EncodingConstants.OCTET_STRING_LENGTH_SMALL_LIMIT]) {
  1.2229 +            write(b | (length - 1));
  1.2230 +        } else if (length < constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_LIMIT]) {
  1.2231 +            write(b | constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_FLAG]);
  1.2232 +            write(length - constants[EncodingConstants.OCTET_STRING_LENGTH_SMALL_LIMIT]);
  1.2233 +        } else {
  1.2234 +            write(b | constants[EncodingConstants.OCTET_STRING_LENGTH_LARGE_FLAG]);
  1.2235 +            length -= constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_LIMIT];
  1.2236 +            write(length >>> 24);
  1.2237 +            write((length >> 16) & 0xFF);
  1.2238 +            write((length >> 8) & 0xFF);
  1.2239 +            write(length & 0xFF);
  1.2240 +        }
  1.2241 +    }
  1.2242 +
  1.2243 +    /**
  1.2244 +     * Encode a non zero integer.
  1.2245 +     *
  1.2246 +     * @param b the current octet that is being written.
  1.2247 +     * @param i the non zero integer.
  1.2248 +     * @param constants the array of constants to use when encoding to determin
  1.2249 +     *        how the non zero integer is encoded.
  1.2250 +     */
  1.2251 +    protected final void encodeNonZeroInteger(int b, int i, int[] constants) throws IOException {
  1.2252 +        if (i < constants[EncodingConstants.INTEGER_SMALL_LIMIT]) {
  1.2253 +            write(b | i);
  1.2254 +        } else if (i < constants[EncodingConstants.INTEGER_MEDIUM_LIMIT]) {
  1.2255 +            i -= constants[EncodingConstants.INTEGER_SMALL_LIMIT];
  1.2256 +            write(b | constants[EncodingConstants.INTEGER_MEDIUM_FLAG] | (i >> 8));
  1.2257 +            write(i & 0xFF);
  1.2258 +        } else if (i < constants[EncodingConstants.INTEGER_LARGE_LIMIT]) {
  1.2259 +            i -= constants[EncodingConstants.INTEGER_MEDIUM_LIMIT];
  1.2260 +            write(b | constants[EncodingConstants.INTEGER_LARGE_FLAG] | (i >> 16));
  1.2261 +            write((i >> 8) & 0xFF);
  1.2262 +            write(i & 0xFF);
  1.2263 +        } else if (i < EncodingConstants.INTEGER_MAXIMUM_SIZE) {
  1.2264 +            i -= constants[EncodingConstants.INTEGER_LARGE_LIMIT];
  1.2265 +            write(b | constants[EncodingConstants.INTEGER_LARGE_LARGE_FLAG]);
  1.2266 +            write(i >> 16);
  1.2267 +            write((i >> 8) & 0xFF);
  1.2268 +            write(i & 0xFF);
  1.2269 +        } else {
  1.2270 +            throw new IOException(CommonResourceBundle.getInstance().getString("message.integerMaxSize", new Object[]{Integer.valueOf(EncodingConstants.INTEGER_MAXIMUM_SIZE)}));
  1.2271 +        }
  1.2272 +    }
  1.2273 +
  1.2274 +    /**
  1.2275 +     * Mark the current position in the buffered stream.
  1.2276 +     */
  1.2277 +    protected final void mark() {
  1.2278 +        _markIndex = _octetBufferIndex;
  1.2279 +    }
  1.2280 +
  1.2281 +    /**
  1.2282 +     * Reset the marked position in the buffered stream.
  1.2283 +     */
  1.2284 +    protected final void resetMark() {
  1.2285 +        _markIndex = -1;
  1.2286 +    }
  1.2287 +
  1.2288 +    /**
  1.2289 +     * @return true if the mark has been set, otherwise false if the mark
  1.2290 +     *         has not been set.
  1.2291 +     */
  1.2292 +    protected final boolean hasMark() {
  1.2293 +        return _markIndex != -1;
  1.2294 +    }
  1.2295 +
  1.2296 +    /**
  1.2297 +     * Write a byte to the buffered stream.
  1.2298 +     */
  1.2299 +    protected final void write(int i) throws IOException {
  1.2300 +        if (_octetBufferIndex < _octetBuffer.length) {
  1.2301 +            _octetBuffer[_octetBufferIndex++] = (byte)i;
  1.2302 +        } else {
  1.2303 +            if (_markIndex == -1) {
  1.2304 +                _s.write(_octetBuffer);
  1.2305 +                _octetBufferIndex = 1;
  1.2306 +                _octetBuffer[0] = (byte)i;
  1.2307 +            } else {
  1.2308 +                resize(_octetBuffer.length * 3 / 2);
  1.2309 +                _octetBuffer[_octetBufferIndex++] = (byte)i;
  1.2310 +            }
  1.2311 +        }
  1.2312 +    }
  1.2313 +
  1.2314 +    /**
  1.2315 +     * Write an array of bytes to the buffered stream.
  1.2316 +     *
  1.2317 +     * @param b the array of bytes.
  1.2318 +     * @param length the length of bytes.
  1.2319 +     */
  1.2320 +    protected final void write(byte[] b, int length) throws IOException {
  1.2321 +        write(b, 0,  length);
  1.2322 +    }
  1.2323 +
  1.2324 +    /**
  1.2325 +     * Write an array of bytes to the buffered stream.
  1.2326 +     *
  1.2327 +     * @param b the array of bytes.
  1.2328 +     * @param offset the offset into the array of bytes.
  1.2329 +     * @param length the length of bytes.
  1.2330 +     */
  1.2331 +    protected final void write(byte[] b, int offset, int length) throws IOException {
  1.2332 +        if ((_octetBufferIndex + length) < _octetBuffer.length) {
  1.2333 +            System.arraycopy(b, offset, _octetBuffer, _octetBufferIndex, length);
  1.2334 +            _octetBufferIndex += length;
  1.2335 +        } else {
  1.2336 +            if (_markIndex == -1) {
  1.2337 +                _s.write(_octetBuffer, 0, _octetBufferIndex);
  1.2338 +                _s.write(b, offset, length);
  1.2339 +                _octetBufferIndex = 0;
  1.2340 +            } else {
  1.2341 +                resize((_octetBuffer.length + length) * 3 / 2 + 1);
  1.2342 +                System.arraycopy(b, offset, _octetBuffer, _octetBufferIndex, length);
  1.2343 +                _octetBufferIndex += length;
  1.2344 +            }
  1.2345 +        }
  1.2346 +    }
  1.2347 +
  1.2348 +    private void ensureSize(int length) {
  1.2349 +        if ((_octetBufferIndex + length) > _octetBuffer.length) {
  1.2350 +            resize((_octetBufferIndex + length) * 3 / 2 + 1);
  1.2351 +        }
  1.2352 +    }
  1.2353 +
  1.2354 +    private void resize(int length) {
  1.2355 +        byte[] b = new byte[length];
  1.2356 +        System.arraycopy(_octetBuffer, 0, b, 0, _octetBufferIndex);
  1.2357 +        _octetBuffer = b;
  1.2358 +    }
  1.2359 +
  1.2360 +    private void _flush() throws IOException {
  1.2361 +        if (_octetBufferIndex > 0) {
  1.2362 +            _s.write(_octetBuffer, 0, _octetBufferIndex);
  1.2363 +            _octetBufferIndex = 0;
  1.2364 +        }
  1.2365 +    }
  1.2366 +
  1.2367 +
  1.2368 +    private EncodingBufferOutputStream _encodingBufferOutputStream = new EncodingBufferOutputStream();
  1.2369 +
  1.2370 +    private byte[] _encodingBuffer = new byte[512];
  1.2371 +
  1.2372 +    private int _encodingBufferIndex;
  1.2373 +
  1.2374 +    private class EncodingBufferOutputStream extends OutputStream {
  1.2375 +
  1.2376 +        public void write(int b) throws IOException {
  1.2377 +            if (_encodingBufferIndex < _encodingBuffer.length) {
  1.2378 +                _encodingBuffer[_encodingBufferIndex++] = (byte)b;
  1.2379 +            } else {
  1.2380 +                byte newbuf[] = new byte[Math.max(_encodingBuffer.length << 1, _encodingBufferIndex)];
  1.2381 +                System.arraycopy(_encodingBuffer, 0, newbuf, 0, _encodingBufferIndex);
  1.2382 +                _encodingBuffer = newbuf;
  1.2383 +
  1.2384 +                _encodingBuffer[_encodingBufferIndex++] = (byte)b;
  1.2385 +            }
  1.2386 +        }
  1.2387 +
  1.2388 +        public void write(byte b[], int off, int len) throws IOException {
  1.2389 +            if ((off < 0) || (off > b.length) || (len < 0) ||
  1.2390 +                ((off + len) > b.length) || ((off + len) < 0)) {
  1.2391 +                throw new IndexOutOfBoundsException();
  1.2392 +            } else if (len == 0) {
  1.2393 +                return;
  1.2394 +            }
  1.2395 +            final int newoffset = _encodingBufferIndex + len;
  1.2396 +            if (newoffset > _encodingBuffer.length) {
  1.2397 +                byte newbuf[] = new byte[Math.max(_encodingBuffer.length << 1, newoffset)];
  1.2398 +                System.arraycopy(_encodingBuffer, 0, newbuf, 0, _encodingBufferIndex);
  1.2399 +                _encodingBuffer = newbuf;
  1.2400 +            }
  1.2401 +            System.arraycopy(b, off, _encodingBuffer, _encodingBufferIndex, len);
  1.2402 +            _encodingBufferIndex = newoffset;
  1.2403 +        }
  1.2404 +
  1.2405 +        public int getLength() {
  1.2406 +            return _encodingBufferIndex;
  1.2407 +        }
  1.2408 +
  1.2409 +        public void reset() {
  1.2410 +            _encodingBufferIndex = 0;
  1.2411 +        }
  1.2412 +    }
  1.2413 +
  1.2414 +    /**
  1.2415 +     * Encode a string using the UTF-8 encoding.
  1.2416 +     *
  1.2417 +     * @param s the string to encode.
  1.2418 +     */
  1.2419 +    protected final int encodeUTF8String(String s) throws IOException {
  1.2420 +        final int length = s.length();
  1.2421 +        if (length < _charBuffer.length) {
  1.2422 +            s.getChars(0, length, _charBuffer, 0);
  1.2423 +            return encodeUTF8String(_charBuffer, 0, length);
  1.2424 +        } else {
  1.2425 +            char[] ch = s.toCharArray();
  1.2426 +            return encodeUTF8String(ch, 0, length);
  1.2427 +        }
  1.2428 +    }
  1.2429 +
  1.2430 +    private void ensureEncodingBufferSizeForUtf8String(int length) {
  1.2431 +        final int newLength = 4 * length;
  1.2432 +        if (_encodingBuffer.length < newLength) {
  1.2433 +            _encodingBuffer = new byte[newLength];
  1.2434 +        }
  1.2435 +    }
  1.2436 +
  1.2437 +    /**
  1.2438 +     * Encode a string using the UTF-8 encoding.
  1.2439 +     *
  1.2440 +     * @param ch the array of characters.
  1.2441 +     * @param offset the offset into the array of characters.
  1.2442 +     * @param length the length of characters.
  1.2443 +     */
  1.2444 +    protected final int encodeUTF8String(char[] ch, int offset, int length) throws IOException {
  1.2445 +        int bpos = 0;
  1.2446 +
  1.2447 +        // Make sure buffer is large enough
  1.2448 +        ensureEncodingBufferSizeForUtf8String(length);
  1.2449 +
  1.2450 +        final int end = offset + length;
  1.2451 +        int c;
  1.2452 +        while (end != offset) {
  1.2453 +            c = ch[offset++];
  1.2454 +            if (c < 0x80) {
  1.2455 +                // 1 byte, 7 bits
  1.2456 +                _encodingBuffer[bpos++] = (byte) c;
  1.2457 +            } else if (c < 0x800) {
  1.2458 +                // 2 bytes, 11 bits
  1.2459 +                _encodingBuffer[bpos++] =
  1.2460 +                    (byte) (0xC0 | (c >> 6));    // first 5
  1.2461 +                _encodingBuffer[bpos++] =
  1.2462 +                    (byte) (0x80 | (c & 0x3F));  // second 6
  1.2463 +            } else if (c <= '\uFFFF') {
  1.2464 +                if (!XMLChar.isHighSurrogate(c) && !XMLChar.isLowSurrogate(c)) {
  1.2465 +                    // 3 bytes, 16 bits
  1.2466 +                    _encodingBuffer[bpos++] =
  1.2467 +                        (byte) (0xE0 | (c >> 12));   // first 4
  1.2468 +                    _encodingBuffer[bpos++] =
  1.2469 +                        (byte) (0x80 | ((c >> 6) & 0x3F));  // second 6
  1.2470 +                    _encodingBuffer[bpos++] =
  1.2471 +                        (byte) (0x80 | (c & 0x3F));  // third 6
  1.2472 +                } else {
  1.2473 +                    // 4 bytes, high and low surrogate
  1.2474 +                    encodeCharacterAsUtf8FourByte(c, ch, offset, end, bpos);
  1.2475 +                    bpos += 4;
  1.2476 +                    offset++;
  1.2477 +                }
  1.2478 +            }
  1.2479 +        }
  1.2480 +
  1.2481 +        return bpos;
  1.2482 +    }
  1.2483 +
  1.2484 +    private void encodeCharacterAsUtf8FourByte(int c, char[] ch, int chpos, int chend, int bpos) throws IOException {
  1.2485 +        if (chpos == chend) {
  1.2486 +            throw new IOException("");
  1.2487 +        }
  1.2488 +
  1.2489 +        final char d = ch[chpos];
  1.2490 +        if (!XMLChar.isLowSurrogate(d)) {
  1.2491 +            throw new IOException("");
  1.2492 +        }
  1.2493 +
  1.2494 +        final int uc = (((c & 0x3ff) << 10) | (d & 0x3ff)) + 0x10000;
  1.2495 +        if (uc < 0 || uc >= 0x200000) {
  1.2496 +            throw new IOException("");
  1.2497 +        }
  1.2498 +
  1.2499 +        _encodingBuffer[bpos++] = (byte)(0xF0 | ((uc >> 18)));
  1.2500 +        _encodingBuffer[bpos++] = (byte)(0x80 | ((uc >> 12) & 0x3F));
  1.2501 +        _encodingBuffer[bpos++] = (byte)(0x80 | ((uc >> 6) & 0x3F));
  1.2502 +        _encodingBuffer[bpos++] = (byte)(0x80 | (uc & 0x3F));
  1.2503 +    }
  1.2504 +
  1.2505 +    /**
  1.2506 +     * Encode a string using the UTF-16 encoding.
  1.2507 +     *
  1.2508 +     * @param s the string to encode.
  1.2509 +     */
  1.2510 +    protected final int encodeUtf16String(String s) throws IOException {
  1.2511 +        final int length = s.length();
  1.2512 +        if (length < _charBuffer.length) {
  1.2513 +            s.getChars(0, length, _charBuffer, 0);
  1.2514 +            return encodeUtf16String(_charBuffer, 0, length);
  1.2515 +        } else {
  1.2516 +            char[] ch = s.toCharArray();
  1.2517 +            return encodeUtf16String(ch, 0, length);
  1.2518 +        }
  1.2519 +    }
  1.2520 +
  1.2521 +    private void ensureEncodingBufferSizeForUtf16String(int length) {
  1.2522 +        final int newLength = 2 * length;
  1.2523 +        if (_encodingBuffer.length < newLength) {
  1.2524 +            _encodingBuffer = new byte[newLength];
  1.2525 +        }
  1.2526 +    }
  1.2527 +
  1.2528 +    /**
  1.2529 +     * Encode a string using the UTF-16 encoding.
  1.2530 +     *
  1.2531 +     * @param ch the array of characters.
  1.2532 +     * @param offset the offset into the array of characters.
  1.2533 +     * @param length the length of characters.
  1.2534 +     */
  1.2535 +    protected final int encodeUtf16String(char[] ch, int offset, int length) throws IOException {
  1.2536 +        int byteLength = 0;
  1.2537 +
  1.2538 +        // Make sure buffer is large enough
  1.2539 +        ensureEncodingBufferSizeForUtf16String(length);
  1.2540 +
  1.2541 +        final int n = offset + length;
  1.2542 +        for (int i = offset; i < n; i++) {
  1.2543 +            final int c = (int) ch[i];
  1.2544 +            _encodingBuffer[byteLength++] = (byte)(c >> 8);
  1.2545 +            _encodingBuffer[byteLength++] = (byte)(c & 0xFF);
  1.2546 +        }
  1.2547 +
  1.2548 +        return byteLength;
  1.2549 +    }
  1.2550 +
  1.2551 +    /**
  1.2552 +     * Obtain the prefix from a qualified name.
  1.2553 +     *
  1.2554 +     * @param qName the qualified name
  1.2555 +     * @return the prefix, or "" if there is no prefix.
  1.2556 +     */
  1.2557 +    public static String getPrefixFromQualifiedName(String qName) {
  1.2558 +        int i = qName.indexOf(':');
  1.2559 +        String prefix = "";
  1.2560 +        if (i != -1) {
  1.2561 +            prefix = qName.substring(0, i);
  1.2562 +        }
  1.2563 +        return prefix;
  1.2564 +    }
  1.2565 +
  1.2566 +    /**
  1.2567 +     * Check if character array contains characters that are all white space.
  1.2568 +     *
  1.2569 +     * @param ch the character array
  1.2570 +     * @param start the starting character index into the array to check from
  1.2571 +     * @param length the number of characters to check
  1.2572 +     * @return true if all characters are white space, false otherwise
  1.2573 +     */
  1.2574 +    public static boolean isWhiteSpace(final char[] ch, int start, final int length) {
  1.2575 +        if (!XMLChar.isSpace(ch[start])) return false;
  1.2576 +
  1.2577 +        final int end = start + length;
  1.2578 +        while(++start < end && XMLChar.isSpace(ch[start]));
  1.2579 +
  1.2580 +        return start == end;
  1.2581 +    }
  1.2582 +
  1.2583 +    /**
  1.2584 +     * Check if a String contains characters that are all white space.
  1.2585 +     *
  1.2586 +     * @param s the string
  1.2587 +     * @return true if all characters are white space, false otherwise
  1.2588 +     */
  1.2589 +    public static boolean isWhiteSpace(String s) {
  1.2590 +        if (!XMLChar.isSpace(s.charAt(0))) return false;
  1.2591 +
  1.2592 +        final int end = s.length();
  1.2593 +        int start = 1;
  1.2594 +        while(start < end && XMLChar.isSpace(s.charAt(start++)));
  1.2595 +        return start == end;
  1.2596 +    }
  1.2597 +}

mercurial