Skip to content

Commit d8081be

Browse files
committed
EBML: Tag writing
1 parent 31c41ad commit d8081be

29 files changed

+883
-318
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct_excessive_bools = "allow" # I have yet to find one case of this
7272
needless_continue = "allow" # All occurences of this lint are just for clarity in large loops
7373
unbuffered_bytes = "allow" # It is up to the caller to wrap their data in `BufReader`s
7474
struct_field_names = "allow"
75+
module_inception = "allow"
7576

7677
[workspace.lints.rustdoc]
7778
broken_intra_doc_links = "deny"

lofty/src/ebml/element_reader.rs

Lines changed: 94 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,58 @@ use lofty_attr::ebml_master_elements;
1212
pub struct ElementHeader {
1313
pub(crate) id: ElementId,
1414
pub(crate) size: VInt<u64>,
15+
/// Number of bytes that the `id` field occupied when parsed
16+
pub(crate) size_of_id: u8,
17+
/// Number of bytes that the `size` field occupied when parsed
18+
pub(crate) size_of_size: u8,
1519
}
1620

1721
impl ElementHeader {
1822
fn read<R>(reader: &mut R, max_id_length: u8, max_vint_length: u8) -> Result<Self>
1923
where
2024
R: Read,
2125
{
26+
let (id, id_bytes_read) = ElementId::parse(reader, max_id_length)?;
27+
let (size, size_bytes_read) = VInt::<u64>::parse(reader, max_vint_length)?;
28+
2229
Ok(Self {
23-
id: ElementId::parse(reader, max_id_length)?,
24-
size: VInt::<u64>::parse(reader, max_vint_length)?,
30+
id,
31+
size,
32+
size_of_id: id_bytes_read,
33+
size_of_size: size_bytes_read,
2534
})
2635
}
2736
}
2837

38+
/// Same as [`ElementHeader`], but with a known ID
39+
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
40+
pub struct KnownElementHeader {
41+
pub(crate) id: ElementIdent,
42+
pub(crate) size: VInt<u64>,
43+
/// Number of bytes that the `id` field occupied when parsed
44+
pub(crate) size_of_id: u8,
45+
/// Number of bytes that the `size` field occupied when parsed
46+
pub(crate) size_of_size: u8,
47+
}
48+
49+
impl KnownElementHeader {
50+
/// The number of bytes the header took occupied when parsed
51+
pub fn len(self) -> usize {
52+
(self.size_of_id + self.size_of_size) as usize
53+
}
54+
}
55+
56+
impl From<KnownElementHeader> for ElementHeader {
57+
fn from(header: KnownElementHeader) -> Self {
58+
Self {
59+
id: ElementId(header.id as u64),
60+
size: header.size,
61+
size_of_id: header.size_of_id,
62+
size_of_size: header.size_of_size,
63+
}
64+
}
65+
}
66+
2967
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
3068
pub enum ElementDataType {
3169
SignedInt,
@@ -255,7 +293,7 @@ ebml_master_elements! {
255293
children: [
256294
FileDescription: { 0x467E, String },
257295
FileName: { 0x466E, Utf8 },
258-
FileMimeType: { 0x4660, String },
296+
FileMediaType: { 0x4660, String },
259297
FileData: { 0x465C, Binary },
260298
FileUID: { 0x46AE, UnsignedInt },
261299
FileReferral: { 0x4675, Binary },
@@ -348,29 +386,30 @@ impl ElementReaderContext {
348386
}
349387
}
350388

351-
#[derive(Debug)]
389+
#[derive(Copy, Clone, Debug)]
352390
pub(crate) enum ElementReaderYield {
353-
Master((ElementIdent, VInt<u64>)),
391+
Master(KnownElementHeader),
354392
Child((ChildElementDescriptor, VInt<u64>)),
355393
Unknown(ElementHeader),
356394
Eof,
357395
}
358396

359397
impl ElementReaderYield {
360-
pub fn ident(&self) -> Option<u64> {
398+
pub fn ident(&self) -> Option<ElementId> {
361399
match self {
362-
ElementReaderYield::Master((ident, _)) => Some(*ident as u64),
363-
ElementReaderYield::Child((child, _)) => Some(child.ident as u64),
364-
ElementReaderYield::Unknown(header) => Some(header.id.value()),
400+
ElementReaderYield::Master(KnownElementHeader { id, .. }) => {
401+
Some(ElementId(*id as u64))
402+
},
403+
ElementReaderYield::Child((child, _)) => Some(ElementId(child.ident as u64)),
404+
ElementReaderYield::Unknown(header) => Some(header.id),
365405
_ => None,
366406
}
367407
}
368408

369409
pub fn size(&self) -> Option<u64> {
370410
match self {
371-
ElementReaderYield::Master((_, size)) | ElementReaderYield::Child((_, size)) => {
372-
Some(size.value())
373-
},
411+
ElementReaderYield::Master(KnownElementHeader { size, .. })
412+
| ElementReaderYield::Child((_, size)) => Some(size.value()),
374413
ElementReaderYield::Unknown(header) => Some(header.size.value()),
375414
_ => None,
376415
}
@@ -421,13 +460,21 @@ impl<R> ElementReader<R>
421460
where
422461
R: Read,
423462
{
424-
pub(crate) fn new(reader: R) -> Self {
463+
pub fn new(reader: R) -> Self {
425464
Self {
426465
reader,
427466
ctx: ElementReaderContext::default(),
428467
}
429468
}
430469

470+
pub fn into_inner(self) -> R {
471+
self.reader
472+
}
473+
474+
pub fn inner(&self) -> &R {
475+
&self.reader
476+
}
477+
431478
pub(crate) fn set_max_id_length(&mut self, len: u8) {
432479
self.ctx.max_id_length = len
433480
}
@@ -437,7 +484,7 @@ where
437484
}
438485

439486
fn push_new_master(&mut self, master: MasterElement, size: VInt<u64>) -> Result<()> {
440-
log::debug!("New master element: {:?}", master.id);
487+
log::trace!("New master element: {:?}", master.id);
441488

442489
if self.ctx.depth == MAX_DEPTH {
443490
decode_err!(@BAIL Ebml, "Maximum depth reached");
@@ -477,8 +524,7 @@ where
477524
}
478525

479526
if self.ctx.depth == ROOT_DEPTH {
480-
return Err(io::Error::new(
481-
io::ErrorKind::Other,
527+
return Err(io::Error::other(
482528
"Cannot go to previous master element, already at root",
483529
));
484530
}
@@ -504,7 +550,12 @@ where
504550

505551
self.push_new_master(*master, header.size)?;
506552

507-
Ok(ElementReaderYield::Master((master.id, header.size)))
553+
Ok(ElementReaderYield::Master(KnownElementHeader {
554+
id: master.id,
555+
size: header.size,
556+
size_of_id: header.size_of_id,
557+
size_of_size: header.size_of_size,
558+
}))
508559
}
509560

510561
pub(crate) fn next(&mut self) -> Result<ElementReaderYield> {
@@ -539,7 +590,12 @@ where
539590
self.push_new_master(master, header.size)?;
540591

541592
// We encountered a nested master element
542-
return Ok(ElementReaderYield::Master((child.ident, header.size)));
593+
return Ok(ElementReaderYield::Master(KnownElementHeader {
594+
id: child.ident,
595+
size: header.size,
596+
size_of_id: header.size_of_id,
597+
size_of_size: header.size_of_size,
598+
}));
543599
}
544600

545601
Ok(ElementReaderYield::Child((*child, header.size)))
@@ -593,7 +649,7 @@ where
593649
}
594650

595651
pub(crate) fn skip_element(&mut self, element_header: ElementHeader) -> Result<()> {
596-
log::debug!(
652+
log::trace!(
597653
"Encountered unknown EBML element: {:X}, skipping",
598654
element_header.id.0
599655
);
@@ -608,6 +664,11 @@ where
608664
decode_err!(@BAIL Ebml, "Invalid size for signed int element")
609665
}
610666

667+
// "a Signed Integer Element with a zero-octet length represents an integer value of zero."
668+
if element_length == 0 {
669+
return Ok(0);
670+
}
671+
611672
let mut buf = [0; 8];
612673
self.read_exact(&mut buf[8 - element_length as usize..])?;
613674
let value = u64::from_be_bytes(buf);
@@ -625,6 +686,11 @@ where
625686
decode_err!(@BAIL Ebml, "Invalid size for unsigned int element")
626687
}
627688

689+
// "an Unsigned Integer Element with a zero-octet length represents an integer value of zero."
690+
if element_length == 0 {
691+
return Ok(0);
692+
}
693+
628694
let mut buf = [0; 8];
629695
self.read_exact(&mut buf[8 - element_length as usize..])?;
630696
Ok(u64::from_be_bytes(buf))
@@ -634,7 +700,7 @@ where
634700
pub(crate) fn read_flag(&mut self, element_length: u64) -> Result<bool> {
635701
let val = self.read_unsigned_int(element_length)?;
636702
if val > 1 {
637-
log::warn!("Flag value `{}` is out of range, assuming true", val);
703+
log::warn!("Flag value `{val}` is out of range, assuming true");
638704
}
639705

640706
Ok(val != 0)
@@ -722,14 +788,18 @@ where
722788
Self { reader }
723789
}
724790

725-
pub(crate) fn next(&mut self) -> Result<Option<ElementReaderYield>> {
791+
pub(crate) fn next(&mut self) -> Option<Result<ElementReaderYield>> {
726792
match self.reader.next() {
727793
Ok(ElementReaderYield::Unknown(header)) => {
728-
self.reader.skip_element(header)?;
794+
if let Err(e) = self.reader.skip_element(header) {
795+
return Some(Err(e));
796+
}
797+
729798
self.next()
730799
},
731-
Err(e) => Err(e),
732-
element => element.map(Some),
800+
Ok(ElementReaderYield::Eof) => None,
801+
Err(e) => Some(Err(e)),
802+
element => Some(element),
733803
}
734804
}
735805

lofty/src/ebml/properties.rs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,68 @@
11
use super::Language;
22
use crate::properties::FileProperties;
33

4+
use std::fmt::Display;
5+
use std::str::FromStr;
46
use std::time::Duration;
57

8+
/// The supported EBML document types
9+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
10+
pub enum DocumentType {
11+
/// Matroska (`audio/x-matroska` / `video/x-matroska`)
12+
Matroska,
13+
/// WebM (`audio/webm` / `video/webm`)
14+
Webm,
15+
}
16+
17+
impl FromStr for DocumentType {
18+
type Err = ();
19+
20+
fn from_str(s: &str) -> Result<Self, Self::Err> {
21+
match s {
22+
"matroska" => Ok(DocumentType::Matroska),
23+
"webm" => Ok(DocumentType::Webm),
24+
_ => Err(()),
25+
}
26+
}
27+
}
28+
29+
impl Display for DocumentType {
30+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31+
match self {
32+
DocumentType::Matroska => write!(f, "matroska"),
33+
DocumentType::Webm => write!(f, "webm"),
34+
}
35+
}
36+
}
37+
638
/// Properties from the EBML header
739
///
840
/// These are present for all EBML formats.
9-
#[derive(Debug, Clone, PartialEq, Default)]
41+
#[derive(Debug, Clone, PartialEq)]
1042
pub struct EbmlHeaderProperties {
1143
pub(crate) version: u64,
1244
pub(crate) read_version: u64,
1345
pub(crate) max_id_length: u8,
1446
pub(crate) max_size_length: u8,
15-
pub(crate) doc_type: String,
47+
pub(crate) doc_type: DocumentType,
1648
pub(crate) doc_type_version: u64,
1749
pub(crate) doc_type_read_version: u64,
1850
}
1951

52+
impl Default for EbmlHeaderProperties {
53+
fn default() -> Self {
54+
Self {
55+
version: 0,
56+
read_version: 0,
57+
max_id_length: 0,
58+
max_size_length: 0,
59+
doc_type: DocumentType::Matroska,
60+
doc_type_version: 0,
61+
doc_type_read_version: 0,
62+
}
63+
}
64+
}
65+
2066
impl EbmlHeaderProperties {
2167
/// The EBML version, should be `1`
2268
pub fn version(&self) -> u64 {
@@ -38,9 +84,9 @@ impl EbmlHeaderProperties {
3884
self.max_size_length
3985
}
4086

41-
/// A string that describes the type of document
42-
pub fn doc_type(&self) -> &str {
43-
&self.doc_type
87+
/// The type of document
88+
pub fn doc_type(&self) -> DocumentType {
89+
self.doc_type
4490
}
4591

4692
/// The version of DocType interpreter used to create the EBML Document

0 commit comments

Comments
 (0)