use nom::{
error::{make_error, ErrorKind, ParseError},
Err, IResult, Needed,
};
pub fn be_u7<'a, E>(i: &'a [u8]) -> IResult<&'a [u8], u8, E>
where
E: ParseError<&'a [u8]>,
{
if i.is_empty() {
Result::Err(Err::Incomplete(Needed::Size(1)))
} else {
let val = i[0];
if val > 127 {
Err(Err::Error(make_error(i, ErrorKind::TooLarge)))
} else {
Ok((&i[1..], val))
}
}
}
pub fn parse_var_length<'a, E>(i: &'a [u8]) -> IResult<&'a [u8], u32, E>
where
E: ParseError<&'a [u8]>,
{
let mut pos = 0;
let mut value = 0u32;
if i.is_empty() {
return Err(Err::Incomplete(Needed::Unknown));
}
while i[pos] & 0x80 > 0 {
value = (value << 7) | (i[pos] as u32) & 0x7F;
pos = pos + 1;
if pos >= 4 {
return Err(Err::Error(make_error(i, ErrorKind::TooLarge)));
}
if i.len() <= pos {
return Err(Err::Incomplete(Needed::Unknown));
}
}
value = (value << 7) | (i[pos] as u32);
Ok((&i[pos + 1..], value))
}
pub fn parse_var_length_bytes<'a, E>(i: &'a [u8]) -> IResult<&'a [u8], &'a [u8], E>
where
E: ParseError<&'a [u8]>,
{
use nom::bytes::streaming::take;
let (i, size) = parse_var_length(i)?;
take(size)(i)
}
#[test]
fn test_var_length() {
let length = [0x7F];
assert_eq!(
parse_var_length::<(&[u8], ErrorKind)>(&length[..]),
Ok((&b""[..], 0x7F))
);
let length = [0x81, 0x7F];
assert_eq!(
parse_var_length::<(&[u8], ErrorKind)>(&length[..]),
Ok((&b""[..], 0xFF))
);
let length = [0x82, 0x80, 0x00];
assert_eq!(
parse_var_length::<(&[u8], ErrorKind)>(&length[..]),
Ok((&b""[..], 0x8000))
);
let length = [0x82, 0x80, 0x80, 0x80];
assert_eq!(
parse_var_length::<(&[u8], ErrorKind)>(&length[..]),
Err(Err::Error(make_error(&length[..], ErrorKind::TooLarge)))
);
}
#[test]
fn test_data_bytes() {
let data = [0x04, b'c', b'h', b'a', b'r', b's'];
assert_eq!(
parse_var_length_bytes::<(&[u8], ErrorKind)>(&data[..]),
Ok((&b"s"[..], &b"char"[..]))
);
}