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, interleave_type: u8, 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 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}