use crate::{
parser::{take, take_n, Parser, Propagate},
AmlContext,
AmlError,
};
use bit_field::BitField;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PkgLength {
pub raw_length: u32,
pub end_offset: u32,
}
impl PkgLength {
pub fn from_raw_length(stream: &[u8], raw_length: u32) -> Result<PkgLength, AmlError> {
Ok(PkgLength {
raw_length,
end_offset: (stream.len() as u32).checked_sub(raw_length).ok_or(AmlError::InvalidPkgLength)?,
})
}
pub fn still_parsing(&self, stream: &[u8]) -> bool {
stream.len() as u32 > self.end_offset
}
}
pub fn pkg_length<'a, 'c>() -> impl Parser<'a, 'c, PkgLength>
where
'c: 'a,
{
move |input: &'a [u8], context: &'c mut AmlContext| -> crate::parser::ParseResult<'a, 'c, PkgLength> {
let (new_input, context, raw_length) = raw_pkg_length().parse(input, context)?;
match PkgLength::from_raw_length(input, raw_length) {
Ok(pkg_length) => Ok((new_input, context, pkg_length)),
Err(err) => Err((input, context, Propagate::Err(err))),
}
}
}
pub fn raw_pkg_length<'a, 'c>() -> impl Parser<'a, 'c, u32>
where
'c: 'a,
{
move |input: &'a [u8], context: &'c mut AmlContext| {
let (new_input, context, lead_byte) = take().parse(input, context)?;
let byte_count = lead_byte.get_bits(6..8);
if byte_count == 0 {
let length = u32::from(lead_byte.get_bits(0..6));
return Ok((new_input, context, length));
}
let (new_input, context, length): (&[u8], &mut AmlContext, u32) = match take_n(byte_count as u32)
.parse(new_input, context)
{
Ok((new_input, context, bytes)) => {
let initial_length = u32::from(lead_byte.get_bits(0..4));
(
new_input,
context,
bytes
.iter()
.enumerate()
.fold(initial_length, |length, (i, &byte)| length + (u32::from(byte) << (4 + i * 8))),
)
}
Err((_, context, _)) => return Err((input, context, Propagate::Err(AmlError::UnexpectedEndOfStream))),
};
Ok((new_input, context, length))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{test_utils::*, AmlError};
fn test_correct_pkglength(stream: &[u8], expected_raw_length: u32, expected_leftover: &[u8]) {
let mut context = make_test_context();
check_ok!(
pkg_length().parse(stream, &mut context),
PkgLength::from_raw_length(stream, expected_raw_length).unwrap(),
&expected_leftover
);
}
#[test]
fn test_raw_pkg_length() {
let mut context = make_test_context();
check_ok!(raw_pkg_length().parse(&[0b01000101, 0x14], &mut context), 325, &[]);
check_ok!(raw_pkg_length().parse(&[0b01000111, 0x14, 0x46], &mut context), 327, &[0x46]);
check_ok!(raw_pkg_length().parse(&[0b10000111, 0x14, 0x46], &mut context), 287047, &[]);
}
#[test]
fn test_pkg_length() {
let mut context = make_test_context();
check_err!(pkg_length().parse(&[], &mut context), AmlError::UnexpectedEndOfStream, &[]);
test_correct_pkglength(&[0x00], 0, &[]);
test_correct_pkglength(&[0x05, 0xf5, 0x7f, 0x3e, 0x54, 0x03], 5, &[0xf5, 0x7f, 0x3e, 0x54, 0x03]);
check_ok!(
pkg_length()
.feed(|length| crate::parser::take_to_end_of_pkglength(length))
.parse(&[0x05, 0x01, 0x02, 0x03, 0x04, 0xff, 0xff, 0xff], &mut context),
&[0x01, 0x02, 0x03, 0x04],
&[0xff, 0xff, 0xff]
);
}
#[test]
fn not_enough_pkglength() {
let mut context = make_test_context();
check_err!(
pkg_length().parse(&[0b11000000, 0xff, 0x4f], &mut context),
AmlError::UnexpectedEndOfStream,
&[0b11000000, 0xff, 0x4f]
);
}
#[test]
fn not_enough_stream() {
let mut context = make_test_context();
check_err!(pkg_length().parse(&[0x05, 0xf5], &mut context), AmlError::InvalidPkgLength, &[0x05, 0xf5]);
}
}