EBML: Bring branch up to date

This commit is contained in:
Serial 2024-07-29 08:10:01 -04:00
parent f27d7c3682
commit dd93d9d211
No known key found for this signature in database
GPG key ID: DA95198DC17C4568
16 changed files with 71 additions and 31 deletions

View file

@ -18,7 +18,7 @@ byteorder = { workspace = true }
# ID3 compressed frames
flate2 = { version = "1.0.30", optional = true }
# Proc macros
lofty_attr = "0.11.0"
lofty_attr = { path = "../lofty_attr" }
# Debug logging
log = "0.4.22"
# OGG Vorbis/Opus

View file

@ -240,7 +240,7 @@ where
self.ctx.max_id_length,
self.ctx.max_size_length,
)?;
let Some(master) = MASTER_ELEMENTS.get(&header.id) else {
let Some(master) = master_elements().get(&header.id) else {
// We encountered an unknown master element
return Ok(ElementReaderYield::Unknown(header));
};
@ -290,7 +290,7 @@ where
if child.data_type == ElementDataType::Master {
self.store_previous_master();
self.ctx.current_master = Some(
*MASTER_ELEMENTS
*master_elements()
.get(&header.id)
.expect("Nested master elements should be defined at this level."),
);

View file

@ -2,7 +2,7 @@
mod element_reader;
mod properties;
mod read;
mod tag;
pub(crate) mod tag;
mod vint;
use lofty_attr::LoftyFile;

View file

@ -3,12 +3,12 @@ mod segment_info;
mod segment_tracks;
use super::EbmlFile;
use crate::config::ParseOptions;
use crate::ebml::element_reader::{ElementHeader, ElementIdent, ElementReader, ElementReaderYield};
use crate::ebml::vint::VInt;
use crate::ebml::EbmlProperties;
use crate::error::Result;
use crate::macros::decode_err;
use crate::probe::ParseOptions;
use std::io::{Read, Seek};

View file

@ -1,10 +1,10 @@
use super::{segment_info, segment_tracks};
use crate::config::ParseOptions;
use crate::ebml::element_reader::{ElementIdent, ElementReader, ElementReaderYield};
use crate::ebml::properties::EbmlProperties;
use crate::ebml::tag::EbmlTag;
use crate::error::Result;
use crate::macros::decode_err;
use crate::probe::ParseOptions;
use std::io::{Read, Seek};

View file

@ -1,8 +1,8 @@
use crate::config::{ParseOptions, ParsingMode};
use crate::ebml::element_reader::{ElementIdent, ElementReader, ElementReaderYield};
use crate::ebml::properties::EbmlProperties;
use crate::error::Result;
use crate::macros::decode_err;
use crate::probe::ParseOptions;
use std::io::{Read, Seek};
@ -35,7 +35,7 @@ where
if properties.segment_info.timestamp_scale == 0 {
log::warn!("Segment.Info.TimecodeScale is 0, which is invalid");
if parse_options.parsing_mode == crate::probe::ParsingMode::Strict {
if parse_options.parsing_mode == ParsingMode::Strict {
decode_err!(@BAIL Ebml, "Segment.Info.TimecodeScale must be nonzero");
}
}

View file

@ -1,8 +1,8 @@
use crate::config::ParseOptions;
use crate::ebml::element_reader::{ElementIdent, ElementReader, ElementReaderYield};
use crate::ebml::properties::EbmlProperties;
use crate::error::Result;
use crate::macros::decode_err;
use crate::probe::ParseOptions;
use std::io::{Read, Seek};

View file

@ -1,8 +1,8 @@
use crate::config::WriteOptions;
use crate::error::LoftyError;
use crate::tag::Tag;
use crate::traits::{Accessor, MergeTag, SplitTag, TagExt};
use crate::io::{FileLike, Length, Truncate};
use crate::tag::{Accessor, MergeTag, SplitTag, Tag, TagExt, TagType};
use std::fs::File;
use std::io::Write;
use std::ops::Deref;
use std::path::Path;
@ -20,6 +20,11 @@ impl TagExt for EbmlTag {
type Err = LoftyError;
type RefKey<'a> = &'a str;
#[inline]
fn tag_type(&self) -> TagType {
TagType::Ebml
}
fn len(&self) -> usize {
todo!()
}
@ -32,11 +37,24 @@ impl TagExt for EbmlTag {
todo!()
}
fn save_to(&self, _file: &mut File) -> std::result::Result<(), Self::Err> {
fn save_to<F>(
&self,
_file: &mut F,
_write_options: WriteOptions,
) -> std::result::Result<(), Self::Err>
where
F: FileLike,
LoftyError: From<<F as Truncate>::Error>,
LoftyError: From<<F as Length>::Error>,
{
todo!()
}
fn dump_to<W: Write>(&self, _writer: &mut W) -> std::result::Result<(), Self::Err> {
fn dump_to<W: Write>(
&self,
_writer: &mut W,
_write_options: WriteOptions,
) -> std::result::Result<(), Self::Err> {
todo!()
}
@ -44,7 +62,12 @@ impl TagExt for EbmlTag {
todo!()
}
fn remove_from(&self, _file: &mut File) -> std::result::Result<(), Self::Err> {
fn remove_from<F>(&self, _file: &mut F) -> std::result::Result<(), Self::Err>
where
F: FileLike,
LoftyError: From<<F as Truncate>::Error>,
LoftyError: From<<F as Length>::Error>,
{
todo!()
}

View file

@ -33,7 +33,7 @@ impl VInt {
/// ```rust
/// use lofty::ebml::VInt;
///
/// # fn main() -> lofty::Result<()> {
/// # fn main() -> lofty::error::Result<()> {
/// // This value is too large to represent
/// let invalid_vint = VInt::from_u64(u64::MAX);
/// assert!(invalid_vint.is_err());
@ -57,7 +57,7 @@ impl VInt {
/// ```rust
/// use lofty::ebml::VInt;
///
/// # fn main() -> lofty::Result<()> {
/// # fn main() -> lofty::error::Result<()> {
/// let vint = VInt::from_u64(2)?;
/// assert_eq!(vint.value(), 2);
/// # Ok(()) }
@ -80,7 +80,7 @@ impl VInt {
/// ```rust
/// use lofty::ebml::VInt;
///
/// # fn main() -> lofty::Result<()> {
/// # fn main() -> lofty::error::Result<()> {
/// // This octet count (9) is too large to represent
/// let mut invalid_vint_reader = &[0b0000_0000_1];
/// let invalid_vint = VInt::parse(&mut &invalid_vint_reader[..], 8);
@ -128,9 +128,9 @@ impl VInt {
/// ```rust
/// use lofty::ebml::VInt;
///
/// # fn main() -> lofty::Result<()> {
/// # fn main() -> lofty::error::Result<()> {
/// // Parse the EBML header element ID
/// let mut reader = &[0x1A, 0x45, 0xDF, 0xA3];
/// let mut reader = &[0x1A, 0x45, 0xDF, 0xA3][..];
/// let vint = VInt::parse_from_element_id(&mut reader, 8)?;
/// assert_eq!(vint.value(), 0x1A45DFA3);
/// # Ok(()) }
@ -175,7 +175,7 @@ impl VInt {
/// ```rust
/// use lofty::ebml::VInt;
///
/// # fn main() -> lofty::Result<()> {
/// # fn main() -> lofty::error::Result<()> {
/// // Anything <= 254 will fit into a single octet
/// let vint = VInt::from_u64(100)?;
/// assert_eq!(vint.octet_length(), 1);
@ -215,7 +215,7 @@ impl VInt {
/// ```rust
/// use lofty::ebml::VInt;
///
/// # fn main() -> lofty::Result<()> {
/// # fn main() -> lofty::error::Result<()> {
/// let vint = VInt::from_u64(10)?;
/// let bytes = vint.as_bytes(None)?;
///

View file

@ -13,6 +13,7 @@ pub enum FileType {
Aac,
Aiff,
Ape,
Ebml,
Flac,
Mpeg,
Mp4,
@ -52,6 +53,7 @@ impl FileType {
match self {
FileType::Aac | FileType::Aiff | FileType::Mpeg | FileType::Wav => TagType::Id3v2,
FileType::Ape | FileType::Mpc | FileType::WavPack => TagType::Ape,
FileType::Ebml => TagType::Ebml,
FileType::Flac | FileType::Opus | FileType::Vorbis | FileType::Speex => {
TagType::VorbisComments
},
@ -90,6 +92,7 @@ impl FileType {
match tag_type {
TagType::Ape => crate::ape::ApeTag::SUPPORTED_FORMATS.contains(self),
TagType::Ebml => crate::ebml::EbmlTag::SUPPORTED_FORMATS.contains(self),
TagType::Id3v1 => crate::id3::v1::Id3v1Tag::SUPPORTED_FORMATS.contains(self),
TagType::Id3v2 => crate::id3::v2::Id3v2Tag::SUPPORTED_FORMATS.contains(self),
TagType::Mp4Ilst => crate::mp4::Ilst::SUPPORTED_FORMATS.contains(self),
@ -137,6 +140,7 @@ impl FileType {
"opus" => Some(Self::Opus),
"flac" => Some(Self::Flac),
"ogg" => Some(Self::Vorbis),
"mka" | "mkv" | "webm" => Some(Self::Ebml),
"mp4" | "m4a" | "m4b" | "m4p" | "m4r" | "m4v" | "3gp" => Some(Self::Mp4),
"mpc" | "mp+" | "mpp" => Some(Self::Mpc),
"spx" => Some(Self::Speex),
@ -300,6 +304,7 @@ impl FileType {
None
},
119 if buf.len() >= 4 && &buf[..4] == b"wvpk" => Some(Self::WavPack),
26 if buf.starts_with(&[0x1A, 0x45, 0xDF, 0xA3]) => Some(Self::Ebml),
_ if buf.len() >= 8 && &buf[4..8] == b"ftyp" => Some(Self::Mp4),
_ if buf.starts_with(b"MPCK") || buf.starts_with(b"MP+") => Some(Self::Mpc),
_ => None,

View file

@ -70,6 +70,7 @@ pub trait MergeTag: private::Sealed {
// https://rust-lang.github.io/api-guidelines/future-proofing.html#c-sealed
mod private {
use crate::ape::ApeTag;
use crate::ebml::EbmlTag;
use crate::id3::v1::Id3v1Tag;
use crate::id3::v2::Id3v2Tag;
use crate::iff::aiff::AiffTextChunks;
@ -85,6 +86,9 @@ mod private {
impl Sealed for ApeTag {}
impl Sealed for crate::ape::tag::SplitTagRemainder {}
impl Sealed for EbmlTag {}
impl Sealed for crate::ebml::tag::SplitTagRemainder {}
impl Sealed for Id3v1Tag {}
impl Sealed for crate::id3::v1::tag::SplitTagRemainder {}

View file

@ -153,6 +153,7 @@ pub trait TagExt: Accessor + Into<Tag> + Sized + private::Sealed {
// https://rust-lang.github.io/api-guidelines/future-proofing.html#c-sealed
mod private {
use crate::ape::ApeTag;
use crate::ebml::EbmlTag;
use crate::id3::v1::Id3v1Tag;
use crate::id3::v2::Id3v2Tag;
use crate::iff::aiff::AiffTextChunks;
@ -165,6 +166,7 @@ mod private {
impl Sealed for AiffTextChunks {}
impl Sealed for ApeTag {}
impl Sealed for EbmlTag {}
impl Sealed for Id3v1Tag {}
impl Sealed for Id3v2Tag {}
impl Sealed for Ilst {}

View file

@ -15,6 +15,8 @@ use std::path::Path;
pub enum TagType {
/// This covers both APEv1 and APEv2 as it doesn't matter much
Ape,
/// Represents an EBML tag element
Ebml,
/// Represents an ID3v1 tag
Id3v1,
/// This covers all ID3v2 versions since they all get upgraded to ID3v2.4

View file

@ -10,7 +10,7 @@ pub(crate) struct EbmlMasterElement {
}
impl Parse for EbmlMasterElement {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
let readable_ident = input.parse::<Ident>()?;
let _: syn::Token![:] = input.parse()?;
@ -30,7 +30,7 @@ pub(crate) struct EbmlMasterInfo {
}
impl Parse for EbmlMasterInfo {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
let _id_field = input.parse::<Ident>()?;
let _: syn::Token![:] = input.parse()?;
@ -60,7 +60,7 @@ pub(crate) struct EbmlChildElement {
}
impl Parse for EbmlChildElement {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
let readable_ident = input.parse::<Ident>()?;
let _: syn::Token![:] = input.parse()?;
@ -80,7 +80,7 @@ pub(crate) struct EbmlChildInfo {
}
impl Parse for EbmlChildInfo {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
let id = input.parse::<syn::LitInt>()?.base10_parse()?;
let _: syn::Token![,] = input.parse()?;

View file

@ -44,6 +44,7 @@ use crate::lofty_file::LoftyFile;
use crate::lofty_tag::{LoftyTag, LoftyTagAttribute};
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemStruct};
/// Creates a file usable by Lofty
@ -111,10 +112,13 @@ pub fn ebml_master_elements(input: TokenStream) -> TokenStream {
#( #identifiers_iter ),*
}
static MASTER_ELEMENTS: once_cell::sync::Lazy<std::collections::HashMap<VInt, MasterElement>> = once_cell::sync::Lazy::new(|| {
let mut m = std::collections::HashMap::new();
#( #elements_map_inserts )*
m
});
fn master_elements() -> &'static ::std::collections::HashMap<VInt, MasterElement> {
static INSTANCE: ::std::sync::OnceLock<::std::collections::HashMap<VInt, MasterElement>> = ::std::sync::OnceLock::new();
INSTANCE.get_or_init(|| {
let mut m = ::std::collections::HashMap::new();
#( #elements_map_inserts )*
m
})
}
})
}