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