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

org.apache.sanselan.common.mylzw.MyLZWDecompressor Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.sanselan.common.mylzw;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public final class MyLZWDecompressor
{
    private static final int MAX_TABLE_SIZE = 1 << 12;

    private final byte[][] table;
    private int codeSize;
    private final int initialCodeSize;
    private int codes = -1;

    private final int byteOrder;

    private final Listener listener;

    public static interface Listener
    {
        public void code(int code);

        public void init(int clearCode, int eoiCode);
    }

    public MyLZWDecompressor(int initialCodeSize, int byteOrder)
    {
        this(initialCodeSize, byteOrder, null);
    }

    public MyLZWDecompressor(int initialCodeSize, int byteOrder,
            Listener listener)
    {
        this.listener = listener;
        this.byteOrder = byteOrder;

        this.initialCodeSize = initialCodeSize;

        table = new byte[MAX_TABLE_SIZE][];
        clearCode = 1 << initialCodeSize;
        eoiCode = clearCode + 1;

        if (null != listener)
            listener.init(clearCode, eoiCode);

        InitializeTable();
    }

    private final void InitializeTable()
    {
        codeSize = initialCodeSize;

        int intial_entries_count = 1 << codeSize + 2;

        for (int i = 0; i < intial_entries_count; i++)
            table[i] = new byte[] { (byte) i, };
    }

    private final void clearTable()
    {
        codes = (1 << initialCodeSize) + 2;
        codeSize = initialCodeSize;
        incrementCodeSize();
    }

    private final int clearCode;
    private final int eoiCode;

    private final int getNextCode(MyBitInputStream is) throws IOException
    {
        int code = is.readBits(codeSize);

        if (null != listener)
            listener.code(code);
        return code;
    }

    private final byte[] stringFromCode(int code) throws IOException
    {
        if ((code >= codes) || (code < 0))
            throw new IOException("Bad Code: " + code + " codes: " + codes
                    + " code_size: " + codeSize + ", table: " + table.length);

        return table[code];
    }

    private final boolean isInTable(int Code)
    {
        return Code < codes;
    }

    private final byte firstChar(byte bytes[])
    {
        return bytes[0];
    }

    private final void addStringToTable(byte bytes[]) throws IOException
    {
        if (codes < (1 << codeSize))
        {
            table[codes] = bytes;
            codes++;
        } else
            throw new IOException("AddStringToTable: codes: " + codes
                    + " code_size: " + codeSize);

        checkCodeSize();
    }

    private final byte[] appendBytes(byte bytes[], byte b)
    {
        byte result[] = new byte[bytes.length + 1];

        System.arraycopy(bytes, 0, result, 0, bytes.length);
        result[result.length - 1] = b;
        return result;
    }

    private int written = 0;

    private final void writeToResult(OutputStream os, byte bytes[])
            throws IOException
    {
        os.write(bytes);
        written += bytes.length;
    }

    private boolean tiffLZWMode = false;

    public void setTiffLZWMode()
    {
        tiffLZWMode = true;
    }

    public byte[] decompress(InputStream is, int expectedLength)
            throws IOException
    {
        int code, oldCode = -1;
        MyBitInputStream mbis = new MyBitInputStream(is, byteOrder);
        if (tiffLZWMode)
            mbis.setTiffLZWMode();

        ByteArrayOutputStream baos = new ByteArrayOutputStream(expectedLength);

        clearTable();

        while ((code = getNextCode(mbis)) != eoiCode)
        {
            if (code == clearCode)
            {
                clearTable();

                if (written >= expectedLength)
                    break;
                code = getNextCode(mbis);

                if (code == eoiCode)
                {
                    break;
                }
                writeToResult(baos, stringFromCode(code));

                oldCode = code;
            } // end of ClearCode case
            else
            {
                if (isInTable(code))
                {
                    writeToResult(baos, stringFromCode(code));

                    addStringToTable(appendBytes(stringFromCode(oldCode),
                            firstChar(stringFromCode(code))));
                    oldCode = code;
                } else
                {
                    byte OutString[] = appendBytes(stringFromCode(oldCode),
                            firstChar(stringFromCode(oldCode)));
                    writeToResult(baos, OutString);
                    addStringToTable(OutString);
                    oldCode = code;
                }
            } // end of not-ClearCode case

            if (written >= expectedLength)
                break;
        } // end of while loop

        byte result[] = baos.toByteArray();

        return result;
    }

    private final void checkCodeSize() // throws IOException
    {
        int limit = (1 << codeSize);
        if (tiffLZWMode)
            limit--;

        if (codes == limit)
            incrementCodeSize();
    }

    private final void incrementCodeSize() // throws IOException
    {
        if (codeSize != 12)
            codeSize++;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy