use std::io::{Error, Result, Seek, SeekFrom, Write};
use crate::BoxType;
const MAX_32BIT_PAYLOAD_SIZE: usize = 0xfffffff7;
pub trait ToBox {
fn box_type(&self) -> BoxType;
fn payload_size(&self) -> Result<usize> {
let mut counting_sink = CountingSink::default();
self.write_payload(&mut counting_sink)?;
counting_sink.flush()?;
Ok(counting_sink.count)
}
fn write_payload(&self, to_stream: &mut dyn WriteAndSeek) -> Result<()>;
}
pub(crate) fn jumbf_size(boxx: &dyn ToBox) -> Result<usize> {
Ok(jumbf_size_from_payload_size(boxx.payload_size()?))
}
pub(crate) fn write_jumbf(boxx: &dyn ToBox, to_stream: &mut dyn WriteAndSeek) -> Result<()> {
let payload_size = boxx.payload_size()?;
let jumbf_size = jumbf_size_from_payload_size(payload_size);
if payload_size <= MAX_32BIT_PAYLOAD_SIZE {
let size_slice: [u8; 4] = [
(jumbf_size >> 24) as u8,
(jumbf_size >> 16) as u8,
(jumbf_size >> 8) as u8,
jumbf_size as u8,
];
to_stream.write_all(&size_slice)?;
} else {
unimplemented!();
}
let box_type = boxx.box_type();
to_stream.write_all(&box_type.0)?;
boxx.write_payload(to_stream)?;
Ok(())
}
fn jumbf_size_from_payload_size(payload_size: usize) -> usize {
if payload_size <= MAX_32BIT_PAYLOAD_SIZE {
payload_size + 8
} else {
unimplemented!();
}
}
pub trait WriteAndSeek: Write + Seek {}
impl<T: Write + Seek> WriteAndSeek for T {}
#[derive(Default)]
struct CountingSink {
count: usize,
}
impl Seek for CountingSink {
fn seek(&mut self, _pos: SeekFrom) -> Result<u64> {
Err(Error::other(
"shouldn't need to seek while calculating payload size",
))
}
}
impl Write for CountingSink {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let len = buf.len();
self.count += len;
Ok(len)
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}