/* * Copyright (C) 2008 Steve Ratcliffe * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * Author: Steve Ratcliffe * Create date: 29-Aug-2008 */ package uk.me.parabola.imgfmt.app; /** * Read an array as a bit stream. * * @author Steve Ratcliffe */ public class BitReader { private final byte[] buf; private int bitPosition; public BitReader(byte[] buf) { this.buf = buf; } public boolean get1() { int off = bitPosition % 8; byte b = buf[bitPosition / 8]; bitPosition++; return ((b >> off) & 1) == 1; } public int get(int n) { int res = 0; int pos = 0; while (pos < n) { int index = bitPosition / 8; int off = bitPosition % 8; byte b = buf[index]; b >>= off; int nbits = n - pos; if (nbits > (8-off)) nbits = 8 - off; int mask = ((1 << nbits) - 1); res |= ((b & mask) << pos); pos += nbits; bitPosition += nbits; } return res; } /** * Get a signed quantity. * * The sign bit is the last bit in the field. * * @param n The field width, including the sign bit. * @return A signed number. */ public int sget(int n) { int res = get(n); int top = 1 << (n - 1); if ((res & top) != 0) { int mask = top - 1; res = ~mask | res; } return res; } /** * Get a signed n-bit value, treating 1 << (n-1) as a flag to read another signed n-bit value * for extended range. */ public int sget2(int n) { int top = 1 << (n - 1); int mask = top - 1; int base = 0; int res = get(n); while (res == top) { // Add to the base value, and read another base += mask; res = get(n); } // The final byte determines the sign of the result. Add or subtract the base as // appropriate. if ((res & top) == 0) res += base; else res = (res | ~mask) - base; // Make negative and subtract the base return res; } public int getBitPosition() { return bitPosition; } public int getNumberOfBits() { return buf.length * 8; } /** * Debugging routine that returns the remainder of the stream as a string. * The bits are in little endian order, so that numbers can be read from left * to right, although the whole string has to read from right to left. * * @return A string in binary. */ public String remainder() { int save = bitPosition; StringBuilder sb = new StringBuilder(); while (bitPosition < buf.length * 8) { sb.insert(0, get1() ? "1" : "0"); } bitPosition = save; return sb.toString(); } }