use anyhow::{bail, Result}; use std::io::{Read, Seek}; use crate::matroska::MatroskaTag; trait ReadAndSeek: Read + Seek {} impl ReadAndSeek for T {} pub struct EbmlReader { inner: Box, pub position: usize, } pub trait EbmlRead: Sized { fn read(r: &mut EbmlReader) -> Result; } impl EbmlReader { pub fn new(inner: T) -> Self { Self { inner: Box::new(inner), position: 0, } } pub fn read_byte(&mut self) -> Result { let mut b = [0u8]; self.inner.read_exact(&mut b)?; self.position += 1; Ok(b[0]) } pub fn read_buf(&mut self, size: impl Into) -> Result> { let size = size.into(); let mut b = vec![0u8; size]; self.inner.read_exact(&mut b)?; self.position += size; Ok(b) } pub fn read_vint_len(&mut self) -> Result<(u64, usize)> { let s = self.read_byte()?; let len = s.leading_zeros() + 1; if len > 8 { bail!("varint too long"); } let mut value = s as u64; value -= 1 << (8 - len); for _ in 1..len { value <<= 8; value += self.read_byte()? as u64; } Ok((value, len as usize)) } pub fn read_vint(&mut self) -> Result { Ok(self.read_vint_len()?.0) } pub fn read_utf8(&mut self, size: impl Into) -> Result { let b = self.read_buf(size)?; Ok(String::from_utf8(b)?) } pub fn read_tag_id(&mut self) -> Result { let (value, len) = self.read_vint_len()?; Ok(value + (1 << (7 * len))) } pub fn read_tag_size(&mut self) -> Result { Ok(EbmlSize::from_vint(self.read_vint_len()?)) } pub fn read_tag(&mut self) -> Result { let id = self.read_tag_id()?; let size = self.read_tag_size()?; if MatroskaTag::is_master(id)? { Ok(MatroskaTag::parse(id, &[])?) } else { let data = self.read_buf(size)?; Ok(MatroskaTag::parse(id, &data)?) } } } #[derive(Debug, Clone, Copy)] pub enum EbmlSize { Exact(usize), Unknown, } impl EbmlSize { pub fn from_vint((value, len): (u64, usize)) -> EbmlSize { if value == ((1 << (7 * len)) - 1) { Self::Unknown } else { Self::Exact(value as usize) } } } impl Into for EbmlSize { fn into(self) -> usize { match self { EbmlSize::Exact(s) => s, EbmlSize::Unknown => panic!("unknown size, where it should have been known"), } } }