mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-12-12 13:42:34 +00:00
EBML: Start parsing \Ebml\Segments\Tracks
This commit is contained in:
parent
9f1d6325a3
commit
10c3e30ae8
8 changed files with 158 additions and 47 deletions
|
@ -169,11 +169,11 @@ ebml_master_elements! {
|
|||
struct ElementReaderContext {
|
||||
/// Previous master element
|
||||
previous_master: Option<MasterElement>,
|
||||
previous_master_length: u64,
|
||||
previous_master_length: VInt,
|
||||
/// Current master element
|
||||
current_master: Option<MasterElement>,
|
||||
/// Remaining length of the master element
|
||||
master_length: u64,
|
||||
master_length: VInt,
|
||||
/// Maximum size in octets of all element IDs
|
||||
max_id_length: u8,
|
||||
/// Maximum size in octets of all element data sizes
|
||||
|
@ -189,9 +189,9 @@ impl Default for ElementReaderContext {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
previous_master: None,
|
||||
previous_master_length: 0,
|
||||
previous_master_length: VInt::ZERO,
|
||||
current_master: None,
|
||||
master_length: 0,
|
||||
master_length: VInt::ZERO,
|
||||
// https://www.rfc-editor.org/rfc/rfc8794.html#name-ebmlmaxidlength-element
|
||||
max_id_length: 4,
|
||||
// https://www.rfc-editor.org/rfc/rfc8794.html#name-ebmlmaxsizelength-element
|
||||
|
@ -202,12 +202,32 @@ impl Default for ElementReaderContext {
|
|||
}
|
||||
|
||||
pub(crate) enum ElementReaderYield {
|
||||
Master((ElementIdent, u64)),
|
||||
Child((ChildElementDescriptor, u64)),
|
||||
Master((ElementIdent, VInt)),
|
||||
Child((ChildElementDescriptor, VInt)),
|
||||
Unknown(ElementHeader),
|
||||
Eof,
|
||||
}
|
||||
|
||||
impl ElementReaderYield {
|
||||
pub fn ident(&self) -> Option<u64> {
|
||||
match self {
|
||||
ElementReaderYield::Master((ident, _)) => Some(*ident as u64),
|
||||
ElementReaderYield::Child((child, _)) => Some(child.ident as u64),
|
||||
ElementReaderYield::Unknown(header) => Some(header.id.value()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Option<u64> {
|
||||
match self {
|
||||
ElementReaderYield::Master((_, size)) => Some(size.value()),
|
||||
ElementReaderYield::Child((_, size)) => Some(size.value()),
|
||||
ElementReaderYield::Unknown(header) => Some(header.size.value()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ElementReader<R> {
|
||||
reader: R,
|
||||
ctx: ElementReaderContext,
|
||||
|
@ -250,7 +270,7 @@ where
|
|||
|
||||
fn goto_next_master(&mut self) -> Result<ElementReaderYield> {
|
||||
if self.ctx.master_length != 0 {
|
||||
self.skip(self.ctx.master_length)?;
|
||||
self.skip(self.ctx.master_length.value())?;
|
||||
}
|
||||
|
||||
let header = ElementHeader::read(
|
||||
|
@ -265,7 +285,7 @@ where
|
|||
|
||||
self.store_previous_master();
|
||||
self.ctx.current_master = Some(*master);
|
||||
self.ctx.master_length = header.size.value();
|
||||
self.ctx.master_length = header.size;
|
||||
Ok(ElementReaderYield::Master((
|
||||
master.id,
|
||||
self.ctx.master_length,
|
||||
|
@ -312,16 +332,13 @@ where
|
|||
.get(&header.id)
|
||||
.expect("Nested master elements should be defined at this level."),
|
||||
);
|
||||
self.ctx.master_length = header.size.value();
|
||||
self.ctx.master_length = header.size;
|
||||
|
||||
// We encountered a nested master element
|
||||
return Ok(ElementReaderYield::Master((
|
||||
child.ident,
|
||||
header.size.value(),
|
||||
)));
|
||||
return Ok(ElementReaderYield::Master((child.ident, header.size)));
|
||||
}
|
||||
|
||||
Ok(ElementReaderYield::Child((*child, header.size.value())))
|
||||
Ok(ElementReaderYield::Child((*child, header.size)))
|
||||
}
|
||||
|
||||
fn lock(&mut self) {
|
||||
|
|
|
@ -92,13 +92,13 @@ where
|
|||
}
|
||||
|
||||
if ident == ElementIdent::EBMLMaxIDLength {
|
||||
properties.header.max_id_length = child_reader.read_unsigned_int(size)? as u8;
|
||||
properties.header.max_id_length = child_reader.read_unsigned_int(size.value())? as u8;
|
||||
child_reader.set_max_id_length(properties.header.max_id_length);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ident == ElementIdent::EBMLMaxSizeLength {
|
||||
properties.header.max_size_length = child_reader.read_unsigned_int(size)? as u8;
|
||||
properties.header.max_size_length = child_reader.read_unsigned_int(size.value())? as u8;
|
||||
child_reader.set_max_size_length(properties.header.max_size_length);
|
||||
continue;
|
||||
}
|
||||
|
@ -106,22 +106,24 @@ where
|
|||
// Anything else in the header is unnecessary, and only read for the properties
|
||||
// struct
|
||||
if !parse_options.read_properties {
|
||||
child_reader.skip(size)?;
|
||||
child_reader.skip(size.value())?;
|
||||
continue;
|
||||
}
|
||||
|
||||
match ident {
|
||||
ElementIdent::EBMLVersion => {
|
||||
properties.header.version = child_reader.read_unsigned_int(size)?
|
||||
properties.header.version = child_reader.read_unsigned_int(size.value())?
|
||||
},
|
||||
ElementIdent::EBMLReadVersion => {
|
||||
properties.header.read_version = child_reader.read_unsigned_int(size)?
|
||||
properties.header.read_version = child_reader.read_unsigned_int(size.value())?
|
||||
},
|
||||
ElementIdent::DocType => {
|
||||
properties.header.doc_type = child_reader.read_string(size.value())?
|
||||
},
|
||||
ElementIdent::DocType => properties.header.doc_type = child_reader.read_string(size)?,
|
||||
ElementIdent::DocTypeVersion => {
|
||||
properties.header.doc_type_version = child_reader.read_unsigned_int(size)?
|
||||
properties.header.doc_type_version = child_reader.read_unsigned_int(size.value())?
|
||||
},
|
||||
_ => child_reader.skip(size)?,
|
||||
_ => child_reader.skip(size.value())?,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,17 +34,11 @@ where
|
|||
ElementIdent::Tracks if parse_options.read_properties => {
|
||||
segment_tracks::read_from(children_reader.inner(), parse_options, properties)?
|
||||
},
|
||||
ElementIdent::Tags | ElementIdent::Attachments | ElementIdent::Chapters => {
|
||||
ElementIdent::Tags | ElementIdent::Chapters if parse_options.read_tags => {
|
||||
let mut tag = tags.unwrap_or_default();
|
||||
|
||||
if id == ElementIdent::Tags {
|
||||
segment_tags::read_from(children_reader.inner(), parse_options, &mut tag)?
|
||||
} else if id == ElementIdent::Attachments {
|
||||
segment_attachments::read_from(
|
||||
children_reader.inner(),
|
||||
parse_options,
|
||||
&mut tag,
|
||||
)?
|
||||
} else {
|
||||
segment_chapters::read_from(
|
||||
children_reader.inner(),
|
||||
|
@ -55,12 +49,23 @@ where
|
|||
|
||||
tags = Some(tag);
|
||||
},
|
||||
ElementIdent::Attachments if parse_options.read_cover_art => {
|
||||
let mut tag = tags.unwrap_or_default();
|
||||
|
||||
segment_attachments::read_from(
|
||||
children_reader.inner(),
|
||||
parse_options,
|
||||
&mut tag,
|
||||
)?;
|
||||
|
||||
tags = Some(tag);
|
||||
},
|
||||
_ => {
|
||||
// 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);
|
||||
children_reader.skip(size)?;
|
||||
children_reader.skip(size.value())?;
|
||||
children_reader.goto_previous_master()?;
|
||||
continue;
|
||||
},
|
||||
|
|
|
@ -23,7 +23,7 @@ where
|
|||
// elements, so we can just skip them.
|
||||
|
||||
log::debug!("Skipping EBML master element: {:?}", id);
|
||||
children_reader.skip(size)?;
|
||||
children_reader.skip(size.value())?;
|
||||
children_reader.goto_previous_master()?;
|
||||
continue;
|
||||
},
|
||||
|
@ -31,7 +31,7 @@ where
|
|||
match child.ident {
|
||||
ElementIdent::TimecodeScale => {
|
||||
properties.segment_info.timestamp_scale =
|
||||
children_reader.read_unsigned_int(size)?;
|
||||
children_reader.read_unsigned_int(size.value())?;
|
||||
|
||||
if properties.segment_info.timestamp_scale == 0 {
|
||||
log::warn!("Segment.Info.TimecodeScale is 0, which is invalid");
|
||||
|
@ -41,17 +41,19 @@ where
|
|||
}
|
||||
},
|
||||
ElementIdent::MuxingApp => {
|
||||
properties.segment_info.muxing_app = children_reader.read_utf8(size)?
|
||||
properties.segment_info.muxing_app =
|
||||
children_reader.read_utf8(size.value())?
|
||||
},
|
||||
ElementIdent::WritingApp => {
|
||||
properties.segment_info.writing_app = children_reader.read_utf8(size)?
|
||||
properties.segment_info.writing_app =
|
||||
children_reader.read_utf8(size.value())?
|
||||
},
|
||||
_ => {
|
||||
// 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 child element: {:?}", child.ident);
|
||||
children_reader.skip(size)?;
|
||||
children_reader.skip(size.value())?;
|
||||
continue;
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::config::ParseOptions;
|
||||
use crate::ebml::element_reader::{ElementIdent, ElementReader, ElementReaderYield};
|
||||
use crate::ebml::element_reader::{
|
||||
ChildElementDescriptor, ElementHeader, ElementIdent, ElementReader, ElementReaderYield,
|
||||
};
|
||||
use crate::ebml::properties::EbmlProperties;
|
||||
use crate::error::Result;
|
||||
use crate::macros::decode_err;
|
||||
|
@ -7,6 +9,43 @@ use crate::macros::decode_err;
|
|||
use std::io::{Read, Seek};
|
||||
|
||||
pub(super) fn read_from<R>(
|
||||
element_reader: &mut ElementReader<R>,
|
||||
parse_options: ParseOptions,
|
||||
properties: &mut EbmlProperties,
|
||||
) -> Result<()>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
let mut children_reader = element_reader.children();
|
||||
|
||||
while let Some(child) = children_reader.next()? {
|
||||
match child {
|
||||
ElementReaderYield::Master((ElementIdent::TrackEntry, size)) => {
|
||||
read_track_entry(children_reader.inner(), parse_options, properties)?;
|
||||
},
|
||||
ElementReaderYield::Eof => {
|
||||
break;
|
||||
},
|
||||
_ => {
|
||||
let id = child
|
||||
.ident()
|
||||
.expect("Child element must have an identifier");
|
||||
let size = child.size().expect("Child element must have a size");
|
||||
|
||||
log::warn!(
|
||||
"Unexpected child element in \\EBML\\Segment\\Tracks: {:?}, skipping",
|
||||
id
|
||||
);
|
||||
children_reader.skip(size)?;
|
||||
continue;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_track_entry<R>(
|
||||
_element_reader: &mut ElementReader<R>,
|
||||
_parse_options: ParseOptions,
|
||||
_properties: &mut EbmlProperties,
|
||||
|
@ -14,5 +53,5 @@ pub(super) fn read_from<R>(
|
|||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
unimplemented!("\\Ebml\\Segment\\Tracks")
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::error::Result;
|
|||
use crate::macros::err;
|
||||
|
||||
use std::io::Read;
|
||||
use std::ops::{Add, Sub};
|
||||
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||
|
||||
|
@ -20,7 +21,12 @@ impl VInt {
|
|||
const MAX_OCTET_LENGTH: u64 = 8;
|
||||
const USABLE_BITS: u64 = Self::MAX_OCTET_LENGTH * Self::USABLE_BITS_PER_BYTE;
|
||||
|
||||
const MAX_VALUE: u64 = u64::MAX >> (u64::BITS as u64 - Self::USABLE_BITS);
|
||||
/// The maximum value that can be represented by a `VInt`
|
||||
pub const MAX: u64 = u64::MAX >> (u64::BITS as u64 - Self::USABLE_BITS);
|
||||
/// The minimum value that can be represented by a `VInt`
|
||||
pub const MIN: u64 = 0;
|
||||
/// A `VInt` with a value of 0
|
||||
pub const ZERO: Self = Self(0);
|
||||
|
||||
/// Create a signed `VInt` from a `u64`
|
||||
///
|
||||
|
@ -43,7 +49,7 @@ impl VInt {
|
|||
/// # Ok(()) }
|
||||
/// ```
|
||||
pub fn from_u64(uint: u64) -> Result<Self> {
|
||||
if uint > Self::MAX_VALUE {
|
||||
if uint > Self::MAX {
|
||||
err!(BadVintSize);
|
||||
}
|
||||
|
||||
|
@ -249,6 +255,35 @@ impl VInt {
|
|||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub(crate) fn saturating_sub(&self, other: u64) -> Self {
|
||||
Self(self.0.saturating_sub(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for VInt {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Self(self.0 - other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for VInt {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
let val = self.0 + other.0;
|
||||
assert!(val <= Self::MAX, "VInt overflow");
|
||||
|
||||
Self(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<u64> for VInt {
|
||||
fn eq(&self, other: &u64) -> bool {
|
||||
self.0 == *other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use proc_macro::TokenStream;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::HashMap;
|
||||
use syn::parse::{Parse, Parser};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{braced, bracketed, Ident, Token};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct EbmlMasterElement {
|
||||
pub(crate) readable_ident: Ident,
|
||||
pub(crate) info: EbmlMasterInfo,
|
||||
|
@ -24,6 +25,7 @@ impl Parse for EbmlMasterElement {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct EbmlMasterInfo {
|
||||
pub(crate) id: u64,
|
||||
pub(crate) children: Vec<EbmlChildElement>,
|
||||
|
@ -54,6 +56,7 @@ impl Parse for EbmlMasterInfo {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct EbmlChildElement {
|
||||
pub(crate) readable_ident: Ident,
|
||||
pub(crate) info: EbmlChildInfo,
|
||||
|
@ -74,6 +77,7 @@ impl Parse for EbmlChildElement {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct EbmlChildInfo {
|
||||
pub(crate) id: u64,
|
||||
pub(crate) data_type: Ident,
|
||||
|
@ -90,17 +94,17 @@ impl Parse for EbmlChildInfo {
|
|||
}
|
||||
}
|
||||
|
||||
fn insert_element_identifiers(identifiers: &mut HashSet<Ident>, element: &EbmlMasterElement) {
|
||||
identifiers.insert(element.readable_ident.clone());
|
||||
fn insert_element_identifiers(identifiers: &mut HashMap<Ident, u64>, element: &EbmlMasterElement) {
|
||||
identifiers.insert(element.readable_ident.clone(), element.info.id);
|
||||
for child in &element.info.children {
|
||||
identifiers.insert(child.readable_ident.clone());
|
||||
identifiers.insert(child.readable_ident.clone(), child.info.id);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_ebml_master_elements(
|
||||
input: TokenStream,
|
||||
) -> syn::Result<(HashSet<Ident>, Vec<EbmlMasterElement>)> {
|
||||
let mut element_identifiers = HashSet::new();
|
||||
) -> syn::Result<(HashMap<Ident, u64>, Vec<EbmlMasterElement>)> {
|
||||
let mut element_identifiers = HashMap::new();
|
||||
|
||||
let parser = Punctuated::<EbmlMasterElement, Token![,]>::parse_terminated;
|
||||
let elements = parser.parse(input)?;
|
||||
|
|
|
@ -79,7 +79,6 @@ pub fn ebml_master_elements(input: TokenStream) -> TokenStream {
|
|||
}
|
||||
|
||||
let (identifiers, elements) = ret.unwrap();
|
||||
let identifiers_iter = identifiers.iter();
|
||||
let elements_map_inserts = elements.iter().map(|element| {
|
||||
let readable_ident = &element.readable_ident;
|
||||
let id = element.info.id;
|
||||
|
@ -106,10 +105,18 @@ pub fn ebml_master_elements(input: TokenStream) -> TokenStream {
|
|||
}
|
||||
});
|
||||
|
||||
let mut ident_variants = Vec::new();
|
||||
for (ident, id) in &identifiers {
|
||||
ident_variants.push(quote! {
|
||||
#ident = #id,
|
||||
});
|
||||
}
|
||||
|
||||
TokenStream::from(quote! {
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
#[repr(u64)]
|
||||
pub(crate) enum ElementIdent {
|
||||
#( #identifiers_iter ),*
|
||||
#( #ident_variants )*
|
||||
}
|
||||
|
||||
fn master_elements() -> &'static ::std::collections::HashMap<VInt, MasterElement> {
|
||||
|
|
Loading…
Reference in a new issue