19 Mayıs 2021 Çarşamba

BitStream

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);
}


Hiç yorum yok:

Yorum Gönder