use gamut_core::{Error, Result};
pub(crate) struct BoxBuilder {
buf: Vec<u8>,
}
impl BoxBuilder {
pub(crate) fn new() -> Self {
Self { buf: Vec::new() }
}
pub(crate) fn begin_box(&mut self, box_type: &[u8; 4]) -> usize {
let start = self.buf.len();
self.buf.extend_from_slice(&[0, 0, 0, 0]);
self.buf.extend_from_slice(box_type);
start
}
pub(crate) fn end_box(&mut self, start: usize) {
let size = (self.buf.len() - start) as u32;
self.buf[start..start + 4].copy_from_slice(&size.to_be_bytes());
}
pub(crate) fn full_box(&mut self, version: u8, flags: u32) {
self.buf.push(version);
self.buf.extend_from_slice(&flags.to_be_bytes()[1..]);
}
pub(crate) fn u8(&mut self, value: u8) {
self.buf.push(value);
}
pub(crate) fn u16(&mut self, value: u16) {
self.buf.extend_from_slice(&value.to_be_bytes());
}
pub(crate) fn u32(&mut self, value: u32) {
self.buf.extend_from_slice(&value.to_be_bytes());
}
pub(crate) fn bytes(&mut self, data: &[u8]) {
self.buf.extend_from_slice(data);
}
pub(crate) fn reserve_u32(&mut self) -> usize {
let pos = self.buf.len();
self.buf.extend_from_slice(&[0, 0, 0, 0]);
pos
}
pub(crate) fn patch_u32(&mut self, pos: usize, value: u32) {
self.buf[pos..pos + 4].copy_from_slice(&value.to_be_bytes());
}
pub(crate) fn len(&self) -> usize {
self.buf.len()
}
pub(crate) fn into_vec(self) -> Vec<u8> {
self.buf
}
}
pub(crate) struct BoxReader<'a> {
data: &'a [u8],
pos: usize,
}
pub(crate) struct RawBox<'a> {
pub(crate) ty: [u8; 4],
pub(crate) body: &'a [u8],
}
impl<'a> BoxReader<'a> {
pub(crate) fn new(data: &'a [u8]) -> Self {
Self { data, pos: 0 }
}
pub(crate) fn remaining(&self) -> usize {
self.data.len() - self.pos
}
pub(crate) fn take(&mut self, n: usize) -> Result<&'a [u8]> {
let end = self
.pos
.checked_add(n)
.ok_or(Error::InvalidInput("ISOBMFF: length overflow"))?;
let slice = self
.data
.get(self.pos..end)
.ok_or(Error::InvalidInput("ISOBMFF: unexpected end of box"))?;
self.pos = end;
Ok(slice)
}
pub(crate) fn u8(&mut self) -> Result<u8> {
Ok(self.take(1)?[0])
}
pub(crate) fn u16(&mut self) -> Result<u16> {
let b = self.take(2)?;
Ok(u16::from_be_bytes([b[0], b[1]]))
}
pub(crate) fn u32(&mut self) -> Result<u32> {
let b = self.take(4)?;
Ok(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
}
pub(crate) fn fourcc(&mut self) -> Result<[u8; 4]> {
let b = self.take(4)?;
Ok([b[0], b[1], b[2], b[3]])
}
pub(crate) fn next_box(&mut self) -> Result<Option<RawBox<'a>>> {
if self.remaining() == 0 {
return Ok(None);
}
let size = self.u32()? as usize;
let ty = self.fourcc()?;
match size {
1 => return Err(Error::Unsupported("ISOBMFF: 64-bit box size (largesize)")),
0 => return Err(Error::Unsupported("ISOBMFF: open-ended box (size 0)")),
s if s < 8 => return Err(Error::InvalidInput("ISOBMFF: box size smaller than header")),
_ => {}
}
let body = self.take(size - 8)?;
Ok(Some(RawBox { ty, body }))
}
}