use winnow::{Parser, error::EmptyError, token::take};
use crate::providers::shared::bmff::{BoxSize, BoxType, heif::iinf::FullBox};
pub fn find_meta_boxes<'borrow, 'types, 'input: 'borrow>(
input: &'borrow mut &'input [u8],
) -> Vec<(FullBox, &'input [u8])> {
let mut boxes: Vec<(FullBox, &[u8])> = Vec::new();
while !input.is_empty() {
let Ok(full_box) = FullBox::new(input)
.inspect_err(|e| log::warn!("Failed to construct box header from input. err: {e}"))
else {
break;
};
log::trace!("Found full box w/ type: {:?}", full_box.extends.box_type);
const fn fullbox_header_len(sz: &BoxSize) -> usize {
match sz {
BoxSize::Small(_) => 8 + 4,
BoxSize::Large(_) => 16 + 4,
BoxSize::Eof => 12,
}
}
if full_box.extends.box_type == BoxType::Id(*b"meta") {
let header_len = fullbox_header_len(&full_box.extends.box_size);
let payload_size = match full_box.extends.box_size {
BoxSize::Small(s) => s.saturating_sub(header_len as u32) as usize,
BoxSize::Large(l) => {
(l.saturating_sub(header_len as u64) as usize).min(input.len())
}
BoxSize::Eof => input.len(),
};
if payload_size > input.len() {
log::warn!("Box payload size exceeds remaining input! Skipping...");
break;
}
let payload = &input[..payload_size];
boxes.push((full_box, payload));
} else {
let header_len = fullbox_header_len(&full_box.extends.box_size);
let skip_amount = match full_box.extends.box_size {
BoxSize::Small(s) => s.saturating_sub(header_len as u32) as usize,
BoxSize::Large(l) => {
(l.saturating_sub(header_len as u64) as usize).min(input.len())
}
BoxSize::Eof => input.len(),
};
let skip_res = take::<_, _, EmptyError>(skip_amount).parse_next(input);
if cfg!(debug_assertions) {
skip_res.expect("skipping should never fail");
}
}
}
boxes
}