package com.justwayward.reader.view.chmview; import java.io.EOFException; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; public class BitsInputStream extends FilterInputStream { int bitbuf; int bitsLeft; static final int BUFFER_BITS = 32; static final int[] UNSIGNED_MASK = new int[]{ 0, 0x01, 0x03, 0x07, 0x0f, 0x01f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff, }; public BitsInputStream(InputStream in) { super(in); } /** * Read 32-bit little endian int instead of a byte! */ public int read32LE() throws IOException { return in.read() + (in.read() << 8) + (in.read() << 16) + (in.read() << 24); } /** * flush n bytes, and reset bitbuf, bitsLeft * often used to align the byte array * NOTE: n may be negative integer, e.g. -2 */ public void skip(int n) throws IOException { bitbuf = 0; bitsLeft = 0; super.skip(n); } /** * Make sure there are at least n (<=16) bits in the buffer, * otherwise, read a 16-bit little-endian word from the byte array. * returns bitsLeft; */ public int ensure(int n) throws IOException { while (bitsLeft < n) { // read in two bytes int b1 = in.read(); int b2 = in.read(); if ((b1 | b2) < 0) break; bitbuf |= (b1 | (b2 << 8)) << (BUFFER_BITS - 16 - bitsLeft); bitsLeft += 16; } return bitsLeft; } /** * Read no more than 16 bits big endian, bits are arranged as * <pre> * 00000000 00000000 00000000 00000000, bitsLeft = 0; * ensure(1); * aaaaaaaa 00000000 00000000 00000000, bitsLeft = 8; * read(3) = 00000aaa; * aaaaa000 00000000 00000000 00000000, bitsLeft = 5; * ensure(16); * aaaaabbb bbbbbccc ccccc000 00000000, bitsLeft = 21; * read(8) = aaaaabbb; * bbbbbccc ccccc000 00000000 00000000, bitsLeft = 13; * </pre> */ public int readLE(int n) throws IOException { int ret = peek(n); bitbuf <<= n; bitsLeft -= n; return ret; } /** * Peek n bits, may raise EOFException. */ public int peek(int n) throws IOException { if (ensure(n) < n) throw new EOFException(); return ((bitbuf >> (BUFFER_BITS - n))) & UNSIGNED_MASK[n]; } /** * Peek no more than n bits, so there is no EOFException. */ public int peekUnder(int n) throws IOException { ensure(n); return ((bitbuf >> (BUFFER_BITS - n))) & UNSIGNED_MASK[n]; } public void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); } public void readFully(byte b[], int off, int len) throws IOException { for (int n = 0; n < len; ) { int count = read(b, off + n, len - n); if (count < 0) throw new EOFException(); n += count; } } /** * return binary string of bitbuf */ public String toString() { String s = "00000000000000000000000000000000" + Long.toBinaryString(bitbuf); s = s.substring(s.length() - 32); return s.substring(0, 8) + " " + s.substring(8, 16) + " " + s.substring(16, 24) + " " + s.substring(24, 32) + " " + bitsLeft; } }