All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.neovisionaries.ws.client.Huffman Maven / Gradle / Ivy

There is a newer version: 2.14
Show newest version
/*
 * Copyright (C) 2015 Neo Visionaries Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.neovisionaries.ws.client;


/**
 * Huffman coding for DEFLATE format (RFC 1951).
 */
class Huffman
{
    private final int mMinCodeLen;
    private final int mMaxCodeLen;
    private final int[] mMaxCodeValsFromCodeLen;
    private final int[] mSymsFromCodeVal;


    public Huffman(int[] codeLensFromSym)
    {
        // Remember the minimum and maximum code lengths.
        mMinCodeLen = Math.max(Misc.min(codeLensFromSym), 1);
        mMaxCodeLen = Misc.max(codeLensFromSym);

        // Count the number of entries for each code length.
        int[] countsFromCodeLen = createCountsFromCodeLen(codeLensFromSym, mMaxCodeLen);

        // Create an array holding the maximum code values for each code length.
        Object[] out = new Object[2];
        mMaxCodeValsFromCodeLen = createMaxCodeValsFromCodeLen(countsFromCodeLen, mMaxCodeLen, out);

        // Create a table to convert code values int symbols.
        int[] codeValsFromCodeLen = (int[])out[0];
        int maxCodeVal = ((Integer)out[1]).intValue();
        mSymsFromCodeVal = createSymsFromCodeVal(codeLensFromSym, codeValsFromCodeLen, maxCodeVal);
    }


    /**
     * Create an array whose elements have the given initial value.
     */
    private static int[] createIntArray(int size, int initialValue)
    {
        int[] array = new int[size];

        for (int i = 0; i < size; ++i)
        {
            array[i] = initialValue;
        }

        return array;
    }


    private static int[] createCountsFromCodeLen(int[] codeLensFromSym, int maxCodeLen)
    {
        int[] countsFromCodeLen = new int[maxCodeLen + 1];

        // Count the number of entries for each code length.
        // This corresponds to the step 1 in 3.2.2. of RFC 1951.
        for (int symbol = 0; symbol < codeLensFromSym.length; ++symbol)
        {
            int codeLength = codeLensFromSym[symbol];
            ++countsFromCodeLen[codeLength];
        }

        return countsFromCodeLen;
    }


    private static int[] createMaxCodeValsFromCodeLen(int[] countsFromCodeLen, int maxCodeLen, Object[] out)
    {
        // Initialize an array that holds the maximum code values
        // for each code length. '-1' indicates that there is no
        // code value for the code length.
        int[] maxCodeValsFromCodeLen = createIntArray(maxCodeLen + 1, -1);

        // Compute the smallest code value for each code length.
        // This corresponds to the step 2 in 3.2.2. of RFC 1951.
        int minCodeVal = 0;
        int maxCodeVal = 0;
        countsFromCodeLen[0] = 0;
        int[] codeValsFromCodeLen = new int[maxCodeLen + 1];
        for (int codeLen = 1; codeLen < countsFromCodeLen.length; ++codeLen)
        {
            // Compute the minimum code value for each code length.
            int prevCount = countsFromCodeLen[codeLen - 1];
            minCodeVal = (minCodeVal + prevCount) << 1;
            codeValsFromCodeLen[codeLen] = minCodeVal;

            // Compute the maximum code value for each code length.
            maxCodeVal = minCodeVal + countsFromCodeLen[codeLen] - 1;
            maxCodeValsFromCodeLen[codeLen] = maxCodeVal;
        }

        out[0] = codeValsFromCodeLen;
        out[1] = Integer.valueOf(maxCodeVal);

        return maxCodeValsFromCodeLen;
    }


    private static int[] createSymsFromCodeVal(int[] codeLensFromSym, int[] codeValsFromCodeLen, int maxCodeVal)
    {
        int[] symsFromCodeVal = new int[maxCodeVal + 1];

        // Set up a table to convert code values into symbols.
        // This corresponds to the step 3 in 3.2.2. of RFC 1951.

        for (int sym = 0; sym < codeLensFromSym.length; ++sym)
        {
            int codeLen = codeLensFromSym[sym];

            if (codeLen == 0)
            {
                continue;
            }

            int codeVal = codeValsFromCodeLen[codeLen]++;
            symsFromCodeVal[codeVal] = sym;
        }

        return symsFromCodeVal;
    }


    public int readSym(ByteArray data, int[] bitIndex) throws FormatException
    {
        for (int codeLen = mMinCodeLen; codeLen <= mMaxCodeLen; ++codeLen)
        {
            // Get the maximum one from among the code values
            // whose code length is 'codeLen'.
            int maxCodeVal = mMaxCodeValsFromCodeLen[codeLen];

            if (maxCodeVal < 0)
            {
                // There is no code value whose code length is 'codeLen'.
                continue;
            }

            // Read a code value from the input assuming its code length is 'codeLen'.
            int codeVal = data.getHuffmanBits(bitIndex[0], codeLen);

            if (maxCodeVal < codeVal)
            {
                // The read code value is bigger than the maximum code value
                // among the code values whose code length is 'codeLen'.
                //
                // Considering the latter rule of the two added for DEFLATE format
                // (3.2.2. Use of Huffman coding in the "deflate" format),
                //
                //     * All codes of a given bit length have lexicographically
                //       consecutive values, in the same order as the symbols
                //       they represent;
                //
                //     * Shorter codes lexicographically precede longer codes.
                //
                // We can expect that the code length of the code value we are
                // parsing is longer than the current 'codeLen'.
                continue;
            }

            // Convert the code value into a symbol value.
            int sym = mSymsFromCodeVal[codeVal];

            // Consume the bits of the code value.
            bitIndex[0] += codeLen;

            return sym;
        }

        // Bad code at the bit index.
        String message = String.format(
                "[%s] Bad code at the bit index '%d'.",
                getClass().getSimpleName(), bitIndex[0]);

        throw new FormatException(message);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy