mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-11-10 06:34:18 +00:00
ID3v2: Ignore empty timestamp frames
I had a file with an empty timestamp frame that errored with `ParsingMode::BestAttempt`. Now that's only an error case with `ParsingMode::Strict`.
This commit is contained in:
parent
d4e58ea15d
commit
fcb5446922
2 changed files with 32 additions and 8 deletions
|
@ -96,7 +96,12 @@ impl<'a> TimestampFrame<'a> {
|
||||||
|
|
||||||
let reader = &mut value.as_bytes();
|
let reader = &mut value.as_bytes();
|
||||||
|
|
||||||
frame.timestamp = Timestamp::parse(reader, parse_mode)?;
|
let Some(timestamp) = Timestamp::parse(reader, parse_mode)? else {
|
||||||
|
// Timestamp is empty
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
frame.timestamp = timestamp;
|
||||||
Ok(Some(frame))
|
Ok(Some(frame))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,8 @@ impl FromStr for Timestamp {
|
||||||
type Err = LoftyError;
|
type Err = LoftyError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
Timestamp::parse(&mut s.as_bytes(), ParsingMode::BestAttempt)
|
Timestamp::parse(&mut s.as_bytes(), ParsingMode::BestAttempt)?
|
||||||
|
.ok_or_else(|| LoftyError::new(ErrorKind::BadTimestamp("Timestamp frame is empty")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +87,7 @@ impl Timestamp {
|
||||||
///
|
///
|
||||||
/// * Failure to read from `reader`
|
/// * Failure to read from `reader`
|
||||||
/// * The timestamp is invalid
|
/// * The timestamp is invalid
|
||||||
pub fn parse<R>(reader: &mut R, parse_mode: ParsingMode) -> Result<Self>
|
pub fn parse<R>(reader: &mut R, parse_mode: ParsingMode) -> Result<Option<Self>>
|
||||||
where
|
where
|
||||||
R: Read,
|
R: Read,
|
||||||
{
|
{
|
||||||
|
@ -109,6 +110,14 @@ impl Timestamp {
|
||||||
.take(Self::MAX_LENGTH as u64)
|
.take(Self::MAX_LENGTH as u64)
|
||||||
.read_to_end(&mut content)?;
|
.read_to_end(&mut content)?;
|
||||||
|
|
||||||
|
if content.is_empty() {
|
||||||
|
if parse_mode == ParsingMode::Strict {
|
||||||
|
err!(BadTimestamp("Timestamp frame is empty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
let reader = &mut &content[..];
|
let reader = &mut &content[..];
|
||||||
|
|
||||||
// We need to very that the year is exactly 4 bytes long. This doesn't matter for other segments.
|
// We need to very that the year is exactly 4 bytes long. This doesn't matter for other segments.
|
||||||
|
@ -131,7 +140,7 @@ impl Timestamp {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(timestamp)
|
Ok(Some(timestamp))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn segment<const SIZE: usize>(
|
fn segment<const SIZE: usize>(
|
||||||
|
@ -237,7 +246,7 @@ mod tests {
|
||||||
let parsed_timestamp =
|
let parsed_timestamp =
|
||||||
Timestamp::parse(&mut content.as_bytes(), ParsingMode::Strict).unwrap();
|
Timestamp::parse(&mut content.as_bytes(), ParsingMode::Strict).unwrap();
|
||||||
|
|
||||||
assert_eq!(parsed_timestamp, expected());
|
assert_eq!(parsed_timestamp, Some(expected()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -248,7 +257,7 @@ mod tests {
|
||||||
let parsed_timestamp =
|
let parsed_timestamp =
|
||||||
Timestamp::parse(&mut content.as_bytes(), ParsingMode::BestAttempt).unwrap();
|
Timestamp::parse(&mut content.as_bytes(), ParsingMode::BestAttempt).unwrap();
|
||||||
|
|
||||||
assert_eq!(parsed_timestamp, expected());
|
assert_eq!(parsed_timestamp, Some(expected()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -259,7 +268,7 @@ mod tests {
|
||||||
let parsed_timestamp =
|
let parsed_timestamp =
|
||||||
Timestamp::parse(&mut content.as_bytes(), ParsingMode::BestAttempt).unwrap();
|
Timestamp::parse(&mut content.as_bytes(), ParsingMode::BestAttempt).unwrap();
|
||||||
|
|
||||||
assert_eq!(parsed_timestamp, expected());
|
assert_eq!(parsed_timestamp, Some(expected()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -348,7 +357,17 @@ mod tests {
|
||||||
|
|
||||||
for (data, expected) in partial_timestamps {
|
for (data, expected) in partial_timestamps {
|
||||||
let parsed_timestamp = Timestamp::parse(&mut &data[..], ParsingMode::Strict).unwrap();
|
let parsed_timestamp = Timestamp::parse(&mut &data[..], ParsingMode::Strict).unwrap();
|
||||||
assert_eq!(parsed_timestamp, expected);
|
assert_eq!(parsed_timestamp, Some(expected));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_timestamp() {
|
||||||
|
let empty_timestamp =
|
||||||
|
Timestamp::parse(&mut "".as_bytes(), ParsingMode::BestAttempt).unwrap();
|
||||||
|
assert!(empty_timestamp.is_none());
|
||||||
|
|
||||||
|
let empty_timestamp_strict = Timestamp::parse(&mut "".as_bytes(), ParsingMode::Strict);
|
||||||
|
assert!(empty_timestamp_strict.is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue