use anyhow::Result;
pub mod mmap;
pub use mmap::MmapMosaicBackend;
use crate::{
ebml::{crc32, MosaicTag, CRC32_SIZE},
reader::MosaicReaderError,
Position, Size,
};
pub trait MosaicBackend: Send + Sync {
fn find_tag_and_size(&self, mut offset: Position) -> Result<(MosaicTag, Size, Position)> {
loop {
let (tag, size, element_start) = self.read_one_tag_and_size(offset)?;
if tag == MosaicTag::Void {
offset = element_start + size;
} else {
return Ok((tag, size, element_start));
}
}
}
fn read_one_tag_and_size(&self, offset: Position) -> Result<(MosaicTag, Size, Position)>;
fn find_element_pre(
&self,
offset: Position,
element_tag: MosaicTag,
) -> Result<(Position, Size, Position)> {
if offset >= self.len() {
return Err(MosaicReaderError::ElementNotFound { tag: element_tag }.into());
}
let mut tag_offset = offset;
let (mut tag, mut size, mut offset) = self.find_tag_and_size(offset)?;
let mut element_size = size;
let mut element_offset = offset;
loop {
if tag != element_tag {
offset += size;
if offset >= self.len() {
return Err(MosaicReaderError::ElementNotFound { tag: element_tag }.into());
}
tag_offset = offset;
(tag, size, offset) = self.find_tag_and_size(offset)?;
element_size = size;
element_offset = offset;
} else {
return Ok((tag_offset, element_size, element_offset));
}
}
}
fn find_element(&self, offset: Position, element_tag: MosaicTag) -> Result<(Size, Position)> {
let (_, element_size, element_offset) = self.find_element_pre(offset, element_tag)?;
Ok((element_size, element_offset))
}
fn find_and_check(&self, offset: Position, master_tag: MosaicTag) -> Result<(Size, Position)> {
if !master_tag.is_master() {
panic!("{master_tag} is not a master element, try using MosaicReader::find_element() instead")
}
let (mut size, mut offset) = self.find_element(offset, master_tag)?;
let (crc32_tag, crc32_size, next_offset) = self.find_tag_and_size(offset)?;
if crc32_tag != MosaicTag::Crc32 {
return Err(MosaicReaderError::MissingChecksum { tag: master_tag }.into());
};
size -= CRC32_SIZE;
let (crc32_raw, next_offset) = self.read_binary(next_offset, crc32_size)?;
let crc32_actual = crc32_raw.to_vec();
let crc32_data = &self.read_binary(next_offset, size)?.0;
let crc32_expected = crc32(crc32_data);
if crc32_actual != crc32_expected {
return Err(MosaicReaderError::BadChecksum { tag: master_tag }.into());
};
offset = next_offset;
Ok((size, offset))
}
fn read_binary(&self, offset: Position, size: Size) -> Result<(&[u8], Position)>;
fn read_u8(&self, offset: Position) -> Result<(u8, Position)>;
fn read_uint(&self, offset: Position, size: Size) -> Result<(u64, Position)>;
fn read_utf8(&self, offset: Position, size: Size) -> Result<(String, Position)>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
}