diff --git a/lofty_attr/src/lib.rs b/lofty_attr/src/lib.rs index 9ef55d525..0abc48200 100644 --- a/lofty_attr/src/lib.rs +++ b/lofty_attr/src/lib.rs @@ -134,7 +134,7 @@ pub fn ebml_master_elements(input: TokenStream) -> TokenStream { }); TokenStream::from(quote! { - #[derive(Copy, Clone, Eq, PartialEq)] + #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub(crate) enum ElementIdent { #( #identifiers_iter ),* } diff --git a/src/ebml/read.rs b/src/ebml/read.rs index 513504a54..b1d97909a 100644 --- a/src/ebml/read.rs +++ b/src/ebml/read.rs @@ -1,5 +1,8 @@ +mod segment; + use super::EbmlFile; -use crate::ebml::element_reader::{ElementIdent, ElementReader, ElementReaderYield}; +use crate::ebml::element_reader::{ElementHeader, ElementIdent, ElementReader, ElementReaderYield}; +use crate::ebml::vint::VInt; use crate::ebml::EbmlProperties; use crate::error::Result; use crate::macros::decode_err; @@ -15,35 +18,38 @@ where // new ones all scattered throughout the file let mut properties = EbmlProperties::default(); + let mut ebml_tag = None; + let mut element_reader = ElementReader::new(reader); // First we need to go through the elements in the EBML master element read_ebml_header(&mut element_reader, parse_options, &mut properties)?; loop { - let ident; - let data_ty; - let size; - let res = element_reader.next()?; match res { - ElementReaderYield::Master(_) => continue, - ElementReaderYield::Child((child, size_)) => { - ident = child.ident; - data_ty = child.data_type; - size = size_; + ElementReaderYield::Master((ElementIdent::Segment, _)) => { + ebml_tag = segment::read_from(&mut element_reader, parse_options, &mut properties)?; + break; }, - ElementReaderYield::Unknown(element) => { - log::debug!("Encountered unknown EBML element: {}", element.id.0); - element_reader.skip(element.size.value())?; + // CRC-32 (0xBF) and Void (0xEC) elements can occur at the top level. + // This is valid, and we can just skip them. + ElementReaderYield::Unknown(ElementHeader { + id: VInt(id @ (0xBF | 0xEC)), + size, + }) => { + log::debug!("Skipping global element: {:X}", id); + element_reader.skip(size.value())?; continue; }, - ElementReaderYield::Eof => break, + _ => { + decode_err!(@BAIL Ebml, "File does not contain a segment element") + }, } } Ok(EbmlFile { - ebml_tag: None, + ebml_tag, properties, }) } @@ -78,7 +84,7 @@ where }, ElementReaderYield::Unknown(element) => { log::debug!( - "Encountered unknown EBML element in header: {}", + "Encountered unknown EBML element in header: {:X}", element.id.0 ); element_reader.skip(element.size.value())?; diff --git a/src/ebml/read/segment.rs b/src/ebml/read/segment.rs new file mode 100644 index 000000000..04e56618e --- /dev/null +++ b/src/ebml/read/segment.rs @@ -0,0 +1,58 @@ +use crate::ebml::element_reader::{ElementIdent, ElementReader, ElementReaderYield}; +use crate::ebml::properties::EbmlProperties; +use crate::ebml::tag::EbmlTag; +use crate::error::Result; +use crate::macros::decode_err; +use crate::probe::ParseOptions; + +use std::io::{Read, Seek}; + +pub(super) fn read_from( + element_reader: &mut ElementReader, + _parse_options: ParseOptions, + _properties: &mut EbmlProperties, +) -> Result> +where + R: Read + Seek, +{ + element_reader.lock(); + + let mut tags = None; + + loop { + let res = element_reader.next()?; + match res { + ElementReaderYield::Master((id, size)) => match id { + ElementIdent::Info => todo!("Support segment.Info"), + ElementIdent::Cluster => todo!("Support segment.Cluster"), + ElementIdent::Tracks => todo!("Support segment.Tracks"), + ElementIdent::Tags => todo!("Support segment.Tags"), + ElementIdent::Attachments => todo!("Support segment.Attachments"), + ElementIdent::Chapters => todo!("Support segment.Chapters"), + _ => { + // We do not end up using information from all of the segment + // elements, so we can just skip any useless ones. + + log::debug!("Skipping EBML master element: {:?}", id); + element_reader.skip(size)?; + element_reader.goto_previous_master()?; + continue; + }, + }, + ElementReaderYield::Unknown(element) => { + log::debug!("Skipping unknown EBML element: {:X}", element.id.0); + element_reader.skip(element.size.value())?; + continue; + }, + ElementReaderYield::Eof => { + element_reader.unlock(); + break; + }, + _ => { + decode_err!(@BAIL Ebml, "Segment element should only contain master elements") + }, + } + } + + Ok(tags) +}