Skip to content

Commit e6976f5

Browse files
committed
EBML: Write support for \Segment children
1 parent c702d46 commit e6976f5

File tree

13 files changed

+137
-56
lines changed

13 files changed

+137
-56
lines changed

lofty/src/ebml/tag/mod.rs

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ use crate::io::{FileLike, Length, Truncate};
2121
use crate::picture::Picture;
2222
use crate::tag::companion_tag::CompanionTag;
2323
use crate::tag::{Accessor, MergeTag, SplitTag, TagExt, TagType};
24+
use crate::ebml::tag::write::{ElementWriterCtx, WriteableElement};
2425

2526
use std::borrow::Cow;
2627
use std::collections::HashMap;
27-
use std::io::Write;
28+
use std::io::{Cursor, Write};
2829
use std::ops::Deref;
2930

3031
use lofty_attr::tag;
@@ -356,23 +357,23 @@ impl TagExt for MatroskaTag {
356357

357358
fn save_to<F>(
358359
&self,
359-
_file: &mut F,
360-
_write_options: WriteOptions,
360+
file: &mut F,
361+
write_options: WriteOptions,
361362
) -> std::result::Result<(), Self::Err>
362363
where
363364
F: FileLike,
364365
LoftyError: From<<F as Truncate>::Error>,
365366
LoftyError: From<<F as Length>::Error>,
366367
{
367-
todo!()
368+
MatroskaTagRef::from(self).write_to(file, write_options)
368369
}
369370

370371
fn dump_to<W: Write>(
371372
&self,
372-
_writer: &mut W,
373-
_write_options: WriteOptions,
373+
writer: &mut W,
374+
write_options: WriteOptions,
374375
) -> std::result::Result<(), Self::Err> {
375-
todo!()
376+
MatroskaTagRef::from(self).dump_to(writer, write_options)
376377
}
377378

378379
fn clear(&mut self) {
@@ -440,51 +441,64 @@ impl From<crate::tag::Tag> for MatroskaTag {
440441
}
441442
}
442443

443-
pub(crate) struct MatroskaTagRef<'a, I>
444-
where
445-
I: Iterator<Item = TagRef<'a>>,
444+
pub(crate) struct MatroskaTagRef<'a>
446445
{
447-
pub(crate) tags: I,
446+
pub(crate) tags: Vec<TagRef<'a>>,
448447
}
449448

450-
pub(crate) fn simple_tags_for_tag(tag: &crate::tag::Tag) -> impl Iterator<Item = TagRef<'static>> {
451-
let mut mapped_tags: HashMap<TargetType, Vec<Cow<'static, SimpleTag<'static>>>> =
452-
HashMap::new();
453-
for item in &tag.items {
454-
if let Some((simple_tag, target_type)) = generic::simple_tag_for_item(Cow::Borrowed(item)) {
455-
mapped_tags
456-
.entry(target_type)
457-
.or_default()
458-
.push(Cow::Owned(simple_tag))
449+
impl<'a> From<&'a MatroskaTag> for MatroskaTagRef<'a> {
450+
fn from(value: &'a MatroskaTag) -> Self {
451+
Self {
452+
tags: value.tags.iter().map(Into::into).collect::<Vec<_>>()
459453
}
460454
}
455+
}
461456

462-
mapped_tags
463-
.into_iter()
464-
.map(|(target_type, simple_tags)| TagRef {
465-
targets: TargetDescriptor::Basic(target_type),
466-
simple_tags: Box::new(simple_tags.into_iter()),
467-
})
457+
impl<'a> From<&'a crate::tag::Tag> for MatroskaTagRef<'static> {
458+
fn from(value: &'a crate::tag::Tag) -> Self {
459+
let mut mapped_tags: HashMap<TargetType, Vec<Cow<'static, SimpleTag<'static>>>> =
460+
HashMap::new();
461+
for item in &value.items {
462+
if let Some((simple_tag, target_type)) = generic::simple_tag_for_item(Cow::Borrowed(item)) {
463+
mapped_tags
464+
.entry(target_type)
465+
.or_default()
466+
.push(Cow::Owned(simple_tag))
467+
}
468+
}
469+
470+
let tags = mapped_tags
471+
.into_iter()
472+
.map(|(target_type, simple_tags)| TagRef {
473+
targets: TargetDescriptor::Basic(target_type),
474+
simple_tags,
475+
}).collect::<Vec<_>>();
476+
477+
Self {
478+
tags
479+
}
480+
}
468481
}
469482

470-
impl<'a, I> MatroskaTagRef<'a, I>
471-
where
472-
I: Iterator<Item = TagRef<'a>>,
483+
impl<'a> MatroskaTagRef<'a>
473484
{
474-
pub(crate) fn write_to<F>(&mut self, _file: &mut F, _write_options: WriteOptions) -> Result<()>
485+
pub(crate) fn write_to<F>(&mut self, file: &mut F, write_options: WriteOptions) -> Result<()>
475486
where
476487
F: FileLike,
477488
LoftyError: From<<F as Truncate>::Error>,
478489
LoftyError: From<<F as Length>::Error>,
479490
{
480-
todo!("Writing matroska tags")
491+
write::write_to(file, self, write_options)
481492
}
482493

483494
pub(crate) fn dump_to<W: Write>(
484495
&self,
485-
_writer: &mut W,
496+
writer: &mut W,
486497
_write_options: WriteOptions,
487498
) -> Result<()> {
488-
todo!("Dumping matroska tags")
499+
let mut buf = Cursor::new(Vec::new());
500+
self.write_element(ElementWriterCtx::default(), &mut buf)?;
501+
writer.write_all(&buf.into_inner())?;
502+
Ok(())
489503
}
490504
}

lofty/src/ebml/tag/tag.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,16 @@ impl Tag<'static> {
122122
}
123123
}
124124

125+
impl<'a> From<&'a Tag<'a>> for TagRef<'a> {
126+
fn from(tag: &'a Tag<'a>) -> Self {
127+
Self {
128+
targets: tag.target.as_ref().map(Into::into).unwrap_or_default(),
129+
simple_tags: tag.simple_tags.iter().map(Cow::Borrowed).collect(),
130+
}
131+
}
132+
}
133+
125134
pub(crate) struct TagRef<'a> {
126135
pub(crate) targets: TargetDescriptor<'a>,
127-
pub(crate) simple_tags: Box<dyn Iterator<Item = Cow<'a, SimpleTag<'a>>>>,
136+
pub(crate) simple_tags: Vec<Cow<'a, SimpleTag<'a>>>,
128137
}

lofty/src/ebml/tag/target.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ impl TargetDescriptor<'_> {
158158
}
159159
}
160160

161+
impl Default for TargetDescriptor<'_> {
162+
fn default() -> Self {
163+
TargetDescriptor::Basic(TargetType::default())
164+
}
165+
}
166+
161167
impl<'a> From<&'a Target> for TargetDescriptor<'a> {
162168
fn from(target: &'a Target) -> Self {
163169
if !target.has_uids() {

lofty/src/ebml/tag/write/elements/attached_file.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const FileReferral_ID: ElementId = ElementId(0x4675);
1111
const FileUsedStartTime_ID: ElementId = ElementId(0x4661);
1212
const FileUsedEndTime_ID: ElementId = ElementId(0x4662);
1313

14+
// Segment\Attachments\AttachedFile
1415
impl WriteableElement for AttachedFile<'_> {
1516
const ID: ElementId = ElementId(0x61A7);
1617

lofty/src/ebml/tag/write/elements/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ pub(super) mod attached_file;
44
pub(super) mod simple_tag;
55
pub(super) mod tags;
66
pub(super) mod target;
7+
mod tag;

lofty/src/ebml/tag/write/elements/simple_tag.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const TagDefault_ID: ElementId = ElementId(0x4484);
99
const TagString_ID: ElementId = ElementId(0x4487);
1010
const TagBinary_ID: ElementId = ElementId(0x4485);
1111

12+
// Segment\Tags\Tag\SimpleTag
1213
impl WriteableElement for SimpleTag<'_> {
1314
const ID: ElementId = ElementId(0x67C8);
1415

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use crate::ebml::tag::write::{ElementWriterCtx, WriteableElement, write_element};
2+
use crate::ebml::{ElementId, TagRef};
3+
use crate::io::FileLike;
4+
5+
use std::io::Cursor;
6+
7+
// Segment\Tags\Tag
8+
impl WriteableElement for TagRef<'_> {
9+
const ID: ElementId = ElementId(0x7373);
10+
11+
fn write_element<F: FileLike>(
12+
&self,
13+
ctx: ElementWriterCtx,
14+
writer: &mut F,
15+
) -> crate::error::Result<()> {
16+
let mut element_children = Cursor::new(Vec::new());
17+
self.targets.write_element(ctx, &mut element_children)?;
18+
19+
for simple_tag in &self.simple_tags {
20+
simple_tag.write_element(ctx, &mut element_children)?;
21+
}
22+
23+
write_element(
24+
ctx,
25+
Self::ID,
26+
&element_children.get_ref().as_slice(),
27+
writer,
28+
)?;
29+
30+
Ok(())
31+
}
32+
}

lofty/src/ebml/tag/write/elements/tags.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
1-
use crate::ebml::tag::write::{ElementWriterCtx, WriteableElement, write_element};
2-
use crate::ebml::{ElementId, TagRef};
1+
use crate::ebml::tag::write::{write_element, ElementWriterCtx, WriteableElement};
2+
use crate::ebml::{ElementId, MatroskaTagRef};
33
use crate::io::FileLike;
44

55
use std::io::Cursor;
66

7-
impl WriteableElement for TagRef<'_> {
8-
const ID: ElementId = ElementId(0x7373);
7+
// Segment\Tags
8+
impl<'a> WriteableElement for MatroskaTagRef<'a>
9+
{
10+
const ID: ElementId = ElementId(0x1254_C367);
911

1012
fn write_element<F: FileLike>(
1113
&self,
1214
ctx: ElementWriterCtx,
1315
writer: &mut F,
1416
) -> crate::error::Result<()> {
1517
let mut element_children = Cursor::new(Vec::new());
16-
self.targets.write_element(ctx, &mut element_children)?;
17-
18-
// TODO
19-
// for simple_tag in self.simple_tags {
20-
// simple_tag.write_element(ctx, &mut element_children)?;
21-
// }
18+
for tag in &self.tags {
19+
tag.write_element(ctx, &mut element_children)?;
20+
}
2221

2322
write_element(
2423
ctx,

lofty/src/ebml/tag/write/elements/target.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const TagEditionUID_ID: ElementId = ElementId(0x63C9);
99
const TagChapterUID_ID: ElementId = ElementId(0x63C4);
1010
const TagAttachmentUID_ID: ElementId = ElementId(0x63C6);
1111

12+
// Segment\Tags\Tag\Targets
1213
impl WriteableElement for TargetDescriptor<'_> {
1314
const ID: ElementId = ElementId(0x63C0);
1415

@@ -93,10 +94,7 @@ mod tests {
9394
let target_descriptor = TargetDescriptor::from(&target);
9495
target_descriptor
9596
.write_element(
96-
ElementWriterCtx {
97-
max_id_len: 4,
98-
max_size_len: 8,
99-
},
97+
ElementWriterCtx::default(),
10098
&mut buf,
10199
)
102100
.unwrap();

lofty/src/ebml/tag/write/mod.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ mod type_encodings;
33

44
use crate::ebml::{ElementId, VInt};
55
use crate::error::Result;
6-
use crate::io::FileLike;
6+
use super::MatroskaTagRef;
7+
use crate::config::WriteOptions;
8+
use crate::error::LoftyError;
9+
use crate::io::{FileLike, Truncate};
710

811
use std::io::Write;
912

@@ -15,6 +18,15 @@ pub(crate) struct ElementWriterCtx {
1518
pub(crate) max_size_len: u8,
1619
}
1720

21+
impl Default for ElementWriterCtx {
22+
fn default() -> Self {
23+
Self {
24+
max_id_len: 4,
25+
max_size_len: 8,
26+
}
27+
}
28+
}
29+
1830
pub(crate) trait EbmlWriteExt: Write + Sized {
1931
fn write_id(&mut self, ctx: ElementWriterCtx, id: ElementId) -> Result<()> {
2032
id.write_to(Some(ctx.max_id_len), self)?;
@@ -46,3 +58,15 @@ pub(crate) fn write_element<W: Write, E: ElementEncodable>(
4658

4759
Ok(())
4860
}
61+
62+
pub(crate) fn write_to<'a, F>(
63+
_file: &mut F,
64+
_tag_ref: &mut MatroskaTagRef<'a>,
65+
_write_options: WriteOptions,
66+
) -> Result<()>
67+
where
68+
F: FileLike,
69+
LoftyError: From<<F as Truncate>::Error>,
70+
{
71+
todo!("Writing Segment\\Tags")
72+
}

0 commit comments

Comments
 (0)