Skip to content

Commit ae5a727

Browse files
uklotzdeSerial-ATA
authored andcommitted
id3v2: Ignore frames with bad IDs while reading
1 parent f1e8ab6 commit ae5a727

File tree

2 files changed

+37
-13
lines changed

2 files changed

+37
-13
lines changed

src/id3/v2/frame/header.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ 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;
67

78
use std::borrow::Cow;
89
use std::io::Read;
910

1011
pub(crate) fn parse_v2_header<R>(
1112
reader: &mut R,
13+
parse_mode: ParsingMode,
1214
) -> Result<Option<(FrameId<'static>, u32, FrameFlags)>>
1315
where
1416
R: Read,
@@ -24,12 +26,20 @@ where
2426
return Ok(None);
2527
}
2628

27-
let frame_id = &frame_header[..3];
28-
let id_str = std::str::from_utf8(frame_id)
29-
.map_err(|_| Id3v2Error::new(Id3v2ErrorKind::BadFrameId(frame_id.to_vec())))?;
30-
let id = upgrade_v2(id_str).map_or_else(|| Cow::Owned(id_str.to_owned()), Cow::Borrowed);
31-
32-
let frame_id = FrameId::new_cow(id)?;
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())
32+
.map(|id_str| {
33+
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+
};
3343

3444
let size = u32::from_be_bytes([0, frame_header[3], frame_header[4], frame_header[5]]);
3545

@@ -40,6 +50,7 @@ where
4050
pub(crate) fn parse_header<R>(
4151
reader: &mut R,
4252
synchsafe: bool,
53+
parse_mode: ParsingMode,
4354
) -> Result<Option<(FrameId<'static>, u32, FrameFlags)>>
4455
where
4556
R: Read,
@@ -64,9 +75,16 @@ where
6475
frame_id_end = 3;
6576
}
6677

67-
let frame_id = &frame_header[..frame_id_end];
68-
let id_str = std::str::from_utf8(&frame_header[..frame_id_end])
69-
.map_err(|_| Id3v2Error::new(Id3v2ErrorKind::BadFrameId(frame_id.to_vec())))?;
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+
};
7088

7189
let mut size = u32::from_be_bytes([
7290
frame_header[4],
@@ -87,7 +105,13 @@ where
87105
} else {
88106
Cow::Owned(id_str.to_owned())
89107
};
90-
let frame_id = FrameId::new_cow(id)?;
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+
};
91115

92116
// unsynch the frame size if necessary
93117
if synchsafe {

src/id3/v2/frame/read.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ impl<'a> Frame<'a> {
2222
{
2323
// The header will be upgraded to ID3v2.4 past this point, so they can all be treated the same
2424
let (id, mut size, mut flags) = match match version {
25-
Id3v2Version::V2 => parse_v2_header(reader)?,
26-
Id3v2Version::V3 => parse_header(reader, false)?,
27-
Id3v2Version::V4 => parse_header(reader, true)?,
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)?,
2828
} {
2929
None => return Ok((None, true)),
3030
Some(frame_header) => frame_header,

0 commit comments

Comments
 (0)