Skip to main content

mp4_atom/
any.rs

1use crate::*;
2
3use std::fmt;
4use std::io::Read;
5
6macro_rules! any {
7    (basic: [$($kind:ident,)* $(,)?], boxed: [$($boxed:ident,)* $(,)?]) => {
8        /// Any of the supported atoms.
9        #[derive(Clone, PartialEq)]
10        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11        #[non_exhaustive]
12        pub enum Any {
13            $($kind($kind),)*
14            $($boxed(Box<$boxed>),)*
15            Unknown(FourCC, Vec<u8>),
16        }
17
18        impl Any {
19            /// Get the kind of the atom.
20            pub fn kind(&self) -> FourCC {
21                match self {
22                    $(Any::$kind(_) => $kind::KIND,)*
23                    $(Any::$boxed(_) => $boxed::KIND,)*
24                    Any::Unknown(kind, _) => *kind,
25                }
26            }
27        }
28
29        impl Decode for Any {
30            fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
31                match Self::decode_maybe(buf)? {
32                    Some(any) => Ok(any),
33                    None => Err(Error::OutOfBounds),
34                }
35            }
36        }
37
38        impl DecodeMaybe for Any {
39            fn decode_maybe<B: Buf>(buf: &mut B) -> Result<Option<Self>> {
40                // Decode the header from a view so an incomplete atom leaves
41                // the caller's buffer untouched.
42                let remaining = buf.remaining();
43                let mut peek = buf.slice(remaining);
44                let header = match Header::decode_maybe(&mut peek)? {
45                    Some(header) => header,
46                    None => return Ok(None),
47                };
48
49                let size = header.size.unwrap_or(peek.remaining());
50                if size > peek.remaining() {
51                    return Ok(None);
52                }
53
54                buf.advance(remaining - peek.remaining());
55                Ok(Some(Self::decode_atom(&header, buf)?))
56            }
57        }
58
59        impl Encode for Any {
60            fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
61                buf.encode_atom(self.kind(), |buf| match self {
62                    $(Any::$kind(inner) => Atom::encode_body(inner, buf),)*
63                    $(Any::$boxed(boxed) => Atom::encode_body(boxed.as_ref(), buf),)*
64                    Any::Unknown(_, data) => data.encode(buf),
65                })
66            }
67        }
68
69        impl DecodeAtom for Any {
70            /// Decode the atom from a header and payload.
71            fn decode_atom<B: Buf>(header: &Header, buf: &mut B) -> Result<Self> {
72                let size = header.size.unwrap_or(buf.remaining());
73                if size > buf.remaining() {
74                    return Err(Error::OutOfBounds);
75                }
76
77                let mut body = &mut buf.slice(size);
78
79                let atom = match header.kind {
80                    $(_ if header.kind == $kind::KIND => {
81                        Any::$kind(match $kind::decode_body(&mut body) {
82                            Ok(atom) => atom,
83                            Err(Error::OutOfBounds) => return Err(Error::OverDecode($kind::KIND)),
84                            Err(Error::ShortRead) => return Err(Error::UnderDecode($kind::KIND)),
85                            Err(err) => return Err(err),
86                        })
87                    },)*
88                    $(_ if header.kind == $boxed::KIND => {
89                        Any::$boxed(match $boxed::decode_body(&mut body) {
90                            Ok(atom) => Box::new(atom),
91                            Err(Error::OutOfBounds) => return Err(Error::OverDecode($boxed::KIND)),
92                            Err(Error::ShortRead) => return Err(Error::UnderDecode($boxed::KIND)),
93                            Err(err) => return Err(err),
94                        })
95                    },)*
96                    _ => {
97                        let body = Vec::decode(body)?;
98                        Any::Unknown(header.kind, body)
99                    },
100                };
101
102                if body.has_remaining() {
103                    return Err(Error::UnderDecode(header.kind));
104                }
105
106                buf.advance(size);
107
108                Ok(atom)
109            }
110        }
111
112        impl fmt::Debug for Any {
113            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114                match self {
115                    $(Any::$kind(inner) => inner.fmt(f),)*
116                    $(Any::$boxed(boxed) => boxed.fmt(f),)*
117                    Any::Unknown(kind, body) => write!(f, "Unknown {{ kind: {:?}, size: {:?}, bytes: {:?} }}", kind, body.len(), body),
118                }
119            }
120        }
121
122        $(impl From<$kind> for Any {
123            fn from(inner: $kind) -> Self {
124                Any::$kind(inner)
125            }
126        })*
127
128        $(impl From<$boxed> for Any {
129            fn from(inner: $boxed) -> Self {
130                Any::$boxed(Box::new(inner))
131            }
132        })*
133
134        $(impl TryFrom<Any> for $kind {
135            type Error = Any;
136
137            fn try_from(any: Any) -> std::result::Result<Self, Any> {
138                match any {
139                    Any::$kind(inner) => Ok(inner),
140                    _ => Err(any),
141                }
142            }
143        })*
144
145        $(impl TryFrom<Any> for $boxed {
146            type Error = Any;
147
148            fn try_from(any: Any) -> std::result::Result<Self, Any> {
149                match any {
150                    Any::$boxed(boxed) => Ok(*boxed),
151                    _ => Err(any),
152                }
153            }
154        })*
155
156        // So we can use .into() to automatically unbox
157        $(impl From<Box<$boxed>> for $boxed {
158            fn from(boxed: Box<$boxed>) -> Self {
159                *boxed
160            }
161        })*
162
163        /// A trait to help casting to/from Any.
164        /// From/TryFrom use concrete types, but if we want to use generics, then we need a trait.
165        pub trait AnyAtom: Atom {
166            fn from_any(any: Any) -> Option<Self>;
167            fn from_any_ref(any: &Any) -> Option<&Self>;
168            fn from_any_mut(any: &mut Any) -> Option<&mut Self>;
169
170            fn into_any(self) -> Any;
171        }
172
173        $(impl AnyAtom for $kind {
174            fn from_any(any: Any) -> Option<Self> {
175                match any {
176                    Any::$kind(inner) => Some(inner),
177                    _ => None,
178                }
179            }
180
181            fn from_any_ref(any: &Any) -> Option<&Self> {
182                match any {
183                    Any::$kind(inner) => Some(inner),
184                    _ => None,
185                }
186            }
187
188            fn from_any_mut(any: &mut Any) -> Option<&mut Self> {
189                match any {
190                    Any::$kind(inner) => Some(inner),
191                    _ => None,
192                }
193            }
194
195            fn into_any(self) -> Any {
196                Any::$kind(self)
197            }
198        })*
199
200        $(impl AnyAtom for $boxed {
201            fn from_any(any: Any) -> Option<Self> {
202                match any {
203                    Any::$boxed(boxed) => Some(*boxed),
204                    _ => None,
205                }
206            }
207
208            fn from_any_ref(any: &Any) -> Option<&Self> {
209                match any {
210                    Any::$boxed(boxed) => Some(boxed),
211                    _ => None,
212                }
213            }
214
215            fn from_any_mut(any: &mut Any) -> Option<&mut Self> {
216                match any {
217                    Any::$boxed(boxed) => Some(boxed),
218                    _ => None,
219                }
220            }
221
222            fn into_any(self) -> Any {
223                Any::$boxed(Box::new(self))
224            }
225        })*
226    };
227}
228
229any! {
230    basic: [
231    Ftyp,
232    Styp,
233    Meta,
234        Hdlr,
235        Pitm,
236        Iloc,
237        Iinf,
238        Iprp,
239            Ipco,
240                Auxc,
241                Clap,
242                Imir,
243                Irot,
244                Iscl,
245                Ispe,
246                Pixi,
247                Rref,
248            Ipma,
249        Iref,
250        Idat,
251        Ilst,
252            Covr,
253            Desc,
254            Tool, // "©too"
255            Name,
256            Rtng,
257            Year,
258        Keys,
259    Moov,
260        Mvhd,
261        Ainf,
262        Udta,
263            Cprt,
264            Kind,
265            Skip,
266        // Trak, // boxed to avoid large size differences between variants
267            Tkhd,
268            Mdia,
269                Mdhd,
270                Minf,
271                    Stbl,
272                        Stsd,
273                            Avc1, Avc3,
274                                Avcc,
275                                Btrt,
276                                Ccst,
277                                Colr,
278                                Pasp,
279                                Taic,
280                                Fiel,
281                            Jpeg,
282                            Hev1, Hvc1,
283                                Hvcc, Lhvc,
284                            Mp4a,
285                                Esds,
286                            Mp3,
287                            Tx3g,
288                                Disp,
289                                Ftab,
290                            Vp08, Vp09,
291                                VpcC,
292                            Av01,
293                                Av1c,
294                            Opus,
295                                Dops,
296                            Uncv,
297                                Cmpd,
298                                UncC,
299                            Flac,
300                                Dfla,
301                            Ac3,
302                                Ac3SpecificBox,
303                            Eac3,
304                                Ec3SpecificBox,
305                            Sowt, Twos, Lpcm, Ipcm, Fpcm, In24, In32, Fl32, Fl64, S16l,
306                                PcmC,
307                                Chnl,
308                            Wvtt,
309                                VttC,
310                                Vlab,
311                            Samr,
312                                Damr,
313                            Mett,
314                                TxtC,
315                            Metx,
316                            Urim,
317                                Uri,
318                                UriI,
319                            Camm,
320                            Evte,
321                                Silb,
322                            Mebx,
323                                Keyd,
324                                Dtyp,
325                                Loca,
326                                Setu,
327                        Stts,
328                        Stsc,
329                        Stsz,
330                        Stss,
331                        Stco,
332                        Co64,
333                        Cslg,
334                        Ctts,
335                        Sbgp,
336                        Sgpd,
337                        Subs,
338                        Saio,
339                        Saiz,
340                    Dinf,
341                        Dref,
342                    Hmhd,
343                    Nmhd,
344                    Smhd,
345                    Sthd,
346                    Vmhd,
347            Edts,
348                Elst,
349            Tref,
350        Mvex,
351            Mehd,
352            Trex,
353    Emsg,
354    Moof,
355        Mfhd,
356        Traf,
357            Tfhd,
358            Tfdt,
359            Trun,
360            Senc,
361    Mdat,
362    Free,
363    Sidx,
364    Prft,
365    Mfra,
366        Tfra,
367        Mfro,
368    Uuid,
369    ],
370    boxed: [
371        Trak,
372    ]
373}
374
375impl ReadFrom for Any {
376    fn read_from<R: Read + ?Sized>(r: &mut R) -> Result<Self> {
377        <Option<Any> as ReadFrom>::read_from(r)?.ok_or(Error::UnexpectedEof)
378    }
379}
380
381impl ReadFrom for Option<Any> {
382    fn read_from<R: Read + ?Sized>(r: &mut R) -> Result<Self> {
383        let header = match <Option<Header> as ReadFrom>::read_from(r)? {
384            Some(header) => header,
385            None => return Ok(None),
386        };
387
388        let body = &mut header.read_body(r)?;
389        Ok(Some(Any::decode_atom(&header, body)?))
390    }
391}
392
393impl ReadAtom for Any {
394    fn read_atom<R: Read + ?Sized>(header: &Header, r: &mut R) -> Result<Self> {
395        let body = &mut header.read_body(r)?;
396        Any::decode_atom(header, body)
397    }
398}
399
400#[cfg(test)]
401mod tests {
402    use super::*;
403
404    const PARTIAL_FTYP: &[u8] = b"\0\0\0\x14ftypisom";
405
406    #[test]
407    fn decode_maybe_preserves_incomplete_atom() {
408        let mut buf = PARTIAL_FTYP;
409
410        assert!(Any::decode_maybe(&mut buf).unwrap().is_none());
411        assert_eq!(buf, PARTIAL_FTYP);
412    }
413}