use std::cmp;
use crate::common::Result;
use crate::Exceptions;
pub struct BitSource {
bytes: Vec<u8>,
byte_offset: usize,
bit_offset: usize,
}
impl BitSource {
pub fn new(bytes: Vec<u8>) -> Self {
Self {
bytes,
byte_offset: 0,
bit_offset: 0,
}
}
pub fn getBitOffset(&self) -> usize {
self.bit_offset
}
pub fn getByteOffset(&self) -> usize {
self.byte_offset
}
pub fn readBits(&mut self, numBits: usize) -> Result<u32> {
if !(1..=32).contains(&numBits) || numBits > self.available() {
return Err(Exceptions::illegal_argument_with(numBits.to_string()));
}
let mut result: u32 = 0;
let mut num_bits = numBits;
if self.bit_offset > 0 {
let bitsLeft = 8 - self.bit_offset;
let toRead = cmp::min(num_bits, bitsLeft);
let bitsToNotRead = bitsLeft - toRead;
let mask = (0xFF >> (8 - toRead)) << bitsToNotRead;
result = (self.bytes[self.byte_offset] & mask) as u32 >> bitsToNotRead;
num_bits -= toRead;
self.bit_offset += toRead;
if self.bit_offset == 8 {
self.bit_offset = 0;
self.byte_offset += 1;
}
}
if num_bits > 0 {
while num_bits >= 8 {
result = (result << 8) | self.bytes[self.byte_offset] as u32;
self.byte_offset += 1;
num_bits -= 8;
}
if num_bits > 0 {
let bits_to_not_read = 8 - num_bits;
let mask = (0xFF >> bits_to_not_read) << bits_to_not_read;
result = (result << num_bits)
| ((self.bytes[self.byte_offset] & mask) as u32 >> bits_to_not_read);
self.bit_offset += num_bits;
}
}
Ok(result)
}
pub fn peak_bits(&self, numBits: usize) -> Result<u32> {
if !(1..=32).contains(&numBits) || numBits > self.available() {
return Err(Exceptions::illegal_argument_with(numBits.to_string()));
}
let mut bit_offset = self.bit_offset;
let mut byte_offset = self.byte_offset;
let mut result: u32 = 0;
let mut num_bits = numBits;
if self.bit_offset > 0 {
let bitsLeft = 8 - self.bit_offset;
let toRead = cmp::min(num_bits, bitsLeft);
let bitsToNotRead = bitsLeft - toRead;
let mask = (0xFF >> (8 - toRead)) << bitsToNotRead;
result = (self.bytes[self.byte_offset] & mask) as u32 >> bitsToNotRead;
num_bits -= toRead;
bit_offset += toRead;
if bit_offset == 8 {
byte_offset += 1;
}
}
if num_bits > 0 {
while num_bits >= 8 {
result = (result << 8) | self.bytes[byte_offset] as u32;
byte_offset += 1;
num_bits -= 8;
}
if num_bits > 0 {
let bits_to_not_read = 8 - num_bits;
let mask = (0xFF >> bits_to_not_read) << bits_to_not_read;
result = (result << num_bits)
| ((self.bytes[byte_offset] & mask) as u32 >> bits_to_not_read);
}
}
Ok(result)
}
pub fn available(&self) -> usize {
8 * (self.bytes.len() - self.byte_offset) - self.bit_offset
}
}