use pallas_codec::minicbor::{Decoder, data::Type};
pub const MAX_DEPTH: usize = 128;
pub fn within_depth(cbor: &[u8], max: usize) -> bool {
walk(cbor, max).is_some()
}
fn walk(cbor: &[u8], max: usize) -> Option<()> {
let mut d = Decoder::new(cbor);
let mut open: Vec<Option<u64>> = Vec::new();
loop {
let opens: Option<Option<u64>> = match d.datatype().ok()? {
Type::Array | Type::ArrayIndef => Some(d.array().ok()?),
Type::Map | Type::MapIndef => Some(match d.map().ok()? {
Some(pairs) => Some(pairs.checked_mul(2)?),
None => None,
}),
Type::Tag => {
d.tag().ok()?;
Some(Some(1))
}
Type::Break => {
if open.pop()?.is_some() {
return None;
}
d.set_position(d.position() + 1);
None
}
Type::Unknown(_) => return None,
_ => {
d.skip().ok()?;
None
}
};
if let Some(items) = opens {
if open.len() == max {
return None;
}
if items != Some(0) {
open.push(items);
continue;
}
}
loop {
match open.last_mut() {
None => return (d.position() == cbor.len()).then_some(()),
Some(None) => break,
Some(Some(left)) => {
*left -= 1;
if *left > 0 {
break;
}
open.pop();
}
}
}
}
}