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