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                                Ftab,
289                            Vp08, Vp09,
290                                VpcC,
291                            Av01,
292                                Av1c,
293                            Opus,
294                                Dops,
295                            Uncv,
296                                Cmpd,
297                                UncC,
298                            Flac,
299                                Dfla,
300                            Ac3,
301                                Ac3SpecificBox,
302                            Eac3,
303                                Ec3SpecificBox,
304                            Sowt, Twos, Lpcm, Ipcm, Fpcm, In24, In32, Fl32, Fl64, S16l,
305                                PcmC,
306                                Chnl,
307                            Wvtt,
308                                VttC,
309                                Vlab,
310                            Samr,
311                                Damr,
312                            Mett,
313                                TxtC,
314                            Metx,
315                            Urim,
316                                Uri,
317                                UriI,
318                            Camm,
319                            Evte,
320                                Silb,
321                            Mebx,
322                                Keyd,
323                                Dtyp,
324                                Loca,
325                                Setu,
326                        Stts,
327                        Stsc,
328                        Stsz,
329                        Stss,
330                        Stco,
331                        Co64,
332                        Cslg,
333                        Ctts,
334                        Sbgp,
335                        Sgpd,
336                        Subs,
337                        Saio,
338                        Saiz,
339                    Dinf,
340                        Dref,
341                    Hmhd,
342                    Nmhd,
343                    Smhd,
344                    Sthd,
345                    Vmhd,
346            Edts,
347                Elst,
348            Tref,
349        Mvex,
350            Mehd,
351            Trex,
352    Emsg,
353    Moof,
354        Mfhd,
355        Traf,
356            Tfhd,
357            Tfdt,
358            Trun,
359            Senc,
360    Mdat,
361    Free,
362    Sidx,
363    Prft,
364    Mfra,
365        Tfra,
366        Mfro,
367    Uuid,
368    ],
369    boxed: [
370        Trak,
371    ]
372}
373
374impl ReadFrom for Any {
375    fn read_from<R: Read + ?Sized>(r: &mut R) -> Result<Self> {
376        <Option<Any> as ReadFrom>::read_from(r)?.ok_or(Error::UnexpectedEof)
377    }
378}
379
380impl ReadFrom for Option<Any> {
381    fn read_from<R: Read + ?Sized>(r: &mut R) -> Result<Self> {
382        let header = match <Option<Header> as ReadFrom>::read_from(r)? {
383            Some(header) => header,
384            None => return Ok(None),
385        };
386
387        let body = &mut header.read_body(r)?;
388        Ok(Some(Any::decode_atom(&header, body)?))
389    }
390}
391
392impl ReadAtom for Any {
393    fn read_atom<R: Read + ?Sized>(header: &Header, r: &mut R) -> Result<Self> {
394        let body = &mut header.read_body(r)?;
395        Any::decode_atom(header, body)
396    }
397}
398
399#[cfg(test)]
400mod tests {
401    use super::*;
402
403    const PARTIAL_FTYP: &[u8] = b"\0\0\0\x14ftypisom";
404
405    #[test]
406    fn decode_maybe_preserves_incomplete_atom() {
407        let mut buf = PARTIAL_FTYP;
408
409        assert!(Any::decode_maybe(&mut buf).unwrap().is_none());
410        assert_eq!(buf, PARTIAL_FTYP);
411    }
412}