use std::fmt;
use std::error::Error;
use std::result;
#[cfg(test)]
mod tests;
pub struct BitReader<'a> {
bytes: &'a [u8],
position: u64,
relative_offset: u64,
}
impl<'a> BitReader<'a> {
pub fn new(bytes: &'a [u8]) -> BitReader<'a> {
BitReader {
bytes: bytes,
position: 0,
relative_offset: 0,
}
}
pub fn relative_reader(&self) -> BitReader<'a> {
BitReader {
bytes: self.bytes,
position: self.position,
relative_offset: self.position,
}
}
pub fn read_u8(&mut self, bit_count: u8) -> Result<u8> {
let value = try!(self.read_value(bit_count, 8));
Ok((value & 0xff) as u8)
}
pub fn read_u16(&mut self, bit_count: u8) -> Result<u16> {
let value = try!(self.read_value(bit_count, 16));
Ok((value & 0xffff) as u16)
}
pub fn read_u32(&mut self, bit_count: u8) -> Result<u32> {
let value = try!(self.read_value(bit_count, 32));
Ok((value & 0xffffffff) as u32)
}
pub fn read_u64(&mut self, bit_count: u8) -> Result<u64> {
let value = try!(self.read_value(bit_count, 64));
Ok(value)
}
pub fn read_i8(&mut self, bit_count: u8) -> Result<i8> {
let value = try!(self.read_signed_value(bit_count, 8));
Ok((value & 0xff) as i8)
}
pub fn read_i16(&mut self, bit_count: u8) -> Result<i16> {
let value = try!(self.read_signed_value(bit_count, 16));
Ok((value & 0xffff) as i16)
}
pub fn read_i32(&mut self, bit_count: u8) -> Result<i32> {
let value = try!(self.read_signed_value(bit_count, 32));
Ok((value & 0xffffffff) as i32)
}
pub fn read_i64(&mut self, bit_count: u8) -> Result<i64> {
let value = try!(self.read_signed_value(bit_count, 64));
Ok(value)
}
pub fn read_bool(&mut self) -> Result<bool> {
match try!(self.read_value(1, 1)) {
0 => Ok(false),
_ => Ok(true),
}
}
pub fn skip(&mut self, bit_count: u64) -> Result<()> {
let end_position = self.position + bit_count;
if end_position > self.bytes.len() as u64 * 8 {
return Err(BitReaderError::NotEnoughData {
position: self.position,
length: (self.bytes.len() * 8) as u64,
requested: bit_count,
});
}
self.position = end_position;
Ok(())
}
pub fn position(&self) -> u64 {
self.position - self.relative_offset
}
pub fn is_aligned(&self, alignment_bytes: u32) -> bool {
self.position % (alignment_bytes as u64 * 8) == 0
}
fn read_signed_value(&mut self, bit_count: u8, maximum_count: u8) -> Result<i64> {
let unsigned = try!(self.read_value(bit_count, maximum_count));
let sign_bit = unsigned >> (bit_count - 1) & 1;
let high_bits = if sign_bit == 1 { -1 } else { 0 };
Ok(high_bits << bit_count | unsigned as i64)
}
fn read_value(&mut self, bit_count: u8, maximum_count: u8) -> Result<u64> {
if bit_count == 0 {
return Ok(0);
}
if bit_count > maximum_count {
return Err(BitReaderError::TooManyBitsForType {
position: self.position,
requested: bit_count,
allowed: maximum_count,
});
}
let start_position = self.position;
let end_position = self.position + bit_count as u64;
if end_position > self.bytes.len() as u64 * 8 {
return Err(BitReaderError::NotEnoughData {
position: self.position,
length: (self.bytes.len() * 8) as u64,
requested: bit_count as u64,
});
}
let mut value: u64 = 0;
for i in start_position..end_position {
let byte_index = (i / 8) as usize;
let byte = self.bytes[byte_index];
let shift = 7 - (i % 8);
let bit = (byte >> shift) as u64 & 1;
value = (value << 1) | bit;
}
self.position = end_position;
Ok(value)
}
}
pub type Result<T> = result::Result<T, BitReaderError>;
#[derive(Debug,PartialEq,Copy,Clone)]
pub enum BitReaderError {
NotEnoughData {
position: u64,
length: u64,
requested: u64,
},
TooManyBitsForType {
position: u64,
requested: u8,
allowed: u8,
}
}
impl Error for BitReaderError {
fn description(&self) -> &str {
match *self {
BitReaderError::NotEnoughData {..} => "Requested more bits than the byte slice has left",
BitReaderError::TooManyBitsForType {..} => "Requested more bits than the requested integer type can hold",
}
}
}
impl fmt::Display for BitReaderError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
BitReaderError::NotEnoughData { position, length, requested } => write!(fmt, "BitReader: Requested {} bits with only {}/{} bits left (position {})", requested, length - position, length, position),
BitReaderError::TooManyBitsForType { position, requested, allowed } => write!(fmt, "BitReader: Requested {} bits while the type can only hold {} (position {})", requested, allowed, position),
}
}
}
pub trait ReadInto
where Self: Sized
{
fn read(reader: &mut BitReader, bits: u8) -> Result<Self>;
}
macro_rules! impl_read_into {
($T:ty, $method:ident) => (
impl ReadInto for $T {
fn read(reader: &mut BitReader, bits: u8) -> Result<Self> {
reader.$method(bits)
}
}
)
}
impl_read_into!(u8, read_u8);
impl_read_into!(u16, read_u16);
impl_read_into!(u32, read_u32);
impl_read_into!(u64, read_u64);
impl_read_into!(i8, read_i8);
impl_read_into!(i16, read_i16);
impl_read_into!(i32, read_i32);
impl_read_into!(i64, read_i64);
impl ReadInto for bool {
fn read(reader: &mut BitReader, bits: u8) -> Result<Self> {
match try!(reader.read_u8(bits)) {
0 => Ok(false),
_ => Ok(true),
}
}
}