package com.pblabs.profiler; import java.io.EOFException; public class BitStream { private final int BYTE_LENGTH = 8; private byte bits[]; private int currentBit; private int totalBits; private NetStringCache stringCache; public BitStream(int lengthInBytes) { bits = new byte[lengthInBytes]; currentBit = 0; totalBits = lengthInBytes * BYTE_LENGTH; } public BitStream(int lengthInBytes, byte data[]) { bits = data; currentBit = 0; totalBits = lengthInBytes * BYTE_LENGTH; } public boolean readFlag() throws EOFException { if(currentBit >= totalBits) throw new EOFException(); byte b = bits[currentBit>>3]; return ((b >> (currentBit++ & 0x7)) & 0x1) == 1; } public byte readByte() throws EOFException { byte b = 0; for(int i=0; i<BYTE_LENGTH; i++) b |= boolToInt(readFlag()) << i; return b; } public int readInt(int bitCount) throws EOFException { int val = 0; for(int i=0; i<bitCount; i++) val |= boolToInt(readFlag()) << i; return val; } public float readFloat(int bitCount) throws EOFException { return readInt(bitCount) / (float)((1 << bitCount) - 1); } public boolean writeFlag(boolean value) throws EOFException { if(currentBit >= totalBits) throw new EOFException(); if(value) bits[currentBit>>3] |= (1 << (currentBit & 0x7)); else bits[currentBit>>3] &= ~(1 << (currentBit & 0x7)); currentBit++; return value; } public void writeByte(byte value) throws EOFException { for(int i=0; i<BYTE_LENGTH; i++) writeFlag( ((value>>i)&1) == 1 ); } public void writeInt(int value, int bitCount) throws EOFException { for(int i=0; i<bitCount; i++) writeFlag( ((value>>i)&1) == 1 ); } public void writeFloat(float value, int bitCount) throws EOFException { writeInt((int)(value * ((1 << bitCount) - 1)), bitCount); } public void writeString(String s) throws EOFException { writeInt(s.length(), 10); for(int i=0; i<s.length(); i++) writeByte(s.getBytes()[i]); } public String readString() throws EOFException { int length = readInt(10); String result = new String(); for(int i=0; i<length; i++) { result += (char)readByte(); } return result; } /** * Write int where min <= int < max. * @throws EOFException */ public void writeRangedInt(int value, int min, int max) throws EOFException { int range = max - min + 1; // TODO: Make this use bits and be fast. int bitCount = (int)Math.ceil(Math.log10(range) / Math.log10(2.0)); writeInt(value - min, bitCount); } public int readRangedInt(int min, int max) throws EOFException { int range = max - min + 1; // TODO: Make this use bits and be fast. int bitCount = (int)Math.ceil(Math.log10(range) / Math.log10(2.0)); return readInt(bitCount) + min; } public void setStringCache(NetStringCache nsc) { stringCache = nsc; } public NetStringCache getStringCache() { return stringCache; } public void writeCachedString(String s) throws EOFException { stringCache.write(this, s); } public String readCachedString() throws EOFException { return stringCache.read(this); } public int getLengthInBytes() { return (currentBit+7) >> 3; } public byte[] getBytes() { return bits; } public void reset() { currentBit = 0; } public boolean isEof() { return currentBit >= totalBits; } public int getCurrentPosition() { return currentBit; } public void setCurrentPosition(int bit) throws Exception { if(bit >= totalBits || bit < 0) throw new Exception("Out of bounds."); currentBit = bit; } public int getRemainingBits() { return (totalBits - 1) - currentBit; } private static int boolToInt(boolean bit) { if(bit) return 1; else return 0; } }