mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2025-01-19 07:33:53 +00:00
EBML: Bring branch up to date
This commit is contained in:
parent
f27d7c3682
commit
dd93d9d211
16 changed files with 71 additions and 31 deletions
|
@ -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
|
||||
|
|
|
@ -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."),
|
||||
);
|
|
@ -2,7 +2,7 @@
|
|||
mod element_reader;
|
||||
mod properties;
|
||||
mod read;
|
||||
mod tag;
|
||||
pub(crate) mod tag;
|
||||
mod vint;
|
||||
|
||||
use lofty_attr::LoftyFile;
|
|
@ -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};
|
||||
|
|
@ -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};
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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};
|
||||
|
|
@ -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!()
|
||||
}
|
||||
|
|
@ -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)?;
|
||||
///
|
|
@ -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,
|
||||
|
|
|
@ -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 {}
|
||||
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()?;
|
||||
|
||||
|
|
|
@ -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
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue