use crate::bytes::{Cur, varint64};
const GROUPS: u8 = 0x1f;
const LAST: u8 = 0x80;
const MOD_EXPLICIT: u8 = 7;
const ITEM_LAST: u64 = 1;
const ITEM_RANGE: u64 = 2;
pub(crate) fn valid(entry: &[u8]) -> bool {
walk(entry).is_some()
}
fn walk(entry: &[u8]) -> Option<()> {
let mut c = Cur::new(entry, 0);
while !c.at_end() {
let rule = c.u8()?;
if rule >> 5 > 4 || rule & GROUPS == 0 {
return None;
}
for _ in 0..rule & GROUPS {
loop {
let rel = c.u8()?;
if rel & 7 == 7 {
return None;
}
if (rel >> 3) & 7 == MOD_EXPLICIT && varint64(&mut c)? == 0 {
return None;
}
loop {
let item = varint64(&mut c)?;
if item & ITEM_RANGE != 0 {
let d = varint64(&mut c)?;
if d == 0 {
return None;
}
(item >> 2).checked_add(d)?;
}
if item & ITEM_LAST != 0 {
break;
}
}
if rel & LAST != 0 {
break;
}
}
}
}
Some(())
}
#[cfg(test)]
mod tests {
use super::valid;
#[test]
fn entries() {
assert!(valid(&[0x21, 0x01, 0x05, 0x82, 0x01]));
assert!(valid(&[]));
let en = [0x21, 0x01, 0x05, 0x82, 0x01];
for len in 1..5 {
assert!(!valid(en.get(..len).unwrap_or(&[0xff])));
}
assert!(!valid(&[0x20])); assert!(!valid(&[0xa1, 0x81, 0x01])); assert!(!valid(&[0x21, 0x87, 0x01])); assert!(!valid(&[0x21, 0xb9, 0x00, 0x01])); assert!(!valid(&[0x21, 0x81, 0x03, 0x00])); assert!(valid(&[0x21, 0x81, 0x07, 0x05])); }
}