Skip to content
Snippets Groups Projects
InBitStream.java 2.94 KiB
Newer Older
  • Learn to ignore specific revisions
  • Vojtech Moravec's avatar
    Vojtech Moravec committed
    package azgracompress.io;
    
    Vojtech Moravec's avatar
    Vojtech Moravec committed
    
    import java.io.IOException;
    import java.io.InputStream;
    
    
    public class InBitStream implements AutoCloseable {
    
    Vojtech Moravec's avatar
    Vojtech Moravec committed
    
    
        private final InputStream inputStream;
        private final byte[] buffer;
    
    Vojtech Moravec's avatar
    Vojtech Moravec committed
        private int bufferPosition;
        private int bytesAvailable;
    
        private byte bitBuffer;
        private byte bitBufferSize;
    
        private final int bitsPerValue;
    
    
        private boolean allowReadFromUnderlyingStream = true;
    
    
        public InBitStream(final InputStream inputStream, final int bitsPerValue, final int bufferSize) {
    
    Vojtech Moravec's avatar
    Vojtech Moravec committed
            this.inputStream = inputStream;
            this.bitsPerValue = bitsPerValue;
    
            buffer = new byte[bufferSize];
            bufferPosition = 0;
            bytesAvailable = 0;
    
            bitBuffer = 0;
            bitBufferSize = 0;
        }
    
    
        /**
         * Read whole buffer from input stream.
         *
         * @throws IOException when unable to read from input stream.
         */
    
        public void readToBuffer() throws IOException {
    
            int toRead = buffer.length;
            while (toRead > 0) {
                toRead -= inputStream.read(buffer, buffer.length - toRead, toRead);
            }
            bytesAvailable = buffer.length;
    
    Vojtech Moravec's avatar
    Vojtech Moravec committed
        private void readByteToBitBuffer() throws IOException {
    
            if (!(bufferPosition < bytesAvailable)) {
    
                if (!allowReadFromUnderlyingStream) {
                    throw new IOException("Can not read from underlying stream.");
                }
                readToBuffer();
    
    Vojtech Moravec's avatar
    Vojtech Moravec committed
            }
    
            if (bufferPosition < bytesAvailable) {
                bitBuffer = buffer[bufferPosition++];
                bitBufferSize = 8;
            } else {
                assert (false) : "Underlying buffer is empty.";
            }
        }
    
    
    
        public boolean readBit() throws IOException {
            return (readBitFromBuffer() == 1);
        }
    
        private int readBitFromBuffer() throws IOException {
    
    Vojtech Moravec's avatar
    Vojtech Moravec committed
            if (bitBufferSize == 0) {
                readByteToBitBuffer();
            }
            --bitBufferSize;
    
            final int bit = bitBuffer & (1 << bitBufferSize);
    
    Vojtech Moravec's avatar
    Vojtech Moravec committed
            return (bit > 0 ? 1 : 0);
        }
    
        public int readValue() throws IOException {
            int result = 0;
            int bit;
    
            //writing => bit = (value & (1 << shift));
            for (int shift = 0; shift < bitsPerValue; shift++) {
    
                bit = readBitFromBuffer();
    
    Vojtech Moravec's avatar
    Vojtech Moravec committed
                result |= (bit << shift);
            }
            return result;
        }
    
    
        public int[] readNValues(final int n) throws IOException {
    
            final int[] values = new int[n];
    
            for (int i = 0; i < n; i++) {
                values[i] = readValue();
            }
            return values;
        }
    
    
        public boolean canReadFromUnderlyingStream() {
            return allowReadFromUnderlyingStream;
        }
    
        public void setAllowReadFromUnderlyingStream(final boolean allowReadFromUnderlyingStream) {
            this.allowReadFromUnderlyingStream = allowReadFromUnderlyingStream;
        }
    
    
    
        @Override
        public void close() throws Exception {
            bitBufferSize = 0;
            bytesAvailable = 0;
        }
    
    Vojtech Moravec's avatar
    Vojtech Moravec committed
    }