GirişSınıf şöyle olsun. Byte'lar yazacağımız için 8 tane mask yeterli.
public class BitStream {
protected byte[] data;
protected byte[] sizeInBytes;
protected int bitPosition;
protected int bytePosition;
static final int BYTE_LENGTH = 8;
static final int DEFAULT_SIZE = 16;
static final int GROW_SIZE = 16;
static int[] MASKS = {
0, //0
0x1, //1
0x3, //2
0x7, //3
0xf, //4
0x1f, //5
0x3f, //6
0x7f, //7
0xff, //8
}
...
}
Constructor metodlar şöyle
//For writing
public BitStream {
data = new byte[DEFAULT_SIZE];
sizeInBytes = data.length;
}
//For writing
public BitStream(int capacity) {
data = new byte[capacity];
sizeInBytes = data.length;
}
//For reading
public BitStream(byte[] data {
this.data = data;
sizeInBytes = data.length;
}
Bazı yardımcı metodlar şöyle
public void flipForReading(){
data = toByteArray();
bitPosition = 0;
bytePosition = 0;
}
public void growCapacity() {
data = Arrays.copyOf(data,data.length + GROW_SIZE);
}
//Compelete or partial readable bytes after write operation
public int getReadableBytes() {
if (bytePosition == 0 && bitPosition == 0) {
return 0;
}
return bytePosition + 1;
}
public byte[] toByteArray() {
int length = getReadableBytes();
return Arrays.copyOf(data,length);
}
readNBits metodu
Burada en fazla 32 bit okunabilir. Bit shift işlemleri integer olarak yapılıyor ancak sonuç unsigned olsun diye long olarak döndürülüyor.
- //1 ile işaretli yerde mask bitPosition sayısı kadar kaydırılır. Böylece doğru mask elde edilir. Buffer'dan istenilen bit sayısı okunduktan sonra elde edilen değer tekrar sağa kaydırılır.
- //2 ile işaretli yerde okunan değer toplam okunan bit sayısı kadar kaydırılır ve sonuca dahil edilir.
public long readNBits (int numBits) {
if (numBits > 32) {
throw new IllegalArgumentException();
}
int result = 0;
int bitsReadSoFar = 0;
while (numBits > 0) {
int bitsToRead = numBits;
//It is ok to pass the buffer boundary
if (bitPosition == BYTE_LENGTH) {
gotoNextByte();
}
if (numBits + bitPosition) > BYTE_LENGTH) {
bitsToRead = BYTE_LENGTH - bitPosition;
}
numberOfBits -= bitsToRead;
//1
int buf = ((MASKS [bitsToRead] << bitPosition) & data [bytePosition]) >> bitPosition;
bitPosition += bitsToRead;
//2
result |= (buf << bitsReadSoFar);
bitsReadSoFar += bitsToRead;
} //while
return Integer.toUnsignedLong(result);
}
gotoNextByte şöyle
protected void gotoNextByte() {
++bytePosition;
bitPosition = 0;
}
writeNBits metodu
Şöyle
public void writeNBits(long value, int numBits) {
if (numbits > 32) {
throw new IllegalArgumentException();
}
while(numBits > 0) {
int bitsToWrite = numBits;
if (bitPosition == BYTE_LENGTH) {
gotoNextByte();
}
if ((numBits + bitPosition) > BYTE_LENGTH) {
bitToWrite = BYTE_LENGTH - bitPosition;
}
numBits -= bitsToWrite;
data[bytePosition] &= (byte) ~(MASKS[bitsToWrite] << bitPosition);
data[bytePosition] |= (byte) ((value & MASKS[bitsToWrite]) << bitPosition);
bitPosition += bitsToWrite;
value = (value >> bitsToWrite);
}
}
Elimizde bu iki metod olduktan sonra diğer tipleri yazıp okumak kolay. Şöyle yaparız
public boolean readBoolean() {
int data = (int) readNBits (1);
return data == 1;
}
public void writeBoolean(boolean value) {
int data = value ? 1 : 0;
writeNBits(data,1);
}
public float readFloat() {
int intBits = (int) readNBits(32);
return Float.intBitsToFloat(intBits);
}
public void writeFloat(float value) {
int intBits = Float.floatToRawIntBits(value);
writeNBits(intBits,32);
}