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