Skip to content

Commit a08a7c8

Browse files
committed
MP4: Skip over invalid ilst atoms by default
Signed-off-by: Serial <[email protected]>
1 parent 487d241 commit a08a7c8

File tree

5 files changed

+59
-15
lines changed

5 files changed

+59
-15
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
### Changed
10+
- **MP4**: Skip over invalid `ilst` atoms by default ([issue](https://github.com/Serial-ATA/lofty-rs/issues/291)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/292))
11+
912
## [0.17.0] - 2023-11-14
1013

1114
### Added

src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! which can be extended at any time.
55
66
use crate::file::FileType;
7-
use crate::ItemKey;
7+
use crate::tag::item::ItemKey;
88

99
use std::collections::TryReserveError;
1010
use std::fmt::{Debug, Display, Formatter};

src/mp4/ilst/mod.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -755,19 +755,27 @@ mod tests {
755755
use crate::tag::utils::test_utils;
756756
use crate::tag::utils::test_utils::read_path;
757757
use crate::{
758-
Accessor as _, AudioFile, ItemKey, ItemValue, ParseOptions, SplitTag as _, Tag,
759-
TagExt as _, TagItem, TagType,
758+
Accessor as _, AudioFile, ItemKey, ItemValue, ParseOptions, ParsingMode, SplitTag as _,
759+
Tag, TagExt as _, TagItem, TagType,
760760
};
761761
use std::io::{Cursor, Read as _, Seek as _, Write as _};
762762

763-
fn read_ilst(path: &str) -> Ilst {
764-
let tag = crate::tag::utils::test_utils::read_path(path);
763+
fn read_ilst(path: &str, parse_mode: ParsingMode) -> Ilst {
764+
let tag = std::fs::read(path).unwrap();
765765
let len = tag.len();
766766

767767
let cursor = Cursor::new(tag);
768-
let mut reader = AtomReader::new(cursor, crate::ParsingMode::Strict).unwrap();
768+
let mut reader = AtomReader::new(cursor, parse_mode).unwrap();
769+
770+
super::read::parse_ilst(&mut reader, parse_mode, len as u64).unwrap()
771+
}
769772

770-
super::read::parse_ilst(&mut reader, crate::ParsingMode::Strict, len as u64).unwrap()
773+
fn read_ilst_strict(path: &str) -> Ilst {
774+
read_ilst(path, ParsingMode::Strict)
775+
}
776+
777+
fn read_ilst_bestattempt(path: &str) -> Ilst {
778+
read_ilst(path, ParsingMode::BestAttempt)
771779
}
772780

773781
fn verify_atom(ilst: &Ilst, ident: [u8; 4], data: &AtomData) {
@@ -843,7 +851,7 @@ mod tests {
843851

844852
#[test]
845853
fn ilst_re_read() {
846-
let parsed_tag = read_ilst("tests/tags/assets/ilst/test.ilst");
854+
let parsed_tag = read_ilst_strict("tests/tags/assets/ilst/test.ilst");
847855

848856
let mut writer = Vec::new();
849857
parsed_tag.dump_to(&mut writer).unwrap();
@@ -935,7 +943,7 @@ mod tests {
935943

936944
#[test]
937945
fn issue_34() {
938-
let ilst = read_ilst("tests/tags/assets/ilst/issue_34.ilst");
946+
let ilst = read_ilst_strict("tests/tags/assets/ilst/issue_34.ilst");
939947

940948
verify_atom(
941949
&ilst,
@@ -954,7 +962,7 @@ mod tests {
954962

955963
#[test]
956964
fn advisory_rating() {
957-
let ilst = read_ilst("tests/tags/assets/ilst/advisory_rating.ilst");
965+
let ilst = read_ilst_strict("tests/tags/assets/ilst/advisory_rating.ilst");
958966

959967
verify_atom(
960968
&ilst,
@@ -1073,7 +1081,7 @@ mod tests {
10731081

10741082
#[test]
10751083
fn multi_value_atom() {
1076-
let ilst = read_ilst("tests/tags/assets/ilst/multi_value_atom.ilst");
1084+
let ilst = read_ilst_strict("tests/tags/assets/ilst/multi_value_atom.ilst");
10771085
let artist_atom = ilst.get(&AtomIdent::Fourcc(*b"\xa9ART")).unwrap();
10781086

10791087
assert_eq!(
@@ -1184,7 +1192,7 @@ mod tests {
11841192

11851193
#[test]
11861194
fn invalid_atom_type() {
1187-
let ilst = read_ilst("tests/tags/assets/ilst/invalid_atom_type.ilst");
1195+
let ilst = read_ilst_strict("tests/tags/assets/ilst/invalid_atom_type.ilst");
11881196

11891197
// The tag contains 3 items, however the last one has an invalid type. We will stop at that point, but retain the
11901198
// first two items.
@@ -1195,4 +1203,19 @@ mod tests {
11951203
assert_eq!(ilst.disk().unwrap(), 1);
11961204
assert_eq!(ilst.disk_total().unwrap(), 2);
11971205
}
1206+
1207+
#[test]
1208+
fn invalid_string_encoding() {
1209+
let ilst = read_ilst_bestattempt("tests/tags/assets/ilst/invalid_string_encoding.ilst");
1210+
1211+
// The tag has an album string with some unknown encoding, but the rest of the tag
1212+
// is valid. We should have all items present except the album.
1213+
assert_eq!(ilst.len(), 3);
1214+
1215+
assert_eq!(ilst.artist().unwrap(), "Foo artist");
1216+
assert_eq!(ilst.title().unwrap(), "Bar title");
1217+
assert_eq!(ilst.comment().unwrap(), "Baz comment");
1218+
1219+
assert!(ilst.album().is_none());
1220+
}
11981221
}

src/mp4/ilst/read.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::constants::{
22
BE_SIGNED_INTEGER, BE_UNSIGNED_INTEGER, BMP, JPEG, PNG, RESERVED, UTF16, UTF8,
33
};
44
use super::{Atom, AtomData, AtomIdent, Ilst};
5-
use crate::error::Result;
5+
use crate::error::{Result, LoftyError};
66
use crate::id3::v1::constants::GENRES;
77
use crate::macros::{err, try_vec};
88
use crate::mp4::atom_info::AtomInfo;
@@ -144,11 +144,25 @@ fn parse_data<R>(
144144
where
145145
R: Read + Seek,
146146
{
147+
let handle_error =
148+
|err: LoftyError, parsing_mode: ParsingMode| -> Result<()> {
149+
match parsing_mode {
150+
ParsingMode::Strict => Err(err),
151+
ParsingMode::BestAttempt | ParsingMode::Relaxed => {
152+
log::warn!("Skipping atom with invalid content: {}", err);
153+
Ok(())
154+
},
155+
}
156+
};
157+
147158
if let Some(mut atom_data) = parse_data_inner(reader, parsing_mode, &atom_info)? {
148159
// Most atoms we encounter are only going to have 1 value, so store them as such
149160
if atom_data.len() == 1 {
150161
let (flags, content) = atom_data.remove(0);
151-
let data = interpret_atom_content(flags, content)?;
162+
let data = match interpret_atom_content(flags, content) {
163+
Ok(data) => data,
164+
Err(err) => return handle_error(err, parsing_mode),
165+
};
152166

153167
tag.atoms.push(Atom {
154168
ident: atom_info.ident,
@@ -160,7 +174,11 @@ where
160174

161175
let mut data = Vec::new();
162176
for (flags, content) in atom_data {
163-
let value = interpret_atom_content(flags, content)?;
177+
let value = match interpret_atom_content(flags, content) {
178+
Ok(data) => data,
179+
Err(err) => return handle_error(err, parsing_mode),
180+
};
181+
164182
data.push(value);
165183
}
166184

146 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)