Skip to main content

mp4_atom/moov/trak/mdia/minf/stbl/stsd/
uncv.rs

1use crate::*;
2
3use super::{Btrt, Pasp, Taic, Visual};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7pub struct Uncv {
8    pub visual: Visual,
9    pub cmpd: Option<Cmpd>,
10    pub uncc: UncC,
11    pub btrt: Option<Btrt>,
12    pub ccst: Option<Ccst>,
13    pub pasp: Option<Pasp>,
14    pub taic: Option<Taic>,
15    pub spatial: Option<Box<Spatial>>,
16}
17
18impl Atom for Uncv {
19    const KIND: FourCC = FourCC::new(b"uncv");
20
21    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
22        let visual = Visual::decode(buf)?;
23
24        let mut ccst = None;
25        let mut cmpd = None;
26        let mut uncc = None;
27        let mut btrt = None;
28        let mut pasp = None;
29        let mut taic = None;
30        let mut spatial = None;
31        while let Some(atom) = Any::decode_maybe(buf)? {
32            match atom {
33                Any::Cmpd(atom) => cmpd = atom.into(),
34                Any::UncC(atom) => uncc = atom.into(),
35                Any::Btrt(atom) => btrt = atom.into(),
36                Any::Ccst(atom) => ccst = atom.into(),
37                Any::Pasp(atom) => pasp = atom.into(),
38                Any::Taic(atom) => taic = atom.into(),
39                atom => Spatial::decode_child::<Self>(&mut spatial, atom)?,
40            }
41        }
42        skip_trailing_padding(buf);
43
44        Ok(Uncv {
45            visual,
46            cmpd,
47            uncc: uncc.ok_or(Error::MissingBox(UncC::KIND))?,
48            btrt,
49            ccst,
50            pasp,
51            taic,
52            spatial,
53        })
54    }
55
56    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
57        self.visual.encode(buf)?;
58        self.cmpd.encode(buf)?;
59        self.uncc.encode(buf)?;
60        self.btrt.encode(buf)?;
61        self.ccst.encode(buf)?;
62        if let Some(spatial) = &self.spatial {
63            spatial.encode(buf)?;
64        }
65        self.pasp.encode(buf)?;
66        self.taic.encode(buf)?;
67
68        Ok(())
69    }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
74pub struct Component {
75    pub component_type: u16,
76    pub component_type_uri: Option<String>,
77}
78
79#[derive(Debug, Clone, PartialEq, Eq, Default)]
80#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
81pub struct Cmpd {
82    pub components: Vec<Component>,
83}
84
85impl Atom for Cmpd {
86    const KIND: FourCC = FourCC::new(b"cmpd");
87
88    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
89        let component_count = u32::decode(buf)?;
90        let mut components: Vec<Component> =
91            Vec::with_capacity((component_count as usize).min(1024));
92        for _ in 0..component_count {
93            let component_type = u16::decode(buf)?;
94            if component_type >= 0x8000 {
95                let component_type_uri = String::decode(buf)?;
96                components.push(Component {
97                    component_type,
98                    component_type_uri: Some(component_type_uri),
99                });
100            } else {
101                components.push(Component {
102                    component_type,
103                    component_type_uri: None,
104                });
105            }
106        }
107        Ok(Cmpd { components })
108    }
109
110    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
111        let component_count: u32 = self.components.len() as u32;
112        component_count.encode(buf)?;
113        for component in &self.components {
114            component.component_type.encode(buf)?;
115            if component.component_type >= 0x8000 {
116                let component_type_uri = component
117                    .component_type_uri
118                    .as_ref()
119                    .expect("Expected valid URI when component_type is >= 0x8000");
120                component_type_uri.as_str().encode(buf)?;
121            }
122        }
123        Ok(())
124    }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq)]
128#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
129pub struct UncompressedComponent {
130    pub component_index: u16,
131    pub component_bit_depth_minus_one: u8,
132    pub component_format: u8,
133    pub component_align_size: u8,
134}
135
136ext! {
137    name: UncC,
138    versions: [0, 1],
139    flags: {}
140}
141
142#[derive(Debug, Clone, PartialEq, Eq)]
143#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
144pub enum UncC {
145    V1 {
146        profile: FourCC,
147    },
148    V0 {
149        profile: FourCC,
150        components: Vec<UncompressedComponent>,
151        sampling_type: u8,   // TODO: enum?
152        interleave_type: u8, // TODO: enum?
153        block_size: u8,
154        components_little_endian: bool,
155        block_pad_lsb: bool,
156        block_little_endian: bool,
157        block_reversed: bool,
158        pad_unknown: bool,
159        pixel_size: u32,
160        row_align_size: u32,
161        tile_align_size: u32,
162        num_tile_cols_minus_one: u32,
163        num_tile_rows_minus_one: u32,
164    },
165}
166
167impl AtomExt for UncC {
168    const KIND_EXT: FourCC = FourCC::new(b"uncC");
169
170    type Ext = UncCExt;
171
172    fn decode_body_ext<B: Buf>(buf: &mut B, ext: UncCExt) -> Result<Self> {
173        match ext.version {
174            UncCVersion::V1 => Ok(UncC::V1 {
175                profile: FourCC::decode(buf)?,
176            }),
177            UncCVersion::V0 => {
178                let profile = FourCC::decode(buf)?;
179                let component_count = u32::decode(buf)?;
180                let mut components = Vec::with_capacity((component_count as usize).min(1024));
181                for _ in 0..component_count {
182                    components.push(UncompressedComponent {
183                        component_index: u16::decode(buf)?,
184                        component_bit_depth_minus_one: u8::decode(buf)?,
185                        component_format: u8::decode(buf)?,
186                        component_align_size: u8::decode(buf)?,
187                    });
188                }
189                let sampling_type = u8::decode(buf)?;
190                let interleave_type = u8::decode(buf)?;
191                let block_size = u8::decode(buf)?;
192                let flag_bits = u8::decode(buf)?;
193                let components_little_endian = flag_bits & 0x80 == 0x80;
194                let block_pad_lsb = flag_bits & 0x40 == 0x40;
195                let block_little_endian = flag_bits & 0x20 == 0x20;
196                let block_reversed = flag_bits & 0x10 == 0x10;
197                let pad_unknown = flag_bits & 0x08 == 0x08;
198                let pixel_size = u32::decode(buf)?;
199                let row_align_size = u32::decode(buf)?;
200                let tile_align_size = u32::decode(buf)?;
201                let num_tile_cols_minus_one = u32::decode(buf)?;
202                let num_tile_rows_minus_one = u32::decode(buf)?;
203                Ok(UncC::V0 {
204                    profile,
205                    components,
206                    sampling_type,
207                    interleave_type,
208                    block_size,
209                    components_little_endian,
210                    block_pad_lsb,
211                    block_little_endian,
212                    block_reversed,
213                    pad_unknown,
214                    pixel_size,
215                    row_align_size,
216                    tile_align_size,
217                    num_tile_cols_minus_one,
218                    num_tile_rows_minus_one,
219                })
220            }
221        }
222    }
223
224    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<UncCExt> {
225        match self {
226            UncC::V1 { profile } => {
227                profile.encode(buf)?;
228                Ok(UncCExt {
229                    version: UncCVersion::V1,
230                })
231            }
232            UncC::V0 {
233                profile,
234                components,
235                sampling_type,
236                interleave_type,
237                block_size,
238                components_little_endian,
239                block_pad_lsb,
240                block_little_endian,
241                block_reversed,
242                pad_unknown,
243                pixel_size,
244                row_align_size,
245                tile_align_size,
246                num_tile_cols_minus_one,
247                num_tile_rows_minus_one,
248            } => {
249                profile.encode(buf)?;
250                let component_count: u32 = components.len() as u32;
251                component_count.encode(buf)?;
252                for component in components {
253                    component.component_index.encode(buf)?;
254                    component.component_bit_depth_minus_one.encode(buf)?;
255                    component.component_format.encode(buf)?;
256                    component.component_align_size.encode(buf)?;
257                }
258                sampling_type.encode(buf)?;
259                interleave_type.encode(buf)?;
260                block_size.encode(buf)?;
261                let mut flags: u8 = 0x00;
262                if *components_little_endian {
263                    flags |= 0x80u8;
264                }
265                if *block_pad_lsb {
266                    flags |= 0x40u8;
267                }
268                if *block_little_endian {
269                    flags |= 0x20u8;
270                }
271                if *block_reversed {
272                    flags |= 0x10u8;
273                }
274                if *pad_unknown {
275                    flags |= 0x08u8;
276                }
277                flags.encode(buf)?;
278                pixel_size.encode(buf)?;
279                row_align_size.encode(buf)?;
280                tile_align_size.encode(buf)?;
281                num_tile_cols_minus_one.encode(buf)?;
282                num_tile_rows_minus_one.encode(buf)?;
283                Ok(UncCExt {
284                    version: UncCVersion::V0,
285                })
286            }
287        }
288    }
289}
290
291#[cfg(test)]
292mod tests {
293    use super::*;
294
295    const ENCODED_CMPD: &[u8] = &[
296        0x00, 0x00, 0x00, 0x12, 0x63, 0x6d, 0x70, 0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
297        0x05, 0x00, 0x06,
298    ];
299
300    const ENCODED_UNCC: &[u8] = &[
301        0x00, 0x00, 0x00, 0x3b, 0x75, 0x6e, 0x63, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302        0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x07, 0x00, 0x00,
303        0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305    ];
306
307    // Regression for issue #180: attacker-controlled component counts must not
308    // cause a multi-gigabyte upfront allocation before decoding fails.
309    const ENCODED_CMPD_HUGE_COUNT: &[u8] = &[
310        0x00, 0x00, 0x00, 0x0c, 0x63, 0x6d, 0x70, 0x64, 0xff, 0xff, 0xff, 0xff,
311    ];
312
313    const ENCODED_UNCC_HUGE_COUNT: &[u8] = &[
314        0x00, 0x00, 0x00, 0x14, 0x75, 0x6e, 0x63, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315        0x00, 0xff, 0xff, 0xff, 0xff,
316    ];
317
318    #[test]
319    fn test_cmpd_decode() {
320        let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_CMPD);
321
322        let cmpd = Cmpd::decode(buf).expect("failed to decode cmpd");
323
324        assert_eq!(
325            cmpd,
326            Cmpd {
327                components: vec![
328                    Component {
329                        component_type: 4,
330                        component_type_uri: None
331                    },
332                    Component {
333                        component_type: 5,
334                        component_type_uri: None
335                    },
336                    Component {
337                        component_type: 6,
338                        component_type_uri: None
339                    }
340                ]
341            },
342        );
343    }
344
345    #[test]
346    fn test_cmpd_huge_count() {
347        let buf = &mut std::io::Cursor::new(&ENCODED_CMPD_HUGE_COUNT);
348        assert!(matches!(Cmpd::decode(buf), Err(Error::OverDecode(_))));
349    }
350
351    #[test]
352    fn test_cmpd_encode() {
353        let cmpd = Cmpd {
354            components: vec![
355                Component {
356                    component_type: 4,
357                    component_type_uri: None,
358                },
359                Component {
360                    component_type: 5,
361                    component_type_uri: None,
362                },
363                Component {
364                    component_type: 6,
365                    component_type_uri: None,
366                },
367            ],
368        };
369
370        let mut buf = Vec::new();
371        cmpd.encode(&mut buf).unwrap();
372
373        assert_eq!(buf.as_slice(), ENCODED_CMPD);
374    }
375
376    #[test]
377    fn test_uncc_decode() {
378        let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_UNCC);
379
380        let uncc = UncC::decode(buf).expect("failed to decode uncC");
381
382        assert_eq!(
383            uncc,
384            UncC::V0 {
385                profile: FourCC::new(b"\0\0\0\0"),
386                components: vec![
387                    UncompressedComponent {
388                        component_index: 0,
389                        component_bit_depth_minus_one: 7,
390                        component_format: 0,
391                        component_align_size: 0
392                    },
393                    UncompressedComponent {
394                        component_index: 1,
395                        component_bit_depth_minus_one: 7,
396                        component_format: 0,
397                        component_align_size: 0
398                    },
399                    UncompressedComponent {
400                        component_index: 2,
401                        component_bit_depth_minus_one: 7,
402                        component_format: 0,
403                        component_align_size: 0
404                    },
405                ],
406                sampling_type: 0,
407                interleave_type: 1,
408                block_size: 0,
409                components_little_endian: false,
410                block_pad_lsb: false,
411                block_little_endian: false,
412                block_reversed: false,
413                pad_unknown: false,
414                pixel_size: 0,
415                row_align_size: 0,
416                tile_align_size: 0,
417                num_tile_cols_minus_one: 0,
418                num_tile_rows_minus_one: 0
419            }
420        );
421    }
422
423    #[test]
424    fn test_uncc_huge_count() {
425        let buf = &mut std::io::Cursor::new(&ENCODED_UNCC_HUGE_COUNT);
426        assert!(matches!(UncC::decode(buf), Err(Error::OverDecode(_))));
427    }
428
429    #[test]
430    fn test_uncc_encode() {
431        let uncc = UncC::V0 {
432            profile: FourCC::new(b"\0\0\0\0"),
433            components: vec![
434                UncompressedComponent {
435                    component_index: 0,
436                    component_bit_depth_minus_one: 7,
437                    component_format: 0,
438                    component_align_size: 0,
439                },
440                UncompressedComponent {
441                    component_index: 1,
442                    component_bit_depth_minus_one: 7,
443                    component_format: 0,
444                    component_align_size: 0,
445                },
446                UncompressedComponent {
447                    component_index: 2,
448                    component_bit_depth_minus_one: 7,
449                    component_format: 0,
450                    component_align_size: 0,
451                },
452            ],
453            sampling_type: 0,
454            interleave_type: 1,
455            block_size: 0,
456            components_little_endian: false,
457            block_pad_lsb: false,
458            block_little_endian: false,
459            block_reversed: false,
460            pad_unknown: false,
461            pixel_size: 0,
462            row_align_size: 0,
463            tile_align_size: 0,
464            num_tile_cols_minus_one: 0,
465            num_tile_rows_minus_one: 0,
466        };
467
468        let mut buf = Vec::new();
469        uncc.encode(&mut buf).unwrap();
470
471        assert_eq!(buf.as_slice(), ENCODED_UNCC);
472    }
473}