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    Moov,
268        Mvhd,
269        Ainf,
270        Udta,
271            Cprt,
272            Kind,
273            Skip,
274        // Trak, // boxed to avoid large size differences between variants
275            Tkhd,
276            Mdia,
277                Mdhd,
278                Minf,
279                    Stbl,
280                        Stsd,
281                            Avc1,
282                                Avcc,
283                                Btrt,
284                                Ccst,
285                                Colr,
286                                Pasp,
287                                Taic,
288                                Fiel,
289                            Hev1, Hvc1,
290                                Hvcc, Lhvc,
291                            Mp4a,
292                                Esds,
293                            Tx3g,
294                                Ftab,
295                            Vp08, Vp09,
296                                VpcC,
297                            Av01,
298                                Av1c,
299                            Opus,
300                                Dops,
301                            Uncv,
302                                Cmpd,
303                                UncC,
304                            Flac,
305                                Dfla,
306                            Ac3,
307                                Ac3SpecificBox,
308                            Eac3,
309                                Ec3SpecificBox,
310                            Sowt, Twos, Lpcm, Ipcm, Fpcm, In24, In32, Fl32, Fl64, S16l,
311                                PcmC,
312                                Chnl,
313                            Wvtt,
314                                VttC,
315                                Vlab,
316                            Samr,
317                                Damr,
318                        Stts,
319                        Stsc,
320                        Stsz,
321                        Stss,
322                        Stco,
323                        Co64,
324                        Cslg,
325                        Ctts,
326                        Sbgp,
327                        Sgpd,
328                        Subs,
329                        Saio,
330                        Saiz,
331                    Dinf,
332                        Dref,
333                    Hmhd,
334                    Nmhd,
335                    Smhd,
336                    Sthd,
337                    Vmhd,
338            Edts,
339                Elst,
340            Tref,
341        Mvex,
342            Mehd,
343            Trex,
344    Emsg,
345    Moof,
346        Mfhd,
347        Traf,
348            Tfhd,
349            Tfdt,
350            Trun,
351            Senc,
352    Mdat,
353    Free,
354    Sidx,
355    Prft,
356    Mfra,
357        Tfra,
358        Mfro,
359    ],
360    boxed: [
361        Trak,
362    ]
363}
364
365impl ReadFrom for Any {
366    fn read_from<R: Read + ?Sized>(r: &mut R) -> Result<Self> {
367        <Option<Any> as ReadFrom>::read_from(r)?.ok_or(Error::UnexpectedEof)
368    }
369}
370
371impl ReadFrom for Option<Any> {
372    fn read_from<R: Read + ?Sized>(r: &mut R) -> Result<Self> {
373        let header = match <Option<Header> as ReadFrom>::read_from(r)? {
374            Some(header) => header,
375            None => return Ok(None),
376        };
377
378        let body = &mut header.read_body(r)?;
379        Ok(Some(Any::decode_atom(&header, body)?))
380    }
381}
382
383impl ReadAtom for Any {
384    fn read_atom<R: Read + ?Sized>(header: &Header, r: &mut R) -> Result<Self> {
385        let body = &mut header.read_body(r)?;
386        Any::decode_atom(header, body)
387    }
388}
389
390#[cfg(test)]
391mod tests {
392    use super::*;
393
394    const PARTIAL_FTYP: &[u8] = b"\0\0\0\x14ftypisom";
395
396    #[test]
397    fn decode_maybe_preserves_incomplete_atom() {
398        let mut buf = PARTIAL_FTYP;
399
400        assert!(Any::decode_maybe(&mut buf).unwrap().is_none());
401        assert_eq!(buf, PARTIAL_FTYP);
402    }
403}