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 => chpl.insert_once(Chpl::decode_atom(&header, buf)?)?,
61 Cprt::KIND => cprt.push(Cprt::decode_atom(&header, buf)?),
62 Kind::KIND => kind.push(Kind::decode_atom(&header, buf)?),
63 Meta::KIND => meta.insert_once(Meta::decode_atom(&header, buf)?)?,
64 Rtng::KIND => rtng.push(Rtng::decode_atom(&header, buf)?),
65 Free::KIND | Skip::KIND => {
67 buf.advance(size);
68 }
69 unknown => {
70 let body = Vec::decode(&mut buf.slice(size))?;
71 buf.advance(size);
72 Self::decode_unknown(&Any::Unknown(unknown, body))?;
73 }
74 }
75 }
76 skip_trailing_padding(buf);
78
79 Ok(Udta {
80 chpl,
81 cprt,
82 kind,
83 meta,
84 rtng,
85 })
86 }
87
88 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
89 self.chpl.encode(buf)?;
90 self.cprt.encode(buf)?;
91 self.meta.encode(buf)?;
92 self.kind.encode(buf)?;
93 self.rtng.encode(buf)?;
94 Ok(())
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test_udta_empty() {
104 let expected = Udta {
105 chpl: None,
106 cprt: vec![],
107 meta: None,
108 kind: vec![],
109 rtng: vec![],
110 };
111
112 let mut buf = Vec::new();
113 expected.encode(&mut buf).unwrap();
114
115 let mut buf = buf.as_ref();
116 let output = Udta::decode(&mut buf).unwrap();
117 assert_eq!(output, expected);
118 }
119
120 #[test]
121 fn test_udta() {
122 let expected = Udta {
123 chpl: None,
124 cprt: vec![Cprt {
125 language: "und".into(),
126 notice: "MIT or Apache".into(),
127 }],
128 meta: Some(Meta {
129 hdlr: Hdlr {
130 handler: FourCC::new(b"fake"),
131 name: "".into(),
132 },
133 items: vec![],
134 }),
135 kind: vec![Kind {
136 scheme_uri: "http://www.w3.org/TR/html5/".into(),
137 value: "".into(),
138 }],
139 rtng: vec![Rtng {
140 entity: b"BBFC".into(),
141 criteria: b"PG13".into(),
142 language: "eng".into(),
143 rating_info: "test info".into(),
144 }],
145 };
146
147 let mut buf = Vec::new();
148 expected.encode(&mut buf).unwrap();
149
150 let mut buf = buf.as_ref();
151 let output = Udta::decode(&mut buf).unwrap();
152 assert_eq!(output, expected);
153 }
154
155 const ENCODED_UDTA_WITH_CPRT: &[u8] = &[
157 0x00, 0x00, 0x00, 0x70, 0x75, 0x64, 0x74, 0x61, 0x00, 0x00, 0x00, 0x68, 0x63, 0x70, 0x72,
158 0x74, 0x00, 0x00, 0x00, 0x00, 0x55, 0xc4, 0x45, 0x4e, 0x53, 0x54, 0x20, 0x49, 0x73, 0x6f,
159 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e,
160 0x63, 0x65, 0x20, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x20, 0x2d, 0x20, 0x45, 0x4e, 0x53, 0x54,
161 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x2d, 0x20, 0x52, 0x69, 0x67,
162 0x68, 0x74, 0x73, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x66, 0x6f,
163 0x72, 0x20, 0x49, 0x53, 0x4f, 0x20, 0x43, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e,
164 0x63, 0x65, 0x20, 0x75, 0x73, 0x65, 0x00,
165 ];
166
167 #[test]
168 fn test_udta_cprt() {
169 let mut buf = std::io::Cursor::new(ENCODED_UDTA_WITH_CPRT);
170
171 let udta = Udta::decode(&mut buf).expect("failed to decode udta");
172
173 assert_eq!(
174 udta,
175 Udta {
176 cprt: vec![Cprt { language: "und".into(), notice: "ENST IsoMedia Conformance Files - ENST (c) 2006 - Rights released for ISO Conformance use".into() }],
177 ..Default::default()
178 }
179 );
180
181 let mut buf = Vec::new();
182 udta.encode(&mut buf).unwrap();
183
184 assert_eq!(buf, ENCODED_UDTA_WITH_CPRT);
185 }
186
187 const ENCODED_UDTA_WITH_KIND: &[u8] = &[
189 0x00, 0x00, 0x00, 0x31, 0x75, 0x64, 0x74, 0x61, 0x00, 0x00, 0x00, 0x29, 0x6b, 0x69, 0x6e,
190 0x64, 0x00, 0x00, 0x00, 0x00, 0x75, 0x72, 0x6e, 0x3a, 0x6d, 0x70, 0x65, 0x67, 0x3a, 0x64,
191 0x61, 0x73, 0x68, 0x3a, 0x72, 0x6f, 0x6c, 0x65, 0x3a, 0x32, 0x30, 0x31, 0x31, 0x00, 0x6d,
192 0x61, 0x69, 0x6e, 0x00,
193 ];
194
195 #[test]
196 fn test_udta_kind() {
197 let mut buf = std::io::Cursor::new(ENCODED_UDTA_WITH_KIND);
198
199 let udta = Udta::decode(&mut buf).expect("failed to decode udta");
200
201 assert_eq!(
202 udta,
203 Udta {
204 kind: vec![Kind {
205 scheme_uri: "urn:mpeg:dash:role:2011".into(),
206 value: "main".into()
207 }],
208 ..Default::default()
209 }
210 );
211
212 let mut buf = Vec::new();
213 udta.encode(&mut buf).unwrap();
214
215 assert_eq!(buf, ENCODED_UDTA_WITH_KIND);
216 }
217
218 const ENCODED_UDTA_WITH_QT_NAME: &[u8] = &[
222 0x00, 0x00, 0x00, 0x14, 0x75, 0x64, 0x74, 0x61, 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, ];
226
227 #[test]
230 fn test_udta_trailing_padding() {
231 let mut buf = ENCODED_UDTA_WITH_CPRT.to_vec();
232 buf.extend_from_slice(&[0, 0, 0, 0]);
233 let size = (buf.len() as u32).to_be_bytes();
234 buf[0..4].copy_from_slice(&size);
235
236 let udta = Udta::decode(&mut buf.as_slice()).expect("trailing padding must be tolerated");
237 assert_eq!(
238 udta.cprt.len(),
239 1,
240 "the real child still decodes, the padding is dropped"
241 );
242 }
243
244 #[test]
245 fn test_udta_quicktime_name_not_misparsed() {
246 let mut buf = std::io::Cursor::new(ENCODED_UDTA_WITH_QT_NAME);
251 match Udta::decode(&mut buf) {
252 Err(Error::UnexpectedBox(kind)) => assert_eq!(kind, FourCC::new(b"name")),
253 other => panic!("expected UnexpectedBox(name), got {other:?}"),
254 }
255 }
256
257 #[test]
264 fn test_udta_repeated_children() {
265 let expected = Udta {
266 chpl: None,
267 cprt: vec![
268 Cprt {
269 language: "eng".into(),
270 notice: "All rights reserved".into(),
271 },
272 Cprt {
273 language: "fra".into(),
274 notice: "Tous droits réservés".into(),
275 },
276 ],
277 kind: vec![
278 Kind {
279 scheme_uri: "urn:mpeg:dash:role:2011".into(),
280 value: "main".into(),
281 },
282 Kind {
283 scheme_uri: "urn:mpeg:dash:role:2011".into(),
284 value: "caption".into(),
285 },
286 ],
287 meta: None,
288 rtng: vec![
289 Rtng {
290 entity: b"BBFC".into(),
291 criteria: b"PG13".into(),
292 language: "eng".into(),
293 rating_info: "parental guidance".into(),
294 },
295 Rtng {
296 entity: b"BBFC".into(),
297 criteria: b"PG13".into(),
298 language: "fra".into(),
299 rating_info: "accord parental".into(),
300 },
301 ],
302 };
303
304 let mut buf = Vec::new();
305 expected.encode(&mut buf).unwrap();
306
307 let mut buf = buf.as_ref();
308 let output = Udta::decode(&mut buf).unwrap();
309 assert_eq!(output, expected);
310 }
311
312 #[test]
316 fn test_udta_duplicate_meta() {
317 let meta = Meta {
318 hdlr: Hdlr {
319 handler: FourCC::new(b"fake"),
320 name: "".into(),
321 },
322 items: vec![],
323 };
324 let mut body = Vec::new();
325 meta.encode(&mut body).unwrap();
326 meta.encode(&mut body).unwrap();
327
328 let mut bytes = Vec::new();
329 bytes.extend_from_slice(&((body.len() + 8) as u32).to_be_bytes());
330 bytes.extend_from_slice(b"udta");
331 bytes.extend_from_slice(&body);
332
333 match Udta::decode(&mut bytes.as_slice()) {
334 Err(Error::DuplicateBox(kind)) => assert_eq!(kind, Meta::KIND),
335 other => panic!("expected DuplicateBox(meta), got {other:?}"),
336 }
337 }
338}