diff --git a/src/stream/frame/content.rs b/src/stream/frame/content.rs index 858112fd9..5d1202295 100644 --- a/src/stream/frame/content.rs +++ b/src/stream/frame/content.rs @@ -596,12 +596,21 @@ impl<'a> Decoder<'a> { Some(result) } (Some(_), None) => { - // This can only happen if there is an uneven number of elements. - *last_string = None; - Some(Err(Error::new( - ErrorKind::Parsing, - "uneven number of IPLS strings", - ))) + // This can only happen if there is an uneven number of elements. For + // compatibility, we assume that the missing value is an empty string instead of + // erroring out and failing to parse the entire tag. + // + // This is in line with what the Python mutagen library does. See this issue for + // details: + // - + let first = last_string.take().expect("option must be some"); + let result = first.map(|involvement| { + Some(InvolvedPeopleListItem { + involvement, + involvee: String::new(), + }) + }); + Some(result) } (None, None) => None, }) @@ -1711,7 +1720,28 @@ mod tests { data.extend(bytes_for_encoding("other involvement", *encoding).into_iter()); data.extend(delim_for_encoding(*encoding).into_iter()); // involveee missing here - assert!(decode(frame_id, version, &data[..]).is_err()); + + let content = frame::InvolvedPeopleList { + items: vec![ + InvolvedPeopleListItem { + involvement: "involvement".to_string(), + involvee: "involvee".to_string(), + }, + InvolvedPeopleListItem { + involvement: "other involvement".to_string(), + // Assume empty string if value is missing + involvee: "".to_string(), + }, + ], + }; + assert_eq!( + *decode(frame_id, version, &data[..]) + .unwrap() + .0 + .involved_people_list() + .unwrap(), + content + ); } } diff --git a/src/tag.rs b/src/tag.rs index 8c0f78229..a61a5c4fc 100644 --- a/src/tag.rs +++ b/src/tag.rs @@ -751,6 +751,14 @@ mod tests { let _tag = Tag::read_from_path("testdata/github-issue-91.id3").unwrap(); } + #[test] + fn github_issue_147() { + // Tag contains a broken IPLS frame with an odd value count. We need to handle this + // gracefully without failing to parse the entire tag, because these issue is apparently + // widespread. + let _tag = Tag::read_from_path("testdata/github-issue-147.id3").unwrap(); + } + #[test] fn aiff_read_and_write() { // Copy diff --git a/testdata/github-issue-147.id3 b/testdata/github-issue-147.id3 new file mode 100644 index 000000000..1d0e9e3f9 Binary files /dev/null and b/testdata/github-issue-147.id3 differ