Skip to content

Commit 6549e92

Browse files
uklotzdeSerial-ATA
authored andcommitted
id3v2: Don't stop reading after skipping a frame
1 parent ae5a727 commit 6549e92

File tree

3 files changed

+62
-70
lines changed

3 files changed

+62
-70
lines changed

src/id3/v2/frame/header.rs

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,95 +3,73 @@ use crate::error::{Id3v2Error, Id3v2ErrorKind, Result};
33
use crate::id3::v2::util::synchsafe::SynchsafeInteger;
44
use crate::id3::v2::util::upgrade::{upgrade_v2, upgrade_v3};
55
use crate::id3::v2::FrameId;
6-
use crate::ParsingMode;
76

87
use std::borrow::Cow;
98
use std::io::Read;
109

1110
pub(crate) fn parse_v2_header<R>(
1211
reader: &mut R,
13-
parse_mode: ParsingMode,
1412
) -> Result<Option<(FrameId<'static>, u32, FrameFlags)>>
1513
where
1614
R: Read,
1715
{
18-
let mut frame_header = [0; 6];
19-
match reader.read_exact(&mut frame_header) {
16+
let mut header = [0; 6];
17+
match reader.read_exact(&mut header) {
2018
Ok(_) => {},
2119
Err(_) => return Ok(None),
2220
}
2321

2422
// Assume we just started reading padding
25-
if frame_header[0] == 0 {
23+
if header[0] == 0 {
2624
return Ok(None);
2725
}
2826

29-
let frame_id_bytes = &frame_header[..3];
30-
let frame_id = match std::str::from_utf8(frame_id_bytes)
31-
.map_err(|_| Id3v2Error::new(Id3v2ErrorKind::BadFrameId(frame_id_bytes.to_vec())).into())
27+
let id_bytes = &header[..3];
28+
let id_str = std::str::from_utf8(id_bytes)
29+
.map_err(|_| Id3v2Error::new(Id3v2ErrorKind::BadFrameId(id_bytes.to_vec())))
3230
.map(|id_str| {
3331
upgrade_v2(id_str).map_or_else(|| Cow::Owned(id_str.to_owned()), Cow::Borrowed)
34-
})
35-
.and_then(FrameId::new_cow)
36-
{
37-
Ok(id) => id,
38-
Err(err) => match parse_mode {
39-
ParsingMode::Strict => return Err(err),
40-
ParsingMode::BestAttempt | ParsingMode::Relaxed => return Ok(None),
41-
},
42-
};
32+
})?;
33+
let id = FrameId::new_cow(id_str)?;
4334

44-
let size = u32::from_be_bytes([0, frame_header[3], frame_header[4], frame_header[5]]);
35+
let size = u32::from_be_bytes([0, header[3], header[4], header[5]]);
4536

4637
// V2 doesn't store flags
47-
Ok(Some((frame_id, size, FrameFlags::default())))
38+
Ok(Some((id, size, FrameFlags::default())))
4839
}
4940

5041
pub(crate) fn parse_header<R>(
5142
reader: &mut R,
5243
synchsafe: bool,
53-
parse_mode: ParsingMode,
5444
) -> Result<Option<(FrameId<'static>, u32, FrameFlags)>>
5545
where
5646
R: Read,
5747
{
58-
let mut frame_header = [0; 10];
59-
match reader.read_exact(&mut frame_header) {
48+
let mut header = [0; 10];
49+
match reader.read_exact(&mut header) {
6050
Ok(_) => {},
6151
Err(_) => return Ok(None),
6252
}
6353

6454
// Assume we just started reading padding
65-
if frame_header[0] == 0 {
55+
if header[0] == 0 {
6656
return Ok(None);
6757
}
6858

6959
// For some reason, some apps make v3 tags with v2 frame IDs.
7060
// The actual frame header is v3 though
71-
let mut frame_id_end = 4;
61+
let mut id_end = 4;
7262
let mut invalid_v2_frame = false;
73-
if frame_header[3] == 0 && !synchsafe {
63+
if header[3] == 0 && !synchsafe {
7464
invalid_v2_frame = true;
75-
frame_id_end = 3;
65+
id_end = 3;
7666
}
7767

78-
let frame_id_bytes = &frame_header[..frame_id_end];
79-
let id_str = match std::str::from_utf8(frame_id_bytes)
80-
.map_err(|_| Id3v2Error::new(Id3v2ErrorKind::BadFrameId(frame_id_bytes.to_vec())).into())
81-
{
82-
Ok(id_str) => id_str,
83-
Err(err) => match parse_mode {
84-
ParsingMode::Strict => return Err(err),
85-
ParsingMode::BestAttempt | ParsingMode::Relaxed => return Ok(None),
86-
},
87-
};
68+
let id_bytes = &header[..id_end];
69+
let id_str = std::str::from_utf8(id_bytes)
70+
.map_err(|_| Id3v2Error::new(Id3v2ErrorKind::BadFrameId(id_bytes.to_vec())))?;
8871

89-
let mut size = u32::from_be_bytes([
90-
frame_header[4],
91-
frame_header[5],
92-
frame_header[6],
93-
frame_header[7],
94-
]);
72+
let mut size = u32::from_be_bytes([header[4], header[5], header[6], header[7]]);
9573

9674
// Now upgrade the FrameId
9775
let id = if invalid_v2_frame {
@@ -105,20 +83,14 @@ where
10583
} else {
10684
Cow::Owned(id_str.to_owned())
10785
};
108-
let frame_id = match FrameId::new_cow(id) {
109-
Ok(frame_id) => frame_id,
110-
Err(err) => match parse_mode {
111-
ParsingMode::Strict => return Err(err),
112-
ParsingMode::BestAttempt | ParsingMode::Relaxed => return Ok(None),
113-
},
114-
};
86+
let frame_id = FrameId::new_cow(id)?;
11587

11688
// unsynch the frame size if necessary
11789
if synchsafe {
11890
size = size.unsynch();
11991
}
12092

121-
let flags = u16::from_be_bytes([frame_header[8], frame_header[9]]);
93+
let flags = u16::from_be_bytes([header[8], header[9]]);
12294
let flags = parse_flags(flags, synchsafe);
12395

12496
Ok(Some((frame_id, size, flags)))

src/id3/v2/frame/read.rs

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,43 @@ use std::io::Read;
1111

1212
use byteorder::{BigEndian, ReadBytesExt};
1313

14-
impl<'a> Frame<'a> {
14+
pub(crate) enum ParsedFrame<'a> {
15+
Next(Frame<'a>),
16+
Skipped,
17+
Eof,
18+
}
19+
20+
impl<'a> ParsedFrame<'a> {
1521
pub(crate) fn read<R>(
1622
reader: &mut R,
1723
version: Id3v2Version,
1824
parse_mode: ParsingMode,
19-
) -> Result<(Option<Self>, bool)>
25+
) -> Result<Self>
2026
where
2127
R: Read,
2228
{
2329
// The header will be upgraded to ID3v2.4 past this point, so they can all be treated the same
24-
let (id, mut size, mut flags) = match match version {
25-
Id3v2Version::V2 => parse_v2_header(reader, parse_mode)?,
26-
Id3v2Version::V3 => parse_header(reader, false, parse_mode)?,
27-
Id3v2Version::V4 => parse_header(reader, true, parse_mode)?,
28-
} {
29-
None => return Ok((None, true)),
30-
Some(frame_header) => frame_header,
30+
let parse_header_result = match version {
31+
Id3v2Version::V2 => parse_v2_header(reader),
32+
Id3v2Version::V3 => parse_header(reader, false),
33+
Id3v2Version::V4 => parse_header(reader, true),
34+
};
35+
let (id, mut size, mut flags) = match parse_header_result {
36+
Ok(None) => {
37+
// Stop reading
38+
return Ok(Self::Eof);
39+
},
40+
Ok(Some(some)) => some,
41+
Err(err) => {
42+
match parse_mode {
43+
ParsingMode::Strict => return Err(err),
44+
ParsingMode::BestAttempt | ParsingMode::Relaxed => {
45+
// Skip this frame and continue reading
46+
// TODO: Log error?
47+
return Ok(Self::Skipped);
48+
},
49+
}
50+
},
3151
};
3252

3353
// Get the encryption method symbol
@@ -154,7 +174,7 @@ fn handle_encryption<R: Read>(
154174
size: u32,
155175
id: FrameId<'static>,
156176
flags: FrameFlags,
157-
) -> Result<(Option<Frame<'static>>, bool)> {
177+
) -> Result<ParsedFrame<'static>> {
158178
if flags.data_length_indicator.is_none() {
159179
return Err(Id3v2Error::new(Id3v2ErrorKind::MissingDataLengthIndicator).into());
160180
}
@@ -169,7 +189,7 @@ fn handle_encryption<R: Read>(
169189
};
170190

171191
// Nothing further we can do with encrypted frames
172-
Ok((Some(encrypted_frame), false))
192+
Ok(ParsedFrame::Next(encrypted_frame))
173193
}
174194

175195
fn parse_frame<R: Read>(
@@ -178,9 +198,9 @@ fn parse_frame<R: Read>(
178198
flags: FrameFlags,
179199
version: Id3v2Version,
180200
parse_mode: ParsingMode,
181-
) -> Result<(Option<Frame<'static>>, bool)> {
201+
) -> Result<ParsedFrame<'static>> {
182202
match parse_content(reader, id.as_str(), version, parse_mode)? {
183-
Some(value) => Ok((Some(Frame { id, value, flags }), false)),
184-
None => Ok((None, false)),
203+
Some(value) => Ok(ParsedFrame::Next(Frame { id, value, flags })),
204+
None => Ok(ParsedFrame::Skipped),
185205
}
186206
}

src/id3/v2/read.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::frame::Frame;
1+
use super::frame::read::ParsedFrame;
22
use super::tag::Id3v2Tag;
33
use super::Id3v2Header;
44
use crate::error::Result;
@@ -47,12 +47,12 @@ where
4747
tag.set_flags(header.flags);
4848

4949
loop {
50-
match Frame::read(reader, header.version, parse_mode)? {
50+
match ParsedFrame::read(reader, header.version, parse_mode)? {
51+
ParsedFrame::Next(frame) => drop(tag.insert(frame)),
52+
// No frame content found or ignored due to errors, but we can expect more frames
53+
ParsedFrame::Skipped => continue,
5154
// No frame content found, and we can expect there are no more frames
52-
(None, true) => break,
53-
(Some(f), false) => drop(tag.insert(f)),
54-
// No frame content found, but we can expect more frames
55-
_ => {},
55+
ParsedFrame::Eof => break,
5656
}
5757
}
5858

0 commit comments

Comments
 (0)