mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-12-13 06:02:32 +00:00
ID3v2: Pass parsing mode to frame parsing
This commit is contained in:
parent
464be3cb14
commit
21aa7d929d
11 changed files with 48 additions and 25 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue