111 lines
3.3 KiB
Rust
111 lines
3.3 KiB
Rust
//! Bit streams.
|
|
|
|
use crate::durandal::err::*;
|
|
|
|
/// Reads `width` bits from `b` starting at bit `cr_ptr` into an integer.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// The function will return an error if `width` is 0 or more than 64, or if
|
|
/// `(cr_ptr + width - 1) / 8` would overflow an index into `b`.
|
|
pub fn read_bits(b: &[u8], cr_ptr: usize, width: u8) -> ResultS<(usize, u64)>
|
|
{
|
|
if width < 1 || width > 64 {
|
|
bail!("invalid number of bits");
|
|
}
|
|
|
|
let nx_ptr = cr_ptr + usize::from(width);
|
|
let ed_ptr = nx_ptr - 1;
|
|
|
|
let first_byte = cr_ptr / 8;
|
|
let last_byte = ed_ptr / 8;
|
|
|
|
if b.len() <= last_byte {
|
|
bail!("not enough data");
|
|
}
|
|
|
|
let first_bits = cr_ptr as u32 % 8;
|
|
let last_bits = nx_ptr as u32 % 8;
|
|
|
|
let last_mask = ((1_u128 << last_bits) - 1) as u64;
|
|
|
|
let num_bytes = last_byte - first_byte;
|
|
|
|
let bytes = get_bytes(b, num_bytes, first_byte);
|
|
|
|
let bits = u64::from_be_bytes(bytes);
|
|
let bits = bits.wrapping_shl(first_bits);
|
|
let bits = bits >> (64 - width);
|
|
|
|
// special case for over byte boundary
|
|
let bits = if num_bytes == 8 {
|
|
let lbyt = u64::from(b[last_byte]);
|
|
let lbyt = lbyt >> (8 - last_bits);
|
|
let lbyt = lbyt & last_mask;
|
|
|
|
(bits & !last_mask) | lbyt
|
|
} else {
|
|
bits
|
|
};
|
|
|
|
Ok((nx_ptr, bits))
|
|
}
|
|
|
|
fn get_bytes(b: &[u8], num_bytes: usize, f: usize) -> [u8; 8]
|
|
{
|
|
match num_bytes {
|
|
8 |
|
|
7 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], b[f+5], b[f+6], b[f+7]],
|
|
6 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], b[f+5], b[f+6], 0],
|
|
5 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], b[f+5], 0, 0],
|
|
4 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], 0, 0, 0],
|
|
3 => [b[f], b[f+1], b[f+2], b[f+3], 0, 0, 0, 0],
|
|
2 => [b[f], b[f+1], b[f+2], 0, 0, 0, 0, 0],
|
|
1 => [b[f], b[f+1], 0, 0, 0, 0, 0, 0],
|
|
0 => [b[f], 0, 0, 0, 0, 0, 0, 0],
|
|
_ => panic!("invalid number of bytes to read ({})", num_bytes),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn bit_tests()
|
|
{
|
|
const INPUT: &[u8] = &[0b011_00101, 0b10101010, 0b00010000, 0b00000000,
|
|
0b11111111, 0b11100001, 0b10101100, 0b00110011,
|
|
0b10_1001_01, 0b11100_000, 0b00000111, 0b000000_01,
|
|
0b11001010, 0b10101111, 0b00101011, 0b0_1101010,
|
|
0b11010101, 0b10100011, 0b01010101, 0b11_000001];
|
|
|
|
let (p, n) = read_bits(INPUT, 0, 3).unwrap();
|
|
assert_eq!(n, 0b011);
|
|
|
|
let (p, n) = read_bits(INPUT, p, 63).unwrap();
|
|
assert_eq!(n, 0x16A8_4003_FF86_B0CE);
|
|
|
|
let (p, n) = read_bits(INPUT, p, 4).unwrap();
|
|
assert_eq!(n, 0b1001);
|
|
|
|
let (p, n) = read_bits(INPUT, p, 7).unwrap();
|
|
assert_eq!(n, 0b0111100);
|
|
|
|
let (p, n) = read_bits(INPUT, p, 17).unwrap();
|
|
assert_eq!(n, 0b00000000111000000);
|
|
|
|
let (p, n) = read_bits(INPUT, p, 27).unwrap();
|
|
assert_eq!(n, 0b011100101010101111001010110);
|
|
|
|
let (p, n) = read_bits(INPUT, p, 33).unwrap();
|
|
assert_eq!(n, 0b110101011010101101000110101010111);
|
|
|
|
let (p, n) = read_bits(INPUT, p, 6).unwrap();
|
|
assert_eq!(n, 1);
|
|
|
|
let e = read_bits(INPUT, p, 1);
|
|
assert!(if let Err(_) = e {true} else {false});
|
|
|
|
let e = read_bits(INPUT, p, 2);
|
|
assert!(if let Err(_) = e {true} else {false});
|
|
}
|
|
|
|
// EOF
|