Skip to content

Commit fa383da

Browse files
committed
EBML: Start parsing \Ebml\Segments\Tracks
1 parent e1ec6db commit fa383da

File tree

8 files changed

+158
-47
lines changed

8 files changed

+158
-47
lines changed

lofty/src/ebml/element_reader.rs

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,11 @@ ebml_master_elements! {
169169
struct ElementReaderContext {
170170
/// Previous master element
171171
previous_master: Option<MasterElement>,
172-
previous_master_length: u64,
172+
previous_master_length: VInt,
173173
/// Current master element
174174
current_master: Option<MasterElement>,
175175
/// Remaining length of the master element
176-
master_length: u64,
176+
master_length: VInt,
177177
/// Maximum size in octets of all element IDs
178178
max_id_length: u8,
179179
/// Maximum size in octets of all element data sizes
@@ -189,9 +189,9 @@ impl Default for ElementReaderContext {
189189
fn default() -> Self {
190190
Self {
191191
previous_master: None,
192-
previous_master_length: 0,
192+
previous_master_length: VInt::ZERO,
193193
current_master: None,
194-
master_length: 0,
194+
master_length: VInt::ZERO,
195195
// https://www.rfc-editor.org/rfc/rfc8794.html#name-ebmlmaxidlength-element
196196
max_id_length: 4,
197197
// https://www.rfc-editor.org/rfc/rfc8794.html#name-ebmlmaxsizelength-element
@@ -202,12 +202,32 @@ impl Default for ElementReaderContext {
202202
}
203203

204204
pub(crate) enum ElementReaderYield {
205-
Master((ElementIdent, u64)),
206-
Child((ChildElementDescriptor, u64)),
205+
Master((ElementIdent, VInt)),
206+
Child((ChildElementDescriptor, VInt)),
207207
Unknown(ElementHeader),
208208
Eof,
209209
}
210210

211+
impl ElementReaderYield {
212+
pub fn ident(&self) -> Option<u64> {
213+
match self {
214+
ElementReaderYield::Master((ident, _)) => Some(*ident as u64),
215+
ElementReaderYield::Child((child, _)) => Some(child.ident as u64),
216+
ElementReaderYield::Unknown(header) => Some(header.id.value()),
217+
_ => None,
218+
}
219+
}
220+
221+
pub fn size(&self) -> Option<u64> {
222+
match self {
223+
ElementReaderYield::Master((_, size)) => Some(size.value()),
224+
ElementReaderYield::Child((_, size)) => Some(size.value()),
225+
ElementReaderYield::Unknown(header) => Some(header.size.value()),
226+
_ => None,
227+
}
228+
}
229+
}
230+
211231
pub struct ElementReader<R> {
212232
reader: R,
213233
ctx: ElementReaderContext,
@@ -250,7 +270,7 @@ where
250270

251271
fn goto_next_master(&mut self) -> Result<ElementReaderYield> {
252272
if self.ctx.master_length != 0 {
253-
self.skip(self.ctx.master_length)?;
273+
self.skip(self.ctx.master_length.value())?;
254274
}
255275

256276
let header = ElementHeader::read(
@@ -265,7 +285,7 @@ where
265285

266286
self.store_previous_master();
267287
self.ctx.current_master = Some(*master);
268-
self.ctx.master_length = header.size.value();
288+
self.ctx.master_length = header.size;
269289
Ok(ElementReaderYield::Master((
270290
master.id,
271291
self.ctx.master_length,
@@ -312,16 +332,13 @@ where
312332
.get(&header.id)
313333
.expect("Nested master elements should be defined at this level."),
314334
);
315-
self.ctx.master_length = header.size.value();
335+
self.ctx.master_length = header.size;
316336

317337
// We encountered a nested master element
318-
return Ok(ElementReaderYield::Master((
319-
child.ident,
320-
header.size.value(),
321-
)));
338+
return Ok(ElementReaderYield::Master((child.ident, header.size)));
322339
}
323340

324-
Ok(ElementReaderYield::Child((*child, header.size.value())))
341+
Ok(ElementReaderYield::Child((*child, header.size)))
325342
}
326343

327344
fn lock(&mut self) {

lofty/src/ebml/read.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,36 +92,38 @@ where
9292
}
9393

9494
if ident == ElementIdent::EBMLMaxIDLength {
95-
properties.header.max_id_length = child_reader.read_unsigned_int(size)? as u8;
95+
properties.header.max_id_length = child_reader.read_unsigned_int(size.value())? as u8;
9696
child_reader.set_max_id_length(properties.header.max_id_length);
9797
continue;
9898
}
9999

100100
if ident == ElementIdent::EBMLMaxSizeLength {
101-
properties.header.max_size_length = child_reader.read_unsigned_int(size)? as u8;
101+
properties.header.max_size_length = child_reader.read_unsigned_int(size.value())? as u8;
102102
child_reader.set_max_size_length(properties.header.max_size_length);
103103
continue;
104104
}
105105

106106
// Anything else in the header is unnecessary, and only read for the properties
107107
// struct
108108
if !parse_options.read_properties {
109-
child_reader.skip(size)?;
109+
child_reader.skip(size.value())?;
110110
continue;
111111
}
112112

113113
match ident {
114114
ElementIdent::EBMLVersion => {
115-
properties.header.version = child_reader.read_unsigned_int(size)?
115+
properties.header.version = child_reader.read_unsigned_int(size.value())?
116116
},
117117
ElementIdent::EBMLReadVersion => {
118-
properties.header.read_version = child_reader.read_unsigned_int(size)?
118+
properties.header.read_version = child_reader.read_unsigned_int(size.value())?
119+
},
120+
ElementIdent::DocType => {
121+
properties.header.doc_type = child_reader.read_string(size.value())?
119122
},
120-
ElementIdent::DocType => properties.header.doc_type = child_reader.read_string(size)?,
121123
ElementIdent::DocTypeVersion => {
122-
properties.header.doc_type_version = child_reader.read_unsigned_int(size)?
124+
properties.header.doc_type_version = child_reader.read_unsigned_int(size.value())?
123125
},
124-
_ => child_reader.skip(size)?,
126+
_ => child_reader.skip(size.value())?,
125127
}
126128
}
127129

lofty/src/ebml/read/segment.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,11 @@ where
3434
ElementIdent::Tracks if parse_options.read_properties => {
3535
segment_tracks::read_from(children_reader.inner(), parse_options, properties)?
3636
},
37-
ElementIdent::Tags | ElementIdent::Attachments | ElementIdent::Chapters => {
37+
ElementIdent::Tags | ElementIdent::Chapters if parse_options.read_tags => {
3838
let mut tag = tags.unwrap_or_default();
3939

4040
if id == ElementIdent::Tags {
4141
segment_tags::read_from(children_reader.inner(), parse_options, &mut tag)?
42-
} else if id == ElementIdent::Attachments {
43-
segment_attachments::read_from(
44-
children_reader.inner(),
45-
parse_options,
46-
&mut tag,
47-
)?
4842
} else {
4943
segment_chapters::read_from(
5044
children_reader.inner(),
@@ -55,12 +49,23 @@ where
5549

5650
tags = Some(tag);
5751
},
52+
ElementIdent::Attachments if parse_options.read_cover_art => {
53+
let mut tag = tags.unwrap_or_default();
54+
55+
segment_attachments::read_from(
56+
children_reader.inner(),
57+
parse_options,
58+
&mut tag,
59+
)?;
60+
61+
tags = Some(tag);
62+
},
5863
_ => {
5964
// We do not end up using information from all of the segment
6065
// elements, so we can just skip any useless ones.
6166

6267
log::debug!("Skipping EBML master element: {:?}", id);
63-
children_reader.skip(size)?;
68+
children_reader.skip(size.value())?;
6469
children_reader.goto_previous_master()?;
6570
continue;
6671
},

lofty/src/ebml/read/segment_info.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ where
2323
// elements, so we can just skip them.
2424

2525
log::debug!("Skipping EBML master element: {:?}", id);
26-
children_reader.skip(size)?;
26+
children_reader.skip(size.value())?;
2727
children_reader.goto_previous_master()?;
2828
continue;
2929
},
3030
ElementReaderYield::Child((child, size)) => {
3131
match child.ident {
3232
ElementIdent::TimecodeScale => {
3333
properties.segment_info.timestamp_scale =
34-
children_reader.read_unsigned_int(size)?;
34+
children_reader.read_unsigned_int(size.value())?;
3535

3636
if properties.segment_info.timestamp_scale == 0 {
3737
log::warn!("Segment.Info.TimecodeScale is 0, which is invalid");
@@ -41,17 +41,19 @@ where
4141
}
4242
},
4343
ElementIdent::MuxingApp => {
44-
properties.segment_info.muxing_app = children_reader.read_utf8(size)?
44+
properties.segment_info.muxing_app =
45+
children_reader.read_utf8(size.value())?
4546
},
4647
ElementIdent::WritingApp => {
47-
properties.segment_info.writing_app = children_reader.read_utf8(size)?
48+
properties.segment_info.writing_app =
49+
children_reader.read_utf8(size.value())?
4850
},
4951
_ => {
5052
// We do not end up using information from all of the segment
5153
// elements, so we can just skip any useless ones.
5254

5355
log::debug!("Skipping EBML child element: {:?}", child.ident);
54-
children_reader.skip(size)?;
56+
children_reader.skip(size.value())?;
5557
continue;
5658
},
5759
}

lofty/src/ebml/read/segment_tracks.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,57 @@
11
use crate::config::ParseOptions;
2-
use crate::ebml::element_reader::{ElementIdent, ElementReader, ElementReaderYield};
2+
use crate::ebml::element_reader::{
3+
ChildElementDescriptor, ElementHeader, ElementIdent, ElementReader, ElementReaderYield,
4+
};
35
use crate::ebml::properties::EbmlProperties;
46
use crate::error::Result;
57
use crate::macros::decode_err;
68

79
use std::io::{Read, Seek};
810

911
pub(super) fn read_from<R>(
12+
element_reader: &mut ElementReader<R>,
13+
parse_options: ParseOptions,
14+
properties: &mut EbmlProperties,
15+
) -> Result<()>
16+
where
17+
R: Read + Seek,
18+
{
19+
let mut children_reader = element_reader.children();
20+
21+
while let Some(child) = children_reader.next()? {
22+
match child {
23+
ElementReaderYield::Master((ElementIdent::TrackEntry, size)) => {
24+
read_track_entry(children_reader.inner(), parse_options, properties)?;
25+
},
26+
ElementReaderYield::Eof => {
27+
break;
28+
},
29+
_ => {
30+
let id = child
31+
.ident()
32+
.expect("Child element must have an identifier");
33+
let size = child.size().expect("Child element must have a size");
34+
35+
log::warn!(
36+
"Unexpected child element in \\EBML\\Segment\\Tracks: {:?}, skipping",
37+
id
38+
);
39+
children_reader.skip(size)?;
40+
continue;
41+
},
42+
}
43+
}
44+
45+
Ok(())
46+
}
47+
48+
fn read_track_entry<R>(
1049
_element_reader: &mut ElementReader<R>,
1150
_parse_options: ParseOptions,
1251
_properties: &mut EbmlProperties,
1352
) -> Result<()>
1453
where
1554
R: Read + Seek,
1655
{
17-
unimplemented!("\\Ebml\\Segment\\Tracks")
56+
Ok(())
1857
}

lofty/src/ebml/vint.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::error::Result;
22
use crate::macros::err;
33

44
use std::io::Read;
5+
use std::ops::{Add, Sub};
56

67
use byteorder::{ReadBytesExt, WriteBytesExt};
78

@@ -20,7 +21,12 @@ impl VInt {
2021
const MAX_OCTET_LENGTH: u64 = 8;
2122
const USABLE_BITS: u64 = Self::MAX_OCTET_LENGTH * Self::USABLE_BITS_PER_BYTE;
2223

23-
const MAX_VALUE: u64 = u64::MAX >> (u64::BITS as u64 - Self::USABLE_BITS);
24+
/// The maximum value that can be represented by a `VInt`
25+
pub const MAX: u64 = u64::MAX >> (u64::BITS as u64 - Self::USABLE_BITS);
26+
/// The minimum value that can be represented by a `VInt`
27+
pub const MIN: u64 = 0;
28+
/// A `VInt` with a value of 0
29+
pub const ZERO: Self = Self(0);
2430

2531
/// Create a signed `VInt` from a `u64`
2632
///
@@ -43,7 +49,7 @@ impl VInt {
4349
/// # Ok(()) }
4450
/// ```
4551
pub fn from_u64(uint: u64) -> Result<Self> {
46-
if uint > Self::MAX_VALUE {
52+
if uint > Self::MAX {
4753
err!(BadVintSize);
4854
}
4955

@@ -249,6 +255,35 @@ impl VInt {
249255

250256
Ok(ret)
251257
}
258+
259+
pub(crate) fn saturating_sub(&self, other: u64) -> Self {
260+
Self(self.0.saturating_sub(other))
261+
}
262+
}
263+
264+
impl Sub for VInt {
265+
type Output = Self;
266+
267+
fn sub(self, other: Self) -> Self::Output {
268+
Self(self.0 - other.0)
269+
}
270+
}
271+
272+
impl Add for VInt {
273+
type Output = Self;
274+
275+
fn add(self, other: Self) -> Self::Output {
276+
let val = self.0 + other.0;
277+
assert!(val <= Self::MAX, "VInt overflow");
278+
279+
Self(val)
280+
}
281+
}
282+
283+
impl PartialEq<u64> for VInt {
284+
fn eq(&self, other: &u64) -> bool {
285+
self.0 == *other
286+
}
252287
}
253288

254289
#[cfg(test)]

0 commit comments

Comments
 (0)