ID3v2: Pass parsing mode to frame parsing

This commit is contained in:
Serial 2023-06-03 10:07:32 -04:00 committed by Alex
parent 464be3cb14
commit 21aa7d929d
11 changed files with 48 additions and 25 deletions

View file

@ -48,7 +48,7 @@ where
stream_len -= u64::from(header.size);
let id3v2 = parse_id3v2(reader, header)?;
let id3v2 = parse_id3v2(reader, header, parse_mode)?;
if let Some(existing_tag) = &mut file.id3v2_tag {
// https://github.com/Serial-ATA/lofty-rs/issues/87
// Duplicate tags should have their frames appended to the previous

View file

@ -40,7 +40,7 @@ where
let reader = &mut &*content;
let id3v2 = parse_id3v2(reader, header)?;
let id3v2 = parse_id3v2(reader, header, parse_options.parsing_mode)?;
id3v2_tag = Some(id3v2);
}

View file

@ -51,7 +51,7 @@ where
if let ID3FindResults(Some(header), Some(content)) = find_id3v2(data, true)? {
let reader = &mut &*content;
let id3v2 = parse_id3v2(reader, header)?;
let id3v2 = parse_id3v2(reader, header, parse_options.parsing_mode)?;
flac_file.id3v2_tag = Some(id3v2);
}

View file

@ -6,6 +6,7 @@ use crate::id3::v2::items::{
};
use crate::id3::v2::Id3v2Version;
use crate::macros::err;
use crate::probe::ParsingMode;
use crate::util::text::TextEncoding;
use std::io::Read;
@ -15,6 +16,7 @@ pub(super) fn parse_content<R: Read>(
reader: &mut R,
id: &str,
version: Id3v2Version,
parse_mode: ParsingMode,
) -> Result<Option<FrameValue>> {
Ok(match id {
// The ID was previously upgraded, but the content remains unchanged, so version is necessary

View file

@ -5,13 +5,18 @@ use crate::id3::v2::frame::content::parse_content;
use crate::id3::v2::util::synchsafe::{SynchsafeInteger, UnsynchronizedStream};
use crate::id3::v2::{FrameFlags, FrameId, FrameValue, Id3v2Version};
use crate::macros::try_vec;
use crate::probe::ParsingMode;
use std::io::Read;
use byteorder::{BigEndian, ReadBytesExt};
impl<'a> Frame<'a> {
pub(crate) fn read<R>(reader: &mut R, version: Id3v2Version) -> Result<(Option<Self>, bool)>
pub(crate) fn read<R>(
reader: &mut R,
version: Id3v2Version,
parse_mode: ParsingMode,
) -> Result<(Option<Self>, bool)>
where
R: Read,
{
@ -91,14 +96,14 @@ impl<'a> Frame<'a> {
return handle_encryption(&mut compression_reader, size, id, flags);
}
return parse_frame(&mut compression_reader, id, flags, version);
return parse_frame(&mut compression_reader, id, flags, version, parse_mode);
}
if flags.encryption.is_some() {
return handle_encryption(&mut unsynchronized_reader, size, id, flags);
}
return parse_frame(&mut unsynchronized_reader, id, flags, version);
return parse_frame(&mut unsynchronized_reader, id, flags, version, parse_mode);
},
// Possible combinations:
//
@ -113,7 +118,7 @@ impl<'a> Frame<'a> {
return handle_encryption(&mut compression_reader, size, id, flags);
}
return parse_frame(&mut compression_reader, id, flags, version);
return parse_frame(&mut compression_reader, id, flags, version, parse_mode);
},
// Possible combinations:
//
@ -126,7 +131,7 @@ impl<'a> Frame<'a> {
},
// Everything else that doesn't have special flags
_ => {
return parse_frame(&mut reader, id, flags, version);
return parse_frame(&mut reader, id, flags, version, parse_mode);
},
}
}
@ -172,8 +177,9 @@ fn parse_frame<R: Read>(
id: FrameId<'static>,
flags: FrameFlags,
version: Id3v2Version,
parse_mode: ParsingMode,
) -> Result<(Option<Frame<'static>>, bool)> {
match parse_content(reader, id.as_str(), version)? {
match parse_content(reader, id.as_str(), version, parse_mode)? {
Some(value) => Ok((Some(Frame { id, value, flags }), false)),
None => Ok((None, false)),
}

View file

@ -3,10 +3,15 @@ use super::tag::Id3v2Tag;
use super::Id3v2Header;
use crate::error::Result;
use crate::id3::v2::util::synchsafe::UnsynchronizedStream;
use crate::probe::ParsingMode;
use std::io::Read;
pub(crate) fn parse_id3v2<R>(bytes: &mut R, header: Id3v2Header) -> Result<Id3v2Tag>
pub(crate) fn parse_id3v2<R>(
bytes: &mut R,
header: Id3v2Header,
parse_mode: ParsingMode,
) -> Result<Id3v2Tag>
where
R: Read,
{
@ -16,12 +21,12 @@ where
if header.flags.unsynchronisation {
// Unsynchronize the entire tag
let mut unsyncronized_reader = UnsynchronizedStream::new(tag_bytes);
ret = read_all_frames_into_tag(&mut unsyncronized_reader, header)?;
ret = read_all_frames_into_tag(&mut unsyncronized_reader, header, parse_mode)?;
// Get the `Take` back from the `UnsynchronizedStream`
tag_bytes = unsyncronized_reader.into_inner();
} else {
ret = read_all_frames_into_tag(&mut tag_bytes, header)?;
ret = read_all_frames_into_tag(&mut tag_bytes, header, parse_mode)?;
};
// Throw away the rest of the tag (padding, bad frames)
@ -29,7 +34,11 @@ where
Ok(ret)
}
fn read_all_frames_into_tag<R>(reader: &mut R, header: Id3v2Header) -> Result<Id3v2Tag>
fn read_all_frames_into_tag<R>(
reader: &mut R,
header: Id3v2Header,
parse_mode: ParsingMode,
) -> Result<Id3v2Tag>
where
R: Read,
{
@ -38,7 +47,7 @@ where
tag.set_flags(header.flags);
loop {
match Frame::read(reader, header.version)? {
match Frame::read(reader, header.version, parse_mode)? {
// No frame content found, and we can expect there are no more frames
(None, true) => break,
(Some(f), false) => drop(tag.insert(f)),
@ -53,9 +62,10 @@ where
#[test]
fn zero_size_id3v2() {
use crate::id3::v2::read_id3v2_header;
use crate::ParsingMode;
use std::io::Cursor;
let mut f = Cursor::new(std::fs::read("tests/tags/assets/id3v2/zero.id3v2").unwrap());
let header = read_id3v2_header(&mut f).unwrap();
assert!(parse_id3v2(&mut f, header).is_ok());
assert!(parse_id3v2(&mut f, header, ParsingMode::Strict).is_ok());
}

View file

@ -1068,6 +1068,7 @@ impl<'a, I: Iterator<Item = FrameRef<'a>> + Clone + 'a> Id3v2TagRef<'a, I> {
#[cfg(test)]
mod tests {
use crate::ParsingMode;
use std::borrow::Cow;
use crate::id3::v2::frame::MUSICBRAINZ_UFID_OWNER;
@ -1095,7 +1096,7 @@ mod tests {
let mut reader = std::io::Cursor::new(&tag_bytes[..]);
let header = read_id3v2_header(&mut reader).unwrap();
crate::id3::v2::read::parse_id3v2(&mut reader, header).unwrap()
crate::id3::v2::read::parse_id3v2(&mut reader, header, ParsingMode::Strict).unwrap()
}
#[test]
@ -1206,7 +1207,9 @@ mod tests {
let temp_reader = &mut &*writer;
let temp_header = read_id3v2_header(temp_reader).unwrap();
let temp_parsed_tag = crate::id3::v2::read::parse_id3v2(temp_reader, temp_header).unwrap();
let temp_parsed_tag =
crate::id3::v2::read::parse_id3v2(temp_reader, temp_header, ParsingMode::Strict)
.unwrap();
assert_eq!(parsed_tag, temp_parsed_tag);
}
@ -1456,7 +1459,7 @@ mod tests {
let mut reader = &mut &writer[..];
let header = read_id3v2_header(&mut reader).unwrap();
assert!(crate::id3::v2::read::parse_id3v2(reader, header).is_ok());
assert!(crate::id3::v2::read::parse_id3v2(reader, header, ParsingMode::Strict).is_ok());
assert_eq!(writer[3..10], writer[writer.len() - 7..])
}
@ -1481,7 +1484,7 @@ mod tests {
let mut reader = &mut &writer[..];
let header = read_id3v2_header(&mut reader).unwrap();
let tag = crate::id3::v2::read::parse_id3v2(reader, header).unwrap();
let tag = crate::id3::v2::read::parse_id3v2(reader, header, ParsingMode::Strict).unwrap();
assert_eq!(tag.len(), 1);
assert_eq!(
@ -1798,7 +1801,8 @@ mod tests {
let mut reader = std::io::Cursor::new(&content[..]);
let header = read_id3v2_header(&mut reader).unwrap();
let reparsed = crate::id3::v2::read::parse_id3v2(&mut reader, header).unwrap();
let reparsed =
crate::id3::v2::read::parse_id3v2(&mut reader, header, ParsingMode::Strict).unwrap();
assert_eq!(id3v2, reparsed);
}

View file

@ -52,7 +52,7 @@ where
while chunks.next(data).is_ok() {
match &chunks.fourcc {
b"ID3 " | b"id3 " => {
let tag = chunks.id3_chunk(data)?;
let tag = chunks.id3_chunk(data, parse_options.parsing_mode)?;
if let Some(existing_tag) = id3v2_tag.as_mut() {
// https://github.com/Serial-ATA/lofty-rs/issues/87
// Duplicate tags should have their frames appended to the previous

View file

@ -1,6 +1,7 @@
use crate::error::Result;
use crate::id3::v2::tag::Id3v2Tag;
use crate::macros::{err, try_vec};
use crate::probe::ParsingMode;
use std::io::{Read, Seek, SeekFrom};
use std::marker::PhantomData;
@ -91,7 +92,7 @@ impl<B: ByteOrder> Chunks<B> {
Ok(content)
}
pub fn id3_chunk<R>(&mut self, data: &mut R) -> Result<Id3v2Tag>
pub fn id3_chunk<R>(&mut self, data: &mut R, parse_mode: ParsingMode) -> Result<Id3v2Tag>
where
R: Read + Seek,
{
@ -103,7 +104,7 @@ impl<B: ByteOrder> Chunks<B> {
let reader = &mut &*content;
let header = read_id3v2_header(reader)?;
let id3v2 = parse_id3v2(reader, header)?;
let id3v2 = parse_id3v2(reader, header, parse_mode)?;
// Skip over the footer
if id3v2.flags().footer {

View file

@ -88,7 +88,7 @@ where
}
},
b"ID3 " | b"id3 " => {
let tag = chunks.id3_chunk(data)?;
let tag = chunks.id3_chunk(data, parse_options.parsing_mode)?;
if let Some(existing_tag) = id3v2_tag.as_mut() {
// https://github.com/Serial-ATA/lofty-rs/issues/87
// Duplicate tags should have their frames appended to the previous

View file

@ -41,7 +41,7 @@ where
let header = read_id3v2_header(reader)?;
let skip_footer = header.flags.footer;
let id3v2 = parse_id3v2(reader, header)?;
let id3v2 = parse_id3v2(reader, header, parse_options.parsing_mode)?;
if let Some(existing_tag) = &mut file.id3v2_tag {
// https://github.com/Serial-ATA/lofty-rs/issues/87
// Duplicate tags should have their frames appended to the previous