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