mp4san 0.5.3

An MP4 file sanitizer.
Documentation
#![allow(missing_docs)]

use std::mem::size_of;

use bytes::Buf;
use bytes::BufMut;
use mediasan_common::error::WhileParsingType;
use mediasan_common::ResultExt;

use crate::error::Result;

use super::{FourCC, Mp4ValueWriterExt, ParseError};

pub trait Mp4Prim: Sized {
    fn parse<B: Buf>(buf: B) -> Result<Self, ParseError>;
    fn encoded_len() -> u64;
    fn put_buf<B: BufMut>(&self, buf: B);
}

macro_rules! mp4_int {
    ($($ty:ty => ($get_fun:ident, $put_fun:ident)),+ $(,)?) => {
        $(impl Mp4Prim for $ty {
            fn parse<B: Buf>(mut buf: B) -> Result<Self, ParseError> {
                if buf.remaining() < Self::encoded_len() as usize {
                    bail_attach!(ParseError::TruncatedBox, WhileParsingType::new::<$ty>());
                }
                Ok(buf.$get_fun())
            }

            fn encoded_len() -> u64 {
                size_of::<Self>() as u64
            }

            fn put_buf<B: BufMut>(&self, mut buf: B) {
                buf.$put_fun(*self)
            }
        })+
    };
}

mp4_int! {
    u8 => (get_u8, put_u8),
    u16 => (get_u16, put_u16),
    u32 => (get_u32, put_u32),
    u64 => (get_u64, put_u64),
    i8 => (get_i8, put_i8),
    i16 => (get_i16, put_i16),
    i32 => (get_i32, put_i32),
    i64 => (get_i64, put_i64),
}

impl<T: Mp4Prim, const N: usize> Mp4Prim for [T; N] {
    fn parse<B: Buf>(mut buf: B) -> Result<Self, ParseError> {
        ensure_attach!(
            buf.remaining() >= Self::encoded_len() as usize,
            ParseError::TruncatedBox,
            WhileParsingType::new::<Self>(),
        );
        Ok([(); N].map(|()| T::parse(&mut buf).unwrap_or_else(|_| unreachable!())))
    }

    fn encoded_len() -> u64 {
        size_of::<Self>() as u64
    }

    fn put_buf<B: BufMut>(&self, mut buf: B) {
        for value in self {
            buf.put_mp4_value(value);
        }
    }
}

impl Mp4Prim for FourCC {
    fn parse<B: Buf>(buf: B) -> Result<Self, ParseError> {
        Mp4Prim::parse(buf).map(|value| Self { value }).while_parsing_type()
    }

    fn encoded_len() -> u64 {
        Self::size()
    }

    fn put_buf<B: BufMut>(&self, mut buf: B) {
        buf.put_mp4_value(&self.value);
    }
}