From 2756c3f89779bbbc651a1704bbde73c719b72904 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Mon, 29 Jul 2024 08:10:01 -0400 Subject: [PATCH] EBML: Bring branch up to date --- lofty/Cargo.toml | 2 +- {src => lofty/src}/ebml/element_reader.rs | 4 +-- {src => lofty/src}/ebml/mod.rs | 2 +- {src => lofty/src}/ebml/properties.rs | 0 {src => lofty/src}/ebml/read.rs | 2 +- {src => lofty/src}/ebml/read/segment.rs | 2 +- {src => lofty/src}/ebml/read/segment_info.rs | 4 +-- .../src}/ebml/read/segment_tracks.rs | 2 +- {src => lofty/src}/ebml/tag/mod.rs | 35 +++++++++++++++---- {src => lofty/src}/ebml/vint.rs | 14 ++++---- lofty/src/file/file_type.rs | 5 +++ lofty/src/tag/split_merge_tag.rs | 4 +++ lofty/src/tag/tag_ext.rs | 2 ++ lofty/src/tag/tag_type.rs | 2 ++ lofty_attr/src/ebml.rs | 8 ++--- lofty_attr/src/lib.rs | 14 +++++--- 16 files changed, 71 insertions(+), 31 deletions(-) rename {src => lofty/src}/ebml/element_reader.rs (99%) rename {src => lofty/src}/ebml/mod.rs (96%) rename {src => lofty/src}/ebml/properties.rs (100%) rename {src => lofty/src}/ebml/read.rs (99%) rename {src => lofty/src}/ebml/read/segment.rs (98%) rename {src => lofty/src}/ebml/read/segment_info.rs (94%) rename {src => lofty/src}/ebml/read/segment_tracks.rs (92%) rename {src => lofty/src}/ebml/tag/mod.rs (66%) rename {src => lofty/src}/ebml/vint.rs (95%) diff --git a/lofty/Cargo.toml b/lofty/Cargo.toml index f7e1c9837..f24bd1153 100644 --- a/lofty/Cargo.toml +++ b/lofty/Cargo.toml @@ -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 diff --git a/src/ebml/element_reader.rs b/lofty/src/ebml/element_reader.rs similarity index 99% rename from src/ebml/element_reader.rs rename to lofty/src/ebml/element_reader.rs index f5f75f415..95e249e85 100644 --- a/src/ebml/element_reader.rs +++ b/lofty/src/ebml/element_reader.rs @@ -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."), ); diff --git a/src/ebml/mod.rs b/lofty/src/ebml/mod.rs similarity index 96% rename from src/ebml/mod.rs rename to lofty/src/ebml/mod.rs index 8cff22456..21d4d0604 100644 --- a/src/ebml/mod.rs +++ b/lofty/src/ebml/mod.rs @@ -2,7 +2,7 @@ mod element_reader; mod properties; mod read; -mod tag; +pub(crate) mod tag; mod vint; use lofty_attr::LoftyFile; diff --git a/src/ebml/properties.rs b/lofty/src/ebml/properties.rs similarity index 100% rename from src/ebml/properties.rs rename to lofty/src/ebml/properties.rs diff --git a/src/ebml/read.rs b/lofty/src/ebml/read.rs similarity index 99% rename from src/ebml/read.rs rename to lofty/src/ebml/read.rs index 903626c50..30b8bacbb 100644 --- a/src/ebml/read.rs +++ b/lofty/src/ebml/read.rs @@ -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}; diff --git a/src/ebml/read/segment.rs b/lofty/src/ebml/read/segment.rs similarity index 98% rename from src/ebml/read/segment.rs rename to lofty/src/ebml/read/segment.rs index 0f07617c1..6947c9c29 100644 --- a/src/ebml/read/segment.rs +++ b/lofty/src/ebml/read/segment.rs @@ -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}; diff --git a/src/ebml/read/segment_info.rs b/lofty/src/ebml/read/segment_info.rs similarity index 94% rename from src/ebml/read/segment_info.rs rename to lofty/src/ebml/read/segment_info.rs index 891f01be3..11ffe4de9 100644 --- a/src/ebml/read/segment_info.rs +++ b/lofty/src/ebml/read/segment_info.rs @@ -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"); } } diff --git a/src/ebml/read/segment_tracks.rs b/lofty/src/ebml/read/segment_tracks.rs similarity index 92% rename from src/ebml/read/segment_tracks.rs rename to lofty/src/ebml/read/segment_tracks.rs index 9852152ab..7ab16f293 100644 --- a/src/ebml/read/segment_tracks.rs +++ b/lofty/src/ebml/read/segment_tracks.rs @@ -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}; diff --git a/src/ebml/tag/mod.rs b/lofty/src/ebml/tag/mod.rs similarity index 66% rename from src/ebml/tag/mod.rs rename to lofty/src/ebml/tag/mod.rs index 0a7c0068d..3a2f83733 100644 --- a/src/ebml/tag/mod.rs +++ b/lofty/src/ebml/tag/mod.rs @@ -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( + &self, + _file: &mut F, + _write_options: WriteOptions, + ) -> std::result::Result<(), Self::Err> + where + F: FileLike, + LoftyError: From<::Error>, + LoftyError: From<::Error>, + { todo!() } - fn dump_to(&self, _writer: &mut W) -> std::result::Result<(), Self::Err> { + fn dump_to( + &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(&self, _file: &mut F) -> std::result::Result<(), Self::Err> + where + F: FileLike, + LoftyError: From<::Error>, + LoftyError: From<::Error>, + { todo!() } diff --git a/src/ebml/vint.rs b/lofty/src/ebml/vint.rs similarity index 95% rename from src/ebml/vint.rs rename to lofty/src/ebml/vint.rs index 831e7d524..d7158b98e 100644 --- a/src/ebml/vint.rs +++ b/lofty/src/ebml/vint.rs @@ -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)?; /// diff --git a/lofty/src/file/file_type.rs b/lofty/src/file/file_type.rs index 30f7a13e8..17c5b6580 100644 --- a/lofty/src/file/file_type.rs +++ b/lofty/src/file/file_type.rs @@ -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, diff --git a/lofty/src/tag/split_merge_tag.rs b/lofty/src/tag/split_merge_tag.rs index 1a76844b7..18f7c623e 100644 --- a/lofty/src/tag/split_merge_tag.rs +++ b/lofty/src/tag/split_merge_tag.rs @@ -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 {} diff --git a/lofty/src/tag/tag_ext.rs b/lofty/src/tag/tag_ext.rs index d7b91e0ec..36d216ab0 100644 --- a/lofty/src/tag/tag_ext.rs +++ b/lofty/src/tag/tag_ext.rs @@ -153,6 +153,7 @@ pub trait TagExt: Accessor + Into + 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 {} diff --git a/lofty/src/tag/tag_type.rs b/lofty/src/tag/tag_type.rs index f995a968d..8d826db1d 100644 --- a/lofty/src/tag/tag_type.rs +++ b/lofty/src/tag/tag_type.rs @@ -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 diff --git a/lofty_attr/src/ebml.rs b/lofty_attr/src/ebml.rs index 37f699086..d8327f3da 100644 --- a/lofty_attr/src/ebml.rs +++ b/lofty_attr/src/ebml.rs @@ -10,7 +10,7 @@ pub(crate) struct EbmlMasterElement { } impl Parse for EbmlMasterElement { - fn parse(input: syn::parse::ParseStream) -> syn::Result { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { let readable_ident = input.parse::()?; 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 { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { let _id_field = input.parse::()?; 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 { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { let readable_ident = input.parse::()?; 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 { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { let id = input.parse::()?.base10_parse()?; let _: syn::Token![,] = input.parse()?; diff --git a/lofty_attr/src/lib.rs b/lofty_attr/src/lib.rs index 7a0789557..068224816 100644 --- a/lofty_attr/src/lib.rs +++ b/lofty_attr/src/lib.rs @@ -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> = once_cell::sync::Lazy::new(|| { - let mut m = std::collections::HashMap::new(); - #( #elements_map_inserts )* - m - }); + fn master_elements() -> &'static ::std::collections::HashMap { + static INSTANCE: ::std::sync::OnceLock<::std::collections::HashMap> = ::std::sync::OnceLock::new(); + INSTANCE.get_or_init(|| { + let mut m = ::std::collections::HashMap::new(); + #( #elements_map_inserts )* + m + }) + } }) }