Skip to content

Commit 8385683

Browse files
committed
EBML: Stop requiring explicit locking of reader
Signed-off-by: Serial <[email protected]>
1 parent c704999 commit 8385683

File tree

4 files changed

+131
-75
lines changed

4 files changed

+131
-75
lines changed

src/ebml/element_reader.rs

+95-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::error::Result;
33
use crate::macros::{decode_err, try_vec};
44

55
use std::io::Read;
6+
use std::ops::{Deref, DerefMut};
67

78
use byteorder::{BigEndian, ReadBytesExt};
89
use lofty_attr::ebml_master_elements;
@@ -229,7 +230,11 @@ where
229230
self.ctx.previous_master_length = self.ctx.master_length;
230231
}
231232

232-
fn next_master(&mut self) -> Result<ElementReaderYield> {
233+
fn goto_next_master(&mut self) -> Result<ElementReaderYield> {
234+
if self.ctx.master_length != 0 {
235+
self.skip(self.ctx.master_length)?;
236+
}
237+
233238
let header = ElementHeader::read(
234239
&mut self.reader,
235240
self.ctx.max_id_length,
@@ -249,15 +254,6 @@ where
249254
)))
250255
}
251256

252-
/// Lock the reader to the current master element
253-
pub(crate) fn lock(&mut self) {
254-
self.ctx.locked = true;
255-
}
256-
257-
pub(crate) fn unlock(&mut self) {
258-
self.ctx.locked = false;
259-
}
260-
261257
pub(crate) fn goto_previous_master(&mut self) -> Result<()> {
262258
if let Some(previous_master) = self.ctx.previous_master {
263259
self.ctx.current_master = Some(previous_master);
@@ -270,15 +266,15 @@ where
270266

271267
pub(crate) fn next(&mut self) -> Result<ElementReaderYield> {
272268
let Some(current_master) = self.ctx.current_master else {
273-
return self.next_master();
269+
return self.goto_next_master();
274270
};
275271

276272
if self.ctx.master_length == 0 {
277273
if self.ctx.locked {
278274
return Ok(ElementReaderYield::Eof);
279275
}
280276

281-
return self.next_master();
277+
return self.goto_next_master();
282278
}
283279

284280
let header = ElementHeader::read(self, self.ctx.max_id_length, self.ctx.max_size_length)?;
@@ -310,11 +306,33 @@ where
310306
Ok(ElementReaderYield::Child((*child, header.size.value())))
311307
}
312308

309+
fn lock(&mut self) {
310+
self.ctx.locked = true;
311+
}
312+
313+
fn unlock(&mut self) {
314+
self.ctx.locked = false;
315+
}
316+
317+
pub(crate) fn children(&mut self) -> ElementChildIterator<'_, R> {
318+
self.lock();
319+
ElementChildIterator::new(self)
320+
}
321+
313322
pub(crate) fn skip(&mut self, length: u64) -> Result<()> {
314323
std::io::copy(&mut self.by_ref().take(length), &mut std::io::sink())?;
315324
Ok(())
316325
}
317326

327+
pub(crate) fn skip_element(&mut self, element_header: ElementHeader) -> Result<()> {
328+
log::debug!(
329+
"Encountered unknown EBML element in header: {:X}",
330+
element_header.id.0
331+
);
332+
self.skip(element_header.size.value())?;
333+
Ok(())
334+
}
335+
318336
pub(crate) fn read_signed_int(&mut self, element_length: u64) -> Result<i64> {
319337
// https://www.rfc-editor.org/rfc/rfc8794.html#section-7.1
320338
// A Signed Integer Element MUST declare a length from zero to eight octets
@@ -390,3 +408,68 @@ where
390408
todo!()
391409
}
392410
}
411+
412+
pub(crate) struct ElementChildIterator<'a, R>
413+
where
414+
R: Read,
415+
{
416+
reader: &'a mut ElementReader<R>,
417+
}
418+
419+
impl<'a, R> ElementChildIterator<'a, R>
420+
where
421+
R: Read,
422+
{
423+
pub(crate) fn new(reader: &'a mut ElementReader<R>) -> Self {
424+
Self { reader }
425+
}
426+
427+
pub(crate) fn next(&mut self) -> Result<Option<ElementReaderYield>> {
428+
match self.reader.next() {
429+
Ok(ElementReaderYield::Unknown(header)) => {
430+
self.reader.skip_element(header)?;
431+
self.next()
432+
},
433+
Ok(ElementReaderYield::Eof) => Ok(None),
434+
Err(e) => Err(e),
435+
element => element.map(Some),
436+
}
437+
}
438+
439+
pub(crate) fn master_exhausted(&self) -> bool {
440+
self.reader.ctx.master_length == 0
441+
}
442+
443+
pub(crate) fn inner(&mut self) -> &mut ElementReader<R> {
444+
self.reader
445+
}
446+
}
447+
448+
impl<'a, R> Deref for ElementChildIterator<'a, R>
449+
where
450+
R: Read,
451+
{
452+
type Target = ElementReader<R>;
453+
454+
fn deref(&self) -> &Self::Target {
455+
self.reader
456+
}
457+
}
458+
459+
impl<'a, R> DerefMut for ElementChildIterator<'a, R>
460+
where
461+
R: Read,
462+
{
463+
fn deref_mut(&mut self) -> &mut Self::Target {
464+
self.reader
465+
}
466+
}
467+
468+
impl<'a, R> Drop for ElementChildIterator<'a, R>
469+
where
470+
R: Read,
471+
{
472+
fn drop(&mut self) {
473+
self.reader.unlock();
474+
}
475+
}

src/ebml/read.rs

+17-26
Original file line numberDiff line numberDiff line change
@@ -69,69 +69,60 @@ where
6969
Err(e) => return Err(e),
7070
}
7171

72-
element_reader.lock();
73-
74-
loop {
72+
let mut child_reader = element_reader.children();
73+
while let Some(child) = child_reader.next()? {
7574
let ident;
7675
let data_ty;
7776
let size;
7877

79-
let res = element_reader.next()?;
80-
match res {
78+
match child {
8179
// The only expected master element in the header is `DocTypeExtension`
8280
ElementReaderYield::Master((ElementIdent::DocTypeExtension, _)) => continue,
8381
ElementReaderYield::Child((child, size_)) => {
8482
ident = child.ident;
8583
data_ty = child.data_type;
8684
size = size_;
8785
},
88-
ElementReaderYield::Unknown(element) => {
89-
log::debug!(
90-
"Encountered unknown EBML element in header: {:X}",
91-
element.id.0
92-
);
93-
element_reader.skip(element.size.value())?;
94-
continue;
95-
},
9686
_ => break,
9787
}
9888

9989
if ident == ElementIdent::EBMLMaxIDLength {
100-
properties.header.max_id_length = element_reader.read_unsigned_int(size)? as u8;
101-
element_reader.set_max_id_length(properties.header.max_id_length);
90+
properties.header.max_id_length = child_reader.read_unsigned_int(size)? as u8;
91+
child_reader.set_max_id_length(properties.header.max_id_length);
10292
continue;
10393
}
10494

10595
if ident == ElementIdent::EBMLMaxSizeLength {
106-
properties.header.max_size_length = element_reader.read_unsigned_int(size)? as u8;
107-
element_reader.set_max_size_length(properties.header.max_size_length);
96+
properties.header.max_size_length = child_reader.read_unsigned_int(size)? as u8;
97+
child_reader.set_max_size_length(properties.header.max_size_length);
10898
continue;
10999
}
110100

111101
// Anything else in the header is unnecessary, and only read for the properties
112102
// struct
113103
if !parse_options.read_properties {
114-
element_reader.skip(size)?;
104+
child_reader.skip(size)?;
115105
continue;
116106
}
117107

118108
match ident {
119109
ElementIdent::EBMLVersion => {
120-
properties.header.version = element_reader.read_unsigned_int(size)?
110+
properties.header.version = child_reader.read_unsigned_int(size)?
121111
},
122112
ElementIdent::EBMLReadVersion => {
123-
properties.header.read_version = element_reader.read_unsigned_int(size)?
124-
},
125-
ElementIdent::DocType => {
126-
properties.header.doc_type = element_reader.read_string(size)?
113+
properties.header.read_version = child_reader.read_unsigned_int(size)?
127114
},
115+
ElementIdent::DocType => properties.header.doc_type = child_reader.read_string(size)?,
128116
ElementIdent::DocTypeVersion => {
129-
properties.header.doc_type_version = element_reader.read_unsigned_int(size)?
117+
properties.header.doc_type_version = child_reader.read_unsigned_int(size)?
130118
},
131-
_ => element_reader.skip(size)?,
119+
_ => child_reader.skip(size)?,
132120
}
133121
}
134122

135-
element_reader.unlock();
123+
debug_assert!(
124+
child_reader.master_exhausted(),
125+
"There should be no remaining elements in the header"
126+
);
136127
Ok(())
137128
}

src/ebml/read/segment.rs

+8-18
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,14 @@ pub(super) fn read_from<R>(
1616
where
1717
R: Read + Seek,
1818
{
19-
element_reader.lock();
20-
2119
let mut tags = None;
2220

23-
loop {
24-
let res = element_reader.next()?;
25-
match res {
21+
let mut children_reader = element_reader.children();
22+
while let Some(child) = children_reader.next()? {
23+
match child {
2624
ElementReaderYield::Master((id, size)) => match id {
2725
ElementIdent::Info => {
28-
segment_info::read_from(element_reader, parse_options, properties)?
26+
segment_info::read_from(children_reader.inner(), parse_options, properties)?
2927
},
3028
ElementIdent::Cluster => todo!("Support segment.Cluster"),
3129
ElementIdent::Tracks => todo!("Support segment.Tracks"),
@@ -37,23 +35,15 @@ where
3735
// elements, so we can just skip any useless ones.
3836

3937
log::debug!("Skipping EBML master element: {:?}", id);
40-
element_reader.skip(size)?;
41-
element_reader.goto_previous_master()?;
38+
children_reader.skip(size)?;
39+
children_reader.goto_previous_master()?;
4240
continue;
4341
},
4442
},
45-
ElementReaderYield::Unknown(element) => {
46-
log::debug!("Skipping unknown EBML element: {:X}", element.id.0);
47-
element_reader.skip(element.size.value())?;
48-
continue;
49-
},
50-
ElementReaderYield::Eof => {
51-
element_reader.unlock();
52-
break;
53-
},
54-
_ => {
43+
ElementReaderYield::Child(_) => {
5544
decode_err!(@BAIL Ebml, "Segment element should only contain master elements")
5645
},
46+
_ => break,
5747
}
5848
}
5949

src/ebml/read/segment_info.rs

+11-19
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,24 @@ pub(super) fn read_from<R>(
1414
where
1515
R: Read + Seek,
1616
{
17-
element_reader.lock();
17+
let mut children_reader = element_reader.children();
1818

19-
loop {
20-
let res = element_reader.next()?;
21-
match res {
19+
while let Some(child) = children_reader.next()? {
20+
match child {
2221
ElementReaderYield::Master((id, size)) => {
2322
// We do not end up using information from any of the nested master
2423
// elements, so we can just skip them.
2524

2625
log::debug!("Skipping EBML master element: {:?}", id);
27-
element_reader.skip(size)?;
28-
element_reader.goto_previous_master()?;
26+
children_reader.skip(size)?;
27+
children_reader.goto_previous_master()?;
2928
continue;
3029
},
3130
ElementReaderYield::Child((child, size)) => {
3231
match child.ident {
3332
ElementIdent::TimecodeScale => {
3433
properties.segment_info.timestamp_scale =
35-
element_reader.read_unsigned_int(size)?;
34+
children_reader.read_unsigned_int(size)?;
3635

3736
if properties.segment_info.timestamp_scale == 0 {
3837
log::warn!("Segment.Info.TimecodeScale is 0, which is invalid");
@@ -42,33 +41,26 @@ where
4241
}
4342
},
4443
ElementIdent::MuxingApp => {
45-
properties.segment_info.muxing_app = element_reader.read_utf8(size)?
44+
properties.segment_info.muxing_app = children_reader.read_utf8(size)?
4645
},
4746
ElementIdent::WritingApp => {
48-
properties.segment_info.writing_app = element_reader.read_utf8(size)?
47+
properties.segment_info.writing_app = children_reader.read_utf8(size)?
4948
},
5049
_ => {
5150
// We do not end up using information from all of the segment
5251
// elements, so we can just skip any useless ones.
5352

5453
log::debug!("Skipping EBML child element: {:?}", child.ident);
55-
element_reader.skip(size)?;
54+
children_reader.skip(size)?;
5655
continue;
5756
},
5857
}
5958
},
60-
ElementReaderYield::Unknown(element) => {
61-
log::debug!("Skipping unknown EBML element: {:X}", element.id.0);
62-
element_reader.skip(element.size.value())?;
63-
continue;
64-
},
65-
ElementReaderYield::Eof => {
66-
element_reader.unlock();
67-
break;
68-
},
59+
_ => break,
6960
}
7061
}
7162

63+
drop(children_reader);
7264
element_reader.goto_previous_master()?;
7365
Ok(())
7466
}

0 commit comments

Comments
 (0)