ID3v2: Properly handle solidus character (U+002F) in text frames

V2 and V3 allow for the separation of multiple values with the solidus (/) character, while in V4 the separator is null (0). This was not accounted for previously, and would break valid V4 strings ("Foo / Bar" would be split into "Foo " and " Bar").

closes #82
This commit is contained in:
Serial 2022-12-12 13:17:20 -05:00 committed by Alex
parent e24585b420
commit d971615952
3 changed files with 17 additions and 4 deletions

View file

@ -531,7 +531,7 @@ impl From<ID3v2Tag> for Tag {
}), }),
) => { ) => {
let item_key = ItemKey::from_key(TagType::ID3v2, description); let item_key = ItemKey::from_key(TagType::ID3v2, description);
for c in content.split(&['\0', '/'][..]) { for c in content.split('\0') {
tag.items.push(TagItem::new( tag.items.push(TagItem::new(
item_key.clone(), item_key.clone(),
ItemValue::Text(c.to_string()), ItemValue::Text(c.to_string()),
@ -547,7 +547,7 @@ impl From<ID3v2Tag> for Tag {
}), }),
) => { ) => {
let item_key = ItemKey::from_key(TagType::ID3v2, description); let item_key = ItemKey::from_key(TagType::ID3v2, description);
for c in content.split(&['\0', '/'][..]) { for c in content.split('\0') {
tag.items.push(TagItem::new( tag.items.push(TagItem::new(
item_key.clone(), item_key.clone(),
ItemValue::Locator(c.to_string()), ItemValue::Locator(c.to_string()),
@ -562,7 +562,7 @@ impl From<ID3v2Tag> for Tag {
| FrameValue::UnSyncText(LanguageFrame { content, .. }) | FrameValue::UnSyncText(LanguageFrame { content, .. })
| FrameValue::Text { value: content, .. } | FrameValue::Text { value: content, .. }
| FrameValue::UserText(EncodedTextFrame { content, .. }) => { | FrameValue::UserText(EncodedTextFrame { content, .. }) => {
for c in content.split(&['\0', '/'][..]) { for c in content.split('\0') {
tag.items.push(TagItem::new( tag.items.push(TagItem::new(
item_key.clone(), item_key.clone(),
ItemValue::Text(c.to_string()), ItemValue::Text(c.to_string()),
@ -603,7 +603,7 @@ impl From<Tag> for ID3v2Tag {
let mut s = String::with_capacity(iter.size_hint().0); let mut s = String::with_capacity(iter.size_hint().0);
s.push_str(&first); s.push_str(&first);
iter.for_each(|i| { iter.for_each(|i| {
s.push('/'); s.push('\0');
s.push_str(&i); s.push_str(&i);
}); });

Binary file not shown.

View file

@ -52,6 +52,19 @@ fn read_with_junk_bytes_between_frames() {
assert_eq!(id3v1_tag.title(), Some("title test")); assert_eq!(id3v1_tag.title(), Some("title test"));
} }
#[test]
fn issue_82_solidus_in_tag() {
let file = Probe::open("tests/files/assets/issue_82_solidus_in_tag.mp3")
.unwrap()
.read()
.unwrap();
assert_eq!(file.file_type(), FileType::MPEG);
let id3v2_tag = &file.tags()[0];
assert_eq!(id3v2_tag.title(), Some("Foo / title"));
}
#[test] #[test]
fn write() { fn write() {
let mut file = temp_file!("tests/files/assets/minimal/full_test.mp3"); let mut file = temp_file!("tests/files/assets/minimal/full_test.mp3");