package org.jcodec.common.io; import java.lang.IllegalArgumentException; import java.nio.ByteBuffer; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * @author The JCodec project * */ public class BitReader { public static BitReader createBitReader(ByteBuffer bb) { BitReader r = new BitReader(bb); r.curInt = r.readInt(); r.deficit = 0; return r; } private int deficit = -1; private int curInt = -1; private ByteBuffer bb; private int initPos; private BitReader(ByteBuffer bb) { this.bb = bb; this.initPos = bb.position(); } public BitReader fork() { BitReader fork = new BitReader(this.bb.duplicate()); fork.initPos = 0; fork.curInt = this.curInt; fork.deficit = this.deficit; return fork; } public final int readInt() { if (bb.remaining() >= 4) { deficit -= 32; return ((bb.get() & 0xff) << 24) | ((bb.get() & 0xff) << 16) | ((bb.get() & 0xff) << 8) | (bb.get() & 0xff); } else return readIntSafe(); } private int readIntSafe() { deficit -= (bb.remaining() << 3); int res = 0; if (bb.hasRemaining()) res |= bb.get() & 0xff; res <<= 8; if (bb.hasRemaining()) res |= bb.get() & 0xff; res <<= 8; if (bb.hasRemaining()) res |= bb.get() & 0xff; res <<= 8; if (bb.hasRemaining()) res |= bb.get() & 0xff; return res; } public int read1Bit() { int ret = curInt >>> 31; curInt <<= 1; ++deficit; if (deficit == 32) { curInt = readInt(); } // System.out.println(ret); return ret; } public int readNBit(int n) { if (n > 32) throw new IllegalArgumentException("Can not read more then 32 bit"); int nn = n; int ret = 0; if (n + deficit > 31) { ret |= (curInt >>> deficit); n -= 32 - deficit; ret <<= n; deficit = 32; curInt = readInt(); } if (n != 0) { ret |= curInt >>> (32 - n); curInt <<= n; deficit += n; } // for(--nn; nn >=0; nn--) // System.out.print((ret >> nn) & 1); // System.out.println(); return ret; } public boolean moreData() { int remaining = bb.remaining() + 4 - ((deficit + 7) >> 3); return remaining > 1 || (remaining == 1 && curInt != 0); } public int remaining() { return (bb.remaining() << 3) + 32 - deficit; } public final boolean isByteAligned() { return (deficit & 0x7) == 0; } public int skip(int bits) { int left = bits; if (left + deficit > 31) { left -= 32 - deficit; deficit = 32; if (left > 31) { int skip = Math.min(left >> 3, bb.remaining()); bb.position(bb.position() + skip); left -= skip << 3; } curInt = readInt(); } deficit += left; curInt <<= left; return bits; } public int skipFast(int bits) { deficit += bits; curInt <<= bits; return bits; } public int align() { return (deficit & 0x7) > 0 ? skip(8 - (deficit & 0x7)) : 0; } public int check24Bits() { if (deficit > 16) { deficit -= 16; curInt |= nextIgnore16() << deficit; } if (deficit > 8) { deficit -= 8; curInt |= nextIgnore() << deficit; } return curInt >>> 8; } public int check16Bits() { if (deficit > 16) { deficit -= 16; curInt |= nextIgnore16() << deficit; } return curInt >>> 16; } public int readFast16(int n) { if (n == 0) return 0; if (deficit > 16) { deficit -= 16; curInt |= nextIgnore16() << deficit; } int ret = curInt >>> (32 - n); deficit += n; curInt <<= n; return ret; } public int checkNBit(int n) { if (n > 24) throw new IllegalArgumentException("Can not check more then 24 bit"); while (deficit + n > 32) { deficit -= 8; curInt |= nextIgnore() << deficit; } int res = curInt >>> (32 - n); // for (int i = n - 1; i >= 0; i--) { // System.out.print((res >> i) & 0x1); // } // System.out.println(); return res; } private int nextIgnore16() { return bb.remaining() > 1 ? bb.getShort() & 0xffff : (bb.hasRemaining() ? ((bb.get() & 0xff) << 8) : 0); } private int nextIgnore() { return bb.hasRemaining() ? bb.get() & 0xff : 0; } public int curBit() { return deficit & 0x7; } public boolean lastByte() { return bb.remaining() + 4 - (deficit >> 3) <= 1; } public void terminate() { int putBack = (32 - deficit) >> 3; bb.position(bb.position() - putBack); } public int position() { return ((bb.position() - initPos - 4) << 3) + deficit; } /** * Stops this bit reader. Returns underlying ByteBuffer pointer to the next * byte unread byte */ public void stop() { bb.position(bb.position() - ((32 - deficit) >> 3)); } public int checkAllBits() { return curInt; } }