1mod chpl;
2mod cprt;
3mod kind;
4mod rtng;
5mod skip;
6
7pub use chpl::*;
8pub use cprt::*;
9pub use kind::*;
10pub use rtng::*;
11pub use skip::*;
12
13use crate::*;
14
15#[derive(Debug, Clone, PartialEq, Eq, Default)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct Udta {
18 pub chpl: Option<Chpl>,
20 pub cprt: Vec<Cprt>,
22 pub kind: Vec<Kind>,
24 pub meta: Option<Meta>,
26 pub rtng: Vec<Rtng>,
28}
29
30impl Atom for Udta {
31 const KIND: FourCC = FourCC::new(b"udta");
32
33 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
34 let mut chpl = None;
35 let mut cprt = Vec::new();
36 let mut kind = Vec::new();
37 let mut meta = None;
38 let mut rtng = Vec::new();
39
40 while let Some(header) = Header::decode_maybe(buf)? {
47 let size = header.size.unwrap_or(buf.remaining());
48 if size > buf.remaining() {
49 return Err(Error::OutOfBounds);
51 }
52 match header.kind {
60 Chpl::KIND => {
61 if chpl.is_some() {
62 return Err(Error::DuplicateBox(Chpl::KIND));
63 }
64 chpl = Some(Chpl::decode_atom(&header, buf)?);
65 }
66 Cprt::KIND => cprt.push(Cprt::decode_atom(&header, buf)?),
67 Kind::KIND => kind.push(Kind::decode_atom(&header, buf)?),
68 Meta::KIND => {
69 if meta.is_some() {
70 return Err(Error::DuplicateBox(Meta::KIND));
71 }
72 meta = Some(Meta::decode_atom(&header, buf)?);
73 }
74 Rtng::KIND => rtng.push(Rtng::decode_atom(&header, buf)?),
75 Free::KIND | Skip::KIND => {
77 buf.advance(size);
78 }
79 unknown => {
80 let body = Vec::decode(&mut buf.slice(size))?;
81 buf.advance(size);
82 Self::decode_unknown(&Any::Unknown(unknown, body))?;
83 }
84 }
85 }
86 skip_trailing_padding(buf);
88
89 Ok(Udta {
90 chpl,
91 cprt,
92 kind,
93 meta,
94 rtng,
95 })
96 }
97
98 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
99 self.chpl.encode(buf)?;
100 self.cprt.encode(buf)?;
101 self.meta.encode(buf)?;
102 self.kind.encode(buf)?;
103 self.rtng.encode(buf)?;
104 Ok(())
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_udta_empty() {
114 let expected = Udta {
115 chpl: None,
116 cprt: vec![],
117 meta: None,
118 kind: vec![],
119 rtng: vec![],
120 };
121
122 let mut buf = Vec::new();
123 expected.encode(&mut buf).unwrap();
124
125 let mut buf = buf.as_ref();
126 let output = Udta::decode(&mut buf).unwrap();
127 assert_eq!(output, expected);
128 }
129
130 #[test]
131 fn test_udta() {
132 let expected = Udta {
133 chpl: None,
134 cprt: vec![Cprt {
135 language: "und".into(),
136 notice: "MIT or Apache".into(),
137 }],
138 meta: Some(Meta {
139 hdlr: Hdlr {
140 handler: FourCC::new(b"fake"),
141 name: "".into(),
142 },
143 items: vec![],
144 }),
145 kind: vec![Kind {
146 scheme_uri: "http://www.w3.org/TR/html5/".into(),
147 value: "".into(),
148 }],
149 rtng: vec![Rtng {
150 entity: b"BBFC".into(),
151 criteria: b"PG13".into(),
152 language: "eng".into(),
153 rating_info: "test info".into(),
154 }],
155 };
156
157 let mut buf = Vec::new();
158 expected.encode(&mut buf).unwrap();
159
160 let mut buf = buf.as_ref();
161 let output = Udta::decode(&mut buf).unwrap();
162 assert_eq!(output, expected);
163 }
164
165 const ENCODED_UDTA_WITH_CPRT: &[u8] = &[
167 0x00, 0x00, 0x00, 0x70, 0x75, 0x64, 0x74, 0x61, 0x00, 0x00, 0x00, 0x68, 0x63, 0x70, 0x72,
168 0x74, 0x00, 0x00, 0x00, 0x00, 0x55, 0xc4, 0x45, 0x4e, 0x53, 0x54, 0x20, 0x49, 0x73, 0x6f,
169 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e,
170 0x63, 0x65, 0x20, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x20, 0x2d, 0x20, 0x45, 0x4e, 0x53, 0x54,
171 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x2d, 0x20, 0x52, 0x69, 0x67,
172 0x68, 0x74, 0x73, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x66, 0x6f,
173 0x72, 0x20, 0x49, 0x53, 0x4f, 0x20, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e,
174 0x63, 0x65, 0x20, 0x75, 0x73, 0x65, 0x00,
175 ];
176
177 #[test]
178 fn test_udta_cprt() {
179 let mut buf = std::io::Cursor::new(ENCODED_UDTA_WITH_CPRT);
180
181 let udta = Udta::decode(&mut buf).expect("failed to decode udta");
182
183 assert_eq!(
184 udta,
185 Udta {
186 cprt: vec![Cprt { language: "und".into(), notice: "ENST IsoMedia Conformance Files - ENST (c) 2006 - Rights released for ISO Conformance use".into() }],
187 ..Default::default()
188 }
189 );
190
191 let mut buf = Vec::new();
192 udta.encode(&mut buf).unwrap();
193
194 assert_eq!(buf, ENCODED_UDTA_WITH_CPRT);
195 }
196
197 const ENCODED_UDTA_WITH_KIND: &[u8] = &[
199 0x00, 0x00, 0x00, 0x31, 0x75, 0x64, 0x74, 0x61, 0x00, 0x00, 0x00, 0x29, 0x6b, 0x69, 0x6e,
200 0x64, 0x00, 0x00, 0x00, 0x00, 0x75, 0x72, 0x6e, 0x3a, 0x6d, 0x70, 0x65, 0x67, 0x3a, 0x64,
201 0x61, 0x73, 0x68, 0x3a, 0x72, 0x6f, 0x6c, 0x65, 0x3a, 0x32, 0x30, 0x31, 0x31, 0x00, 0x6d,
202 0x61, 0x69, 0x6e, 0x00,
203 ];
204
205 #[test]
206 fn test_udta_kind() {
207 let mut buf = std::io::Cursor::new(ENCODED_UDTA_WITH_KIND);
208
209 let udta = Udta::decode(&mut buf).expect("failed to decode udta");
210
211 assert_eq!(
212 udta,
213 Udta {
214 kind: vec![Kind {
215 scheme_uri: "urn:mpeg:dash:role:2011".into(),
216 value: "main".into()
217 }],
218 ..Default::default()
219 }
220 );
221
222 let mut buf = Vec::new();
223 udta.encode(&mut buf).unwrap();
224
225 assert_eq!(buf, ENCODED_UDTA_WITH_KIND);
226 }
227
228 const ENCODED_UDTA_WITH_QT_NAME: &[u8] = &[
232 0x00, 0x00, 0x00, 0x14, 0x75, 0x64, 0x74, 0x61, 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, ];
236
237 #[test]
240 fn test_udta_trailing_padding() {
241 let mut buf = ENCODED_UDTA_WITH_CPRT.to_vec();
242 buf.extend_from_slice(&[0, 0, 0, 0]);
243 let size = (buf.len() as u32).to_be_bytes();
244 buf[0..4].copy_from_slice(&size);
245
246 let udta = Udta::decode(&mut buf.as_slice()).expect("trailing padding must be tolerated");
247 assert_eq!(
248 udta.cprt.len(),
249 1,
250 "the real child still decodes, the padding is dropped"
251 );
252 }
253
254 #[test]
255 fn test_udta_quicktime_name_not_misparsed() {
256 let mut buf = std::io::Cursor::new(ENCODED_UDTA_WITH_QT_NAME);
261 match Udta::decode(&mut buf) {
262 Err(Error::UnexpectedBox(kind)) => assert_eq!(kind, FourCC::new(b"name")),
263 other => panic!("expected UnexpectedBox(name), got {other:?}"),
264 }
265 }
266
267 #[test]
274 fn test_udta_repeated_children() {
275 let expected = Udta {
276 chpl: None,
277 cprt: vec![
278 Cprt {
279 language: "eng".into(),
280 notice: "All rights reserved".into(),
281 },
282 Cprt {
283 language: "fra".into(),
284 notice: "Tous droits réservés".into(),
285 },
286 ],
287 kind: vec![
288 Kind {
289 scheme_uri: "urn:mpeg:dash:role:2011".into(),
290 value: "main".into(),
291 },
292 Kind {
293 scheme_uri: "urn:mpeg:dash:role:2011".into(),
294 value: "caption".into(),
295 },
296 ],
297 meta: None,
298 rtng: vec![
299 Rtng {
300 entity: b"BBFC".into(),
301 criteria: b"PG13".into(),
302 language: "eng".into(),
303 rating_info: "parental guidance".into(),
304 },
305 Rtng {
306 entity: b"BBFC".into(),
307 criteria: b"PG13".into(),
308 language: "fra".into(),
309 rating_info: "accord parental".into(),
310 },
311 ],
312 };
313
314 let mut buf = Vec::new();
315 expected.encode(&mut buf).unwrap();
316
317 let mut buf = buf.as_ref();
318 let output = Udta::decode(&mut buf).unwrap();
319 assert_eq!(output, expected);
320 }
321
322 #[test]
326 fn test_udta_duplicate_meta() {
327 let meta = Meta {
328 hdlr: Hdlr {
329 handler: FourCC::new(b"fake"),
330 name: "".into(),
331 },
332 items: vec![],
333 };
334 let mut body = Vec::new();
335 meta.encode(&mut body).unwrap();
336 meta.encode(&mut body).unwrap();
337
338 let mut bytes = Vec::new();
339 bytes.extend_from_slice(&((body.len() + 8) as u32).to_be_bytes());
340 bytes.extend_from_slice(b"udta");
341 bytes.extend_from_slice(&body);
342
343 match Udta::decode(&mut bytes.as_slice()) {
344 Err(Error::DuplicateBox(kind)) => assert_eq!(kind, Meta::KIND),
345 other => panic!("expected DuplicateBox(meta), got {other:?}"),
346 }
347 }
348}