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

de.jarnbjo.util.io.ByteArrayBitInputStream Maven / Gradle / Ivy

/*
 * $ProjectName$
 * $ProjectRevision$
 * -----------------------------------------------------------
 * $Id: ByteArrayBitInputStream.java,v 1.3 2003/04/10 19:48:31 jarnbjo Exp $
 * -----------------------------------------------------------
 *
 * $Author: jarnbjo $
 *
 * Description:
 *
 * Copyright 2002-2003 Tor-Einar Jarnbjo
 * -----------------------------------------------------------
 *
 * Change History
 * -----------------------------------------------------------
 * $Log: ByteArrayBitInputStream.java,v $
 * Revision 1.3  2003/04/10 19:48:31  jarnbjo
 * no message
 *
 * Revision 1.2  2003/03/16 01:11:39  jarnbjo
 * no message
 *
 * Revision 1.1  2003/03/03 21:02:20  jarnbjo
 * no message
 */
package de.jarnbjo.util.io;

import java.io.IOException;

/**
 * Implementation of the {@code BitInputStream} interface, using a byte array as
 * data source.
 */
public class ByteArrayBitInputStream implements BitInputStream {
    final private byte[] source;
    private byte currentByte;

    private int endian;

    private int byteIndex = 0;
    private int bitIndex = 0;

    public ByteArrayBitInputStream(byte[] source) {
        this(source, LITTLE_ENDIAN);
    }

    public ByteArrayBitInputStream(byte[] source, int endian) {
        this.endian = endian;
        this.source = source;
        currentByte = source[0];
        bitIndex = (endian == LITTLE_ENDIAN) ? 0 : 7;
    }

    @Override
    public boolean getBit() throws IOException {
        if (endian == LITTLE_ENDIAN) {
            if (bitIndex > 7) {
                bitIndex = 0;
                currentByte = source[++byteIndex];
            }
            return (currentByte & (1 << (bitIndex++))) != 0;
        } else {
            if (bitIndex < 0) {
                bitIndex = 7;
                currentByte = source[++byteIndex];
            }
            return (currentByte & (1 << (bitIndex--))) != 0;
        }
    }

    @Override
    public int getInt(int bits) throws IOException {
        if (bits > 32) {
            throw new IllegalArgumentException(
                    "Argument \"bits\" must be <= 32");
        }
        int res = 0;
        if (endian == LITTLE_ENDIAN) {
            for (int i = 0; i < bits; i++) {
                if (getBit()) {
                    res |= (1 << i);
                }
            }
        } else {
            if (bitIndex < 0) {
                bitIndex = 7;
                currentByte = source[++byteIndex];
            } else if (bitIndex >= 7) {
                currentByte = source[--byteIndex];
            }
            if (bits <= bitIndex + 1) {
                int ci = ((int) currentByte) & 0xff;
                int offset = 1 + bitIndex - bits;
                int mask = ((1 << bits) - 1) << offset;
                res = (ci & mask) >> offset;
                bitIndex -= bits;
            } else {
                res = (((int) currentByte) & 0xff & ((1 << (bitIndex + 1)) - 1))
                        << (bits - bitIndex - 1);
                bits -= bitIndex + 1;
                currentByte = source[++byteIndex];
                while (bits >= 8) {
                    bits -= 8;
                    res |= (((int) source[byteIndex]) & 0xff) << bits;
                    currentByte = source[++byteIndex];
                }
                if (bits > 0) {
                    int ci = ((int) source[byteIndex]) & 0xff;
                    res |= (ci >> (8 - bits)) & ((1 << bits) - 1);
                    bitIndex = 7 - bits;
                } else {
                    currentByte = source[--byteIndex];
                    bitIndex = -1;
                }
            }
        }

        return res;
    }

    @Override
    public int getSignedInt(int bits) throws IOException {
        int raw = getInt(bits);
        if (raw >= 1 << (bits - 1)) {
            raw -= 1 << bits;
        }
        return raw;
    }

    @Override
    public int getInt(HuffmanNode root) throws IOException {
        while (root.value == null) {
            if (bitIndex > 7) {
                bitIndex = 0;
                currentByte = source[++byteIndex];
            }
            root = (currentByte & (1 << (bitIndex++))) != 0 ? root.o1 : root.o0;
        }
        return root.value;
    }

    @Override
    public long getLong(int bits) throws IOException {
        if (bits > 64) {
            throw new IllegalArgumentException(
                    "Argument \"bits\" must be <= 64");
        }
        long res = 0;
        if (endian == LITTLE_ENDIAN) {
            for (int i = 0; i < bits; i++) {
                if (getBit()) {
                    res |= (1L << i);
                }
            }
        } else {
            for (int i = bits - 1; i >= 0; i--) {
                if (getBit()) {
                    res |= (1L << i);
                }
            }
        }
        return res;
    }

    /**
     * 

* reads an integer encoded as "signed rice" as described in the FLAC audio * format specification

* *

* not supported for little endian

* * @param order * @return the decoded integer value read from the stream * * @throws IOException if an I/O error occurs * @throws UnsupportedOperationException if the method is not supported by * the implementation */ @Override public int readSignedRice(int order) throws IOException { int msbs = -1, lsbs = 0, res = 0; if (endian == LITTLE_ENDIAN) { // little endian throw new UnsupportedOperationException( "ByteArrayBitInputStream.readSignedRice() " + "is only supported in big endian mode"); } else { // big endian byte cb = source[byteIndex]; do { msbs++; if (bitIndex < 0) { bitIndex = 7; byteIndex++; cb = source[byteIndex]; } } while ((cb & (1 << bitIndex--)) == 0); int bits = order; if (bitIndex < 0) { bitIndex = 7; byteIndex++; } if (bits <= bitIndex + 1) { int ci = ((int) source[byteIndex]) & 0xff; int offset = 1 + bitIndex - bits; int mask = ((1 << bits) - 1) << offset; lsbs = (ci & mask) >> offset; bitIndex -= bits; } else { lsbs = (((int) source[byteIndex]) & 0xff & ((1 << (bitIndex + 1)) - 1)) << (bits - bitIndex - 1); bits -= bitIndex + 1; byteIndex++; while (bits >= 8) { bits -= 8; lsbs |= (((int) source[byteIndex]) & 0xff) << bits; byteIndex++; } if (bits > 0) { int ci = ((int) source[byteIndex]) & 0xff; lsbs |= (ci >> (8 - bits)) & ((1 << bits) - 1); bitIndex = 7 - bits; } else { byteIndex--; bitIndex = -1; } } res = (msbs << order) | lsbs; } return (res & 1) == 1 ? -(res >> 1) - 1 : (res >> 1); } /** *

* fills the array from {@code offset} with {@code len} integers encoded as * "signed rice" as described in the FLAC audio format specification

* *

* not supported for little endian

* * @param order * @param buffer * @param off offset * @param len * * @throws IOException if an I/O error occurs * @throws UnsupportedOperationException if the method is not supported by * the implementation */ @Override public void readSignedRice(int order, int[] buffer, int off, int len) throws IOException { if (endian == LITTLE_ENDIAN) { // little endian throw new UnsupportedOperationException( "ByteArrayBitInputStream.readSignedRice() " + "is only supported in big endian mode"); } else { // big endian for (int i = off; i < off + len; i++) { int msbs = -1, lsbs = 0; byte cb = source[byteIndex]; do { msbs++; if (bitIndex < 0) { bitIndex = 7; byteIndex++; cb = source[byteIndex]; } } while ((cb & (1 << bitIndex--)) == 0); int bits = order; if (bits <= bitIndex + 1) { int ci = ((int) source[byteIndex]) & 0xff; int offset = 1 + bitIndex - bits; int mask = ((1 << bits) - 1) << offset; lsbs = (ci & mask) >> offset; bitIndex -= bits; } else { lsbs = (((int) source[byteIndex]) & 0xff & ((1 << (bitIndex + 1)) - 1)) << (bits - bitIndex - 1); bits -= bitIndex + 1; byteIndex++; while (bits >= 8) { bits -= 8; lsbs |= (((int) source[byteIndex]) & 0xff) << bits; byteIndex++; } if (bits > 0) { int ci = ((int) source[byteIndex]) & 0xff; lsbs |= (ci >> (8 - bits)) & ((1 << bits) - 1); bitIndex = 7 - bits; } else { byteIndex--; bitIndex = -1; } } int res = (msbs << order) | lsbs; buffer[i] = (res & 1) == 1 ? -(res >> 1) - 1 : (res >> 1); } } } @Override public void align() { if (endian == BIG_ENDIAN && bitIndex >= 0) { bitIndex = 7; byteIndex++; } else if (endian == LITTLE_ENDIAN && bitIndex <= 7) { bitIndex = 0; byteIndex++; } } @Override public void setEndian(int endian) { if (this.endian == BIG_ENDIAN && endian == LITTLE_ENDIAN) { bitIndex = 0; byteIndex++; } else if (this.endian == LITTLE_ENDIAN && endian == BIG_ENDIAN) { bitIndex = 7; byteIndex++; } this.endian = endian; } /** * @return the byte array used as a source for this instance */ public byte[] getSource() { return source; } @Override public int position() { return byteIndex; } @Override public void skip(int length) { if (this.endian == BIG_ENDIAN) { bitIndex = 7; } else if (this.endian == LITTLE_ENDIAN) { bitIndex = 0; } byteIndex += length; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy