📄 bitinput.java
字号:
package com.aliasi.io;import com.aliasi.util.Math;import java.io.InputStream;import java.io.IOException;/** * A <code>BitInput</code> wraps an underlying input stream to provide * bit-level input. Input is read through the method {@link * #readBit()}, which returns a boolean value. Bits are coded * as booleans, with <code>true=1</code> and <code>false=0</code>. * * @author Bob Carpenter * @version 2.1.1 * @since 2.1.1 */public class BitInput { private final InputStream mIn; private int mNextByte; // implied = 0; private int mNextBitIndex; private boolean mEndOfStream = false; /** * Constructs a bit input wrapping the specified input stream. * The input stream is accessed by the constructor to fill * a read-ahead buffer. Thus the constructor will throw an * exception if there is a read exception * @param in Input stream backing this bit input. * @throws IOException If there is an exception reading from the * specified input stream. */ public BitInput(InputStream in) throws IOException { mIn = in; readAhead(); } /** * Returns number of bits available for reading without blocking. * This is the sum of the number of bits buffered and the result * of querying the number of bytes available from the underlying * input stream using {@link InputStream#available()}. * * @return Number of bits available for reading. * @throws IOException If there is an exception while checking * availability in the underlying input stream. */ public long available() throws IOException { return mEndOfStream ? 0l : ((mNextBitIndex + 1l) + (8l * (long) mIn.available())); } /** * Closes this input stream and releases associated resources. * This method will close the underlying input stream for this bit * input by calling {@link InputStream#close()}. After calls to * this method, {@link #available()} will return zero and {@link * #endOfStream()} will return <code>true</code>. * * @throws IOException If there is an exception closing the * underlying input stream. */ public void close() throws IOException { mEndOfStream = true; mIn.close(); } /** * Returns <code>true</code> if all of the available bits have * been read or if this stream has been closed. * * @return <code>true</code> if all of the available bits have * been read. */ public boolean endOfStream() { return mEndOfStream; } /** * Skips and discards the specified number of bits in the input. * The return value is the number of bits skipped, which may be * less than the number requested if the end-of-stream is reached * or if the underlying input stream cannot skip the required * number of bytes. * * @param numBits Number of bits to skip. * @return Number of bits actually skipped. * @throws IOException If there is an I/O error skipping on the * underlying input stream. * @throws IllegalArgumentException If the number of bits argument * is less than zero. */ public long skip(long numBits) throws IOException { if (numBits < 0) { String msg = "Require positive number of bits to skip." + " Found numBits=" + numBits; throw new IllegalArgumentException(msg); } if (mNextBitIndex >= numBits) { mNextBitIndex -= numBits; // decrement within byte buffer return numBits; } long numBitsSkipped = mNextBitIndex + 1; long numBitsLeft = numBits - numBitsSkipped; long bytesToSkip = numBitsLeft / 8; long bytesSkipped = mIn.skip(bytesToSkip); numBitsSkipped += 8 * bytesSkipped; if (bytesSkipped < bytesToSkip) { mEndOfStream = true; // exhausted input stream return numBitsSkipped; } readAhead(); if (mEndOfStream) return numBitsSkipped; // nothing left mNextBitIndex = 7 - (((int)numBitsLeft) % 8); return numBits; } /** * Reads the next bit from the input stream. Bits are encoded * as binary values, using <code>true</code> for <code>1</code> * and <code>false</code> for <code>0</code>. * * <P>The return value is undefined if the end of stream has been * reached, but this method will not throw an exception. * * @return The boolean value of the next bit. * @throws IOException If there is an exception reading from the * underlying stream. */ public boolean readBit() throws IOException { switch (mNextBitIndex--) { case 0: boolean result = ((mNextByte & 1) != 0); readAhead(); return result; case 1: return ((mNextByte & 2) != 0); case 2: return ((mNextByte & 4) != 0); case 3: return ((mNextByte & 8) != 0); case 4: return ((mNextByte & 16) != 0); case 5: return ((mNextByte & 32) != 0); case 6: return ((mNextByte & 64) != 0); case 7: return ((mNextByte & 128) != 0); default: String msg = "Index out of bounds. mNextBitIndex=" + mNextBitIndex; throw new IOException(msg); } } /** * Reads the next value from the input using a unary code. If all * of the remaining bits are zeros, it throws an I/O exception. * If the end of stream has been reached, it returns -1. * * <P>See {@link BitOutput#writeUnary(int)} for a description of * unary coding. * * @return The next integer read with unary code. * @throws IOException If the remaining bits are all zeros. */ public int readUnary() throws IOException { int result = 1; // look through remaining buffered bits for ( ; !endOfStream() && mNextBitIndex != 7; ++result) if (readBit()) return result; // jump over whole 0 bytes while (!endOfStream() && mNextByte == ZERO_BYTE) { result += 8; mNextByte = mIn.read(); if (mNextByte == -1) { String msg = "Final sequence of 0 bits with no 1"; throw new IOException(msg); } } // read to last one bit (could do the search trick here!) while (!readBit()) // know we'll find it given last test ++result; return result; } /** * Skips over and discards the next value from the input using a * unary code. * * @throws IOException If there is a format error in the input stream * or an error reading from the underlying stream. */ public void skipUnary() throws IOException { // cut and paste from readUnary without result increments // look through remaining buffered bits while (!endOfStream() && mNextBitIndex != 7) if (readBit()) return; // jump over whole 0 bytes while (!endOfStream() && mNextByte == ZERO_BYTE) { mNextByte = mIn.read(); if (mNextByte == -1) { String msg = "Final sequence of 0 bits with no 1"; throw new IOException(msg); } } // read to last one bit (could do the search trick here!) while (!readBit()) ; // know we'll find it given last test // } /** * Reads the next value from the input using an Elias gamma code. * If the code is incomplete or not well-formed, an I/O exception * is raised. If the end of stream has been reached, the value * returned is -1. * * <P>See {@link BitOutput#writeGamma(long)} for a description of * gamma coding. * * @return The next integer read using gamma coding. * @throws IOException If the prefix of the remaining bits is not * a valid gamma code or if there is an error reading from the * underlying input stream. */ public long readGamma() throws IOException { int numBits = readUnary(); if (numBits > 63) { String msg = "Gamma code binary part must be <= 63 bits." + " Found numBits=" + numBits; throw new IOException(msg); } return readRest(numBits-1,1l); } /** * Skips over and discards the next value from the input using an * Elias gamma code. * * @throws IOException If there is a format error in the input stream * or an error reading from the underlying stream.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -