@@ -10,11 +10,16 @@ use crate::mp4::ilst::atom::AtomDataStorage;
1010use crate :: mp4:: read:: { skip_unneeded, AtomReader } ;
1111use crate :: picture:: { MimeType , Picture , PictureType } ;
1212use crate :: util:: text:: utf16_decode;
13+ use crate :: ParsingMode ;
1314
1415use std:: borrow:: Cow ;
1516use std:: io:: { Cursor , Read , Seek , SeekFrom } ;
1617
17- pub ( in crate :: mp4) fn parse_ilst < R > ( reader : & mut AtomReader < R > , len : u64 ) -> Result < Ilst >
18+ pub ( in crate :: mp4) fn parse_ilst < R > (
19+ reader : & mut AtomReader < R > ,
20+ parsing_mode : ParsingMode ,
21+ len : u64 ,
22+ ) -> Result < Ilst >
1823where
1924 R : Read + Seek ,
2025{
@@ -35,12 +40,14 @@ where
3540 continue ;
3641 } ,
3742 b"covr" => {
38- handle_covr ( & mut ilst_reader, & mut tag, & atom) ?;
43+ handle_covr ( & mut ilst_reader, parsing_mode , & mut tag, & atom) ?;
3944 continue ;
4045 } ,
4146 // Upgrade this to a \xa9gen atom
4247 b"gnre" => {
43- if let Some ( atom_data) = parse_data_inner ( & mut ilst_reader, & atom) ? {
48+ if let Some ( atom_data) =
49+ parse_data_inner ( & mut ilst_reader, parsing_mode, & atom) ?
50+ {
4451 let mut data = Vec :: new ( ) ;
4552
4653 for ( _, content) in atom_data {
7077 // Special case the "Album ID", as it has the code "BE signed integer" (21), but
7178 // must be interpreted as a "BE 64-bit Signed Integer" (74)
7279 b"plID" => {
73- if let Some ( atom_data) = parse_data_inner ( & mut ilst_reader, & atom) ? {
80+ if let Some ( atom_data) =
81+ parse_data_inner ( & mut ilst_reader, parsing_mode, & atom) ?
82+ {
7483 let mut data = Vec :: new ( ) ;
7584
7685 for ( code, content) in atom_data {
98107 continue ;
99108 } ,
100109 b"cpil" | b"hdvd" | b"pcst" | b"pgap" | b"shwm" => {
101- if let Some ( atom_data) = parse_data_inner ( & mut ilst_reader, & atom) ? {
110+ if let Some ( atom_data) =
111+ parse_data_inner ( & mut ilst_reader, parsing_mode, & atom) ?
112+ {
102113 if let Some ( ( _, content) ) = atom_data. first ( ) {
103114 let data = match content[ ..] {
104115 [ 0 , ..] => AtomData :: Bool ( false ) ,
@@ -118,17 +129,22 @@ where
118129 }
119130 }
120131
121- parse_data ( & mut ilst_reader, & mut tag, atom) ?;
132+ parse_data ( & mut ilst_reader, parsing_mode , & mut tag, atom) ?;
122133 }
123134
124135 Ok ( tag)
125136}
126137
127- fn parse_data < R > ( reader : & mut AtomReader < R > , tag : & mut Ilst , atom_info : AtomInfo ) -> Result < ( ) >
138+ fn parse_data < R > (
139+ reader : & mut AtomReader < R > ,
140+ parsing_mode : ParsingMode ,
141+ tag : & mut Ilst ,
142+ atom_info : AtomInfo ,
143+ ) -> Result < ( ) >
128144where
129145 R : Read + Seek ,
130146{
131- if let Some ( mut atom_data) = parse_data_inner ( reader, & atom_info) ? {
147+ if let Some ( mut atom_data) = parse_data_inner ( reader, parsing_mode , & atom_info) ? {
132148 // Most atoms we encounter are only going to have 1 value, so store them as such
133149 if atom_data. len ( ) == 1 {
134150 let ( flags, content) = atom_data. remove ( 0 ) ;
@@ -157,8 +173,11 @@ where
157173 Ok ( ( ) )
158174}
159175
176+ const DATA_ATOM_IDENT : AtomIdent < ' static > = AtomIdent :: Fourcc ( * b"data" ) ;
177+
160178fn parse_data_inner < R > (
161179 reader : & mut AtomReader < R > ,
180+ parsing_mode : ParsingMode ,
162181 atom_info : & AtomInfo ,
163182) -> Result < Option < Vec < ( u32 , Vec < u8 > ) > > >
164183where
@@ -170,11 +189,7 @@ where
170189 let to_read = ( atom_info. start + atom_info. len ) - reader. stream_position ( ) ?;
171190 let mut pos = 0 ;
172191 while pos < to_read {
173- let data_atom = reader. next ( ) ?;
174- match data_atom. ident {
175- AtomIdent :: Fourcc ( ref name) if name == b"data" => { } ,
176- _ => err ! ( BadAtom ( "Expected atom \" data\" to follow name" ) ) ,
177- }
192+ let next_atom = reader. next ( ) ?;
178193
179194 // We don't care about the version
180195 let _version = reader. read_u8 ( ) ?;
@@ -187,17 +202,32 @@ where
187202 // We don't care about the locale
188203 reader. seek ( SeekFrom :: Current ( 4 ) ) ?;
189204
190- let content_len = ( data_atom. len - 16 ) as usize ;
191- if content_len == 0 {
192- // We won't add empty atoms
193- return Ok ( None ) ;
205+ match next_atom. ident {
206+ DATA_ATOM_IDENT => {
207+ debug_assert ! ( next_atom. len >= 16 ) ;
208+ let content_len = ( next_atom. len - 16 ) as usize ;
209+ if content_len > 0 {
210+ let mut content = try_vec ! [ 0 ; content_len] ;
211+ reader. read_exact ( & mut content) ?;
212+ ret. push ( ( flags, content) ) ;
213+ } else {
214+ log:: warn!( "Skipping empty \" data\" atom" ) ;
215+ }
216+ } ,
217+ _ => match parsing_mode {
218+ ParsingMode :: Strict => {
219+ err ! ( BadAtom ( "Expected atom \" data\" to follow name" ) )
220+ } ,
221+ ParsingMode :: BestAttempt | ParsingMode :: Relaxed => {
222+ log:: warn!(
223+ "Skipping unexpected atom {actual_ident:?}, expected {expected_ident:?}" ,
224+ actual_ident = next_atom. ident,
225+ expected_ident = DATA_ATOM_IDENT
226+ )
227+ } ,
228+ } ,
194229 }
195-
196- let mut content = try_vec ! [ 0 ; content_len] ;
197- reader. read_exact ( & mut content) ?;
198-
199- pos += data_atom. len ;
200- ret. push ( ( flags, content) ) ;
230+ pos += next_atom. len ;
201231 }
202232
203233 let ret = if ret. is_empty ( ) { None } else { Some ( ret) } ;
@@ -228,11 +258,16 @@ fn parse_int(bytes: &[u8]) -> Result<i32> {
228258 } )
229259}
230260
231- fn handle_covr < R > ( reader : & mut AtomReader < R > , tag : & mut Ilst , atom_info : & AtomInfo ) -> Result < ( ) >
261+ fn handle_covr < R > (
262+ reader : & mut AtomReader < R > ,
263+ parsing_mode : ParsingMode ,
264+ tag : & mut Ilst ,
265+ atom_info : & AtomInfo ,
266+ ) -> Result < ( ) >
232267where
233268 R : Read + Seek ,
234269{
235- if let Some ( atom_data) = parse_data_inner ( reader, atom_info) ? {
270+ if let Some ( atom_data) = parse_data_inner ( reader, parsing_mode , atom_info) ? {
236271 let mut data = Vec :: new ( ) ;
237272
238273 let len = atom_data. len ( ) ;
0 commit comments