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