1use crate::error::{Error, Result};
36use dvb_common::{Parse, Serialize};
37
38pub(crate) const COMPAT_DESC_LEN_FIELD: usize = 2;
39const DESC_COUNT_FIELD: usize = 2;
40const DESC_HEADER_LEN: usize = 2;
41const DESC_FIXED_LEN: usize = 9;
42const SUB_DESC_HEADER_LEN: usize = 2;
43
44#[derive(Debug, Clone, PartialEq, Eq)]
53#[cfg_attr(feature = "serde", derive(serde::Serialize))]
54pub struct CompatibilityDescriptor<'a> {
55 pub descriptors: Vec<CompatibilityDescriptorEntry<'a>>,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize))]
67pub struct CompatibilityDescriptorEntry<'a> {
68 pub descriptor_type: u8,
70 pub specifier_type: u8,
72 pub specifier_data: [u8; 3],
74 pub model: u16,
76 pub version: u16,
78 pub sub_descriptors: Vec<SubDescriptor<'a>>,
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
84#[cfg_attr(feature = "serde", derive(serde::Serialize))]
85pub struct SubDescriptor<'a> {
86 pub sub_descriptor_type: u8,
88 #[cfg_attr(feature = "serde", serde(borrow))]
90 pub data: &'a [u8],
91}
92
93fn entry_serialized_len(entry: &CompatibilityDescriptorEntry) -> usize {
94 DESC_HEADER_LEN
95 + DESC_FIXED_LEN
96 + entry
97 .sub_descriptors
98 .iter()
99 .map(|sd| SUB_DESC_HEADER_LEN + sd.data.len())
100 .sum::<usize>()
101}
102
103impl<'a> Parse<'a> for CompatibilityDescriptor<'a> {
104 type Error = Error;
105
106 fn parse(bytes: &'a [u8]) -> Result<Self> {
107 if bytes.len() < COMPAT_DESC_LEN_FIELD {
108 return Err(Error::BufferTooShort {
109 need: COMPAT_DESC_LEN_FIELD,
110 have: bytes.len(),
111 what: "CompatibilityDescriptor length field",
112 });
113 }
114 let compat_desc_len = u16::from_be_bytes([bytes[0], bytes[1]]) as usize;
115 let body_end = COMPAT_DESC_LEN_FIELD + compat_desc_len;
116 if body_end > bytes.len() {
117 return Err(Error::SectionLengthOverflow {
118 declared: compat_desc_len,
119 available: bytes.len() - COMPAT_DESC_LEN_FIELD,
120 });
121 }
122 if compat_desc_len == 0 {
123 return Ok(CompatibilityDescriptor {
124 descriptors: Vec::new(),
125 });
126 }
127 if compat_desc_len < DESC_COUNT_FIELD {
128 return Err(Error::BufferTooShort {
129 need: COMPAT_DESC_LEN_FIELD + DESC_COUNT_FIELD,
130 have: bytes.len(),
131 what: "CompatibilityDescriptor descriptorCount",
132 });
133 }
134 let body = &bytes[COMPAT_DESC_LEN_FIELD..body_end];
135 let descriptor_count = u16::from_be_bytes([body[0], body[1]]) as usize;
136 let mut pos = DESC_COUNT_FIELD;
137 let max_entries = (body.len() - DESC_COUNT_FIELD) / (DESC_HEADER_LEN + DESC_FIXED_LEN);
138 let mut descriptors = Vec::with_capacity(descriptor_count.min(max_entries));
139 for _ in 0..descriptor_count {
140 if pos + DESC_HEADER_LEN > body.len() {
141 return Err(Error::BufferTooShort {
142 need: COMPAT_DESC_LEN_FIELD + pos + DESC_HEADER_LEN,
143 have: COMPAT_DESC_LEN_FIELD + body.len(),
144 what: "CompatibilityDescriptor entry header",
145 });
146 }
147 let descriptor_type = body[pos];
148 let descriptor_length = body[pos + 1] as usize;
149 let entry_end = pos + DESC_HEADER_LEN + descriptor_length;
150 if entry_end > body.len() {
151 return Err(Error::SectionLengthOverflow {
152 declared: descriptor_length,
153 available: body.len() - pos - DESC_HEADER_LEN,
154 });
155 }
156 if descriptor_length < DESC_FIXED_LEN {
157 return Err(Error::InvalidDescriptor {
158 tag: descriptor_type,
159 reason: "descriptorLength shorter than fixed fields",
160 });
161 }
162 let specifier_type = body[pos + DESC_HEADER_LEN];
163 let specifier_data = [
164 body[pos + DESC_HEADER_LEN + 1],
165 body[pos + DESC_HEADER_LEN + 2],
166 body[pos + DESC_HEADER_LEN + 3],
167 ];
168 let model = u16::from_be_bytes([
169 body[pos + DESC_HEADER_LEN + 4],
170 body[pos + DESC_HEADER_LEN + 5],
171 ]);
172 let version = u16::from_be_bytes([
173 body[pos + DESC_HEADER_LEN + 6],
174 body[pos + DESC_HEADER_LEN + 7],
175 ]);
176 let sub_descriptor_count = body[pos + DESC_HEADER_LEN + 8] as usize;
177 let sub_desc_start = pos + DESC_HEADER_LEN + DESC_FIXED_LEN;
178 let sub_desc_end = entry_end;
179 let sub_desc_region_len = sub_desc_end.saturating_sub(sub_desc_start);
180 let mut sub_descriptors = Vec::with_capacity(
181 sub_descriptor_count.min(sub_desc_region_len / SUB_DESC_HEADER_LEN),
182 );
183 let mut sub_pos = sub_desc_start;
184 for _ in 0..sub_descriptor_count {
185 if sub_pos + SUB_DESC_HEADER_LEN > sub_desc_end {
186 return Err(Error::BufferTooShort {
187 need: COMPAT_DESC_LEN_FIELD + sub_pos + SUB_DESC_HEADER_LEN,
188 have: COMPAT_DESC_LEN_FIELD + sub_desc_end,
189 what: "CompatibilityDescriptor subDescriptor header",
190 });
191 }
192 let sub_descriptor_type = body[sub_pos];
193 let sub_descriptor_length = body[sub_pos + 1] as usize;
194 sub_pos += SUB_DESC_HEADER_LEN;
195 if sub_pos + sub_descriptor_length > sub_desc_end {
196 return Err(Error::SectionLengthOverflow {
197 declared: sub_descriptor_length,
198 available: sub_desc_end - sub_pos,
199 });
200 }
201 sub_descriptors.push(SubDescriptor {
202 sub_descriptor_type,
203 data: &body[sub_pos..sub_pos + sub_descriptor_length],
204 });
205 sub_pos += sub_descriptor_length;
206 }
207 pos = entry_end;
208 descriptors.push(CompatibilityDescriptorEntry {
209 descriptor_type,
210 specifier_type,
211 specifier_data,
212 model,
213 version,
214 sub_descriptors,
215 });
216 }
217 if pos != body.len() {
220 return Err(Error::InvalidDescriptor {
221 tag: 0,
222 reason: "trailing bytes after compatibility descriptor entries",
223 });
224 }
225 Ok(CompatibilityDescriptor { descriptors })
226 }
227}
228
229impl Serialize for CompatibilityDescriptor<'_> {
230 type Error = Error;
231
232 fn serialized_len(&self) -> usize {
233 if self.descriptors.is_empty() {
234 return COMPAT_DESC_LEN_FIELD;
235 }
236 COMPAT_DESC_LEN_FIELD
237 + DESC_COUNT_FIELD
238 + self
239 .descriptors
240 .iter()
241 .map(entry_serialized_len)
242 .sum::<usize>()
243 }
244
245 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
246 let len = self.serialized_len();
247 if buf.len() < len {
248 return Err(Error::OutputBufferTooSmall {
249 need: len,
250 have: buf.len(),
251 });
252 }
253 if self.descriptors.is_empty() {
254 buf[0] = 0x00;
255 buf[1] = 0x00;
256 return Ok(COMPAT_DESC_LEN_FIELD);
257 }
258 let body_len = len - COMPAT_DESC_LEN_FIELD;
259 if body_len > u16::MAX as usize {
260 return Err(Error::SectionLengthOverflow {
261 declared: body_len,
262 available: u16::MAX as usize,
263 });
264 }
265 if self.descriptors.len() > u16::MAX as usize {
266 return Err(Error::SectionLengthOverflow {
267 declared: self.descriptors.len(),
268 available: u16::MAX as usize,
269 });
270 }
271 buf[..COMPAT_DESC_LEN_FIELD].copy_from_slice(&(body_len as u16).to_be_bytes());
272 buf[COMPAT_DESC_LEN_FIELD..COMPAT_DESC_LEN_FIELD + DESC_COUNT_FIELD]
273 .copy_from_slice(&(self.descriptors.len() as u16).to_be_bytes());
274 let mut pos = COMPAT_DESC_LEN_FIELD + DESC_COUNT_FIELD;
275 for entry in &self.descriptors {
276 let entry_body_len = entry_serialized_len(entry) - DESC_HEADER_LEN;
277 if entry_body_len > u8::MAX as usize {
278 return Err(Error::SectionLengthOverflow {
279 declared: entry_body_len,
280 available: u8::MAX as usize,
281 });
282 }
283 buf[pos] = entry.descriptor_type;
284 buf[pos + 1] = entry_body_len as u8;
285 buf[pos + DESC_HEADER_LEN] = entry.specifier_type;
286 buf[pos + DESC_HEADER_LEN + 1..pos + DESC_HEADER_LEN + 4]
287 .copy_from_slice(&entry.specifier_data);
288 buf[pos + DESC_HEADER_LEN + 4..pos + DESC_HEADER_LEN + 6]
289 .copy_from_slice(&entry.model.to_be_bytes());
290 buf[pos + DESC_HEADER_LEN + 6..pos + DESC_HEADER_LEN + 8]
291 .copy_from_slice(&entry.version.to_be_bytes());
292 if entry.sub_descriptors.len() > u8::MAX as usize {
293 return Err(Error::SectionLengthOverflow {
294 declared: entry.sub_descriptors.len(),
295 available: u8::MAX as usize,
296 });
297 }
298 buf[pos + DESC_HEADER_LEN + 8] = entry.sub_descriptors.len() as u8;
299 pos += DESC_HEADER_LEN + DESC_FIXED_LEN;
300 for sd in &entry.sub_descriptors {
301 buf[pos] = sd.sub_descriptor_type;
302 if sd.data.len() > u8::MAX as usize {
303 return Err(Error::SectionLengthOverflow {
304 declared: sd.data.len(),
305 available: u8::MAX as usize,
306 });
307 }
308 buf[pos + 1] = sd.data.len() as u8;
309 pos += SUB_DESC_HEADER_LEN;
310 buf[pos..pos + sd.data.len()].copy_from_slice(sd.data);
311 pos += sd.data.len();
312 }
313 }
314 Ok(len)
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321
322 #[test]
323 fn empty_round_trip() {
324 let cd = CompatibilityDescriptor {
325 descriptors: vec![],
326 };
327 let mut buf = vec![0u8; cd.serialized_len()];
328 cd.serialize_into(&mut buf).unwrap();
329 assert_eq!(buf, &[0x00, 0x00]);
330 let re = CompatibilityDescriptor::parse(&buf).unwrap();
331 assert!(re.descriptors.is_empty());
332 }
333
334 #[test]
335 fn empty_with_count_parses_to_empty() {
336 let bytes: &[u8] = &[0x00, 0x02, 0x00, 0x00];
337 let cd = CompatibilityDescriptor::parse(bytes).unwrap();
338 assert!(cd.descriptors.is_empty());
339 let mut buf = vec![0u8; cd.serialized_len()];
340 cd.serialize_into(&mut buf).unwrap();
341 assert_eq!(buf, &[0x00, 0x00]);
342 }
343
344 #[test]
348 fn hand_built_byte_anchor() {
349 let bytes: &[u8] = &[
353 0x00, 0x11, 0x00, 0x01, 0x01, 0x0D, 0x01, 0x00, 0x15, 0x0A, 0x12, 0x34, 0x00, 0x01,
354 0x01, 0x05, 0x02, 0xAA, 0xBB,
355 ];
356 let cd = CompatibilityDescriptor::parse(bytes).unwrap();
357 assert_eq!(cd.descriptors.len(), 1);
358 let e = &cd.descriptors[0];
359 assert_eq!(e.descriptor_type, 0x01);
360 assert_eq!(e.specifier_type, 0x01);
361 assert_eq!(e.specifier_data, [0x00, 0x15, 0x0A]);
362 assert_eq!(e.model, 0x1234);
363 assert_eq!(e.version, 0x0001);
364 assert_eq!(e.sub_descriptors.len(), 1);
365 assert_eq!(e.sub_descriptors[0].sub_descriptor_type, 0x05);
366 assert_eq!(e.sub_descriptors[0].data, &[0xAA, 0xBB]);
367 let mut buf = vec![0u8; cd.serialized_len()];
369 cd.serialize_into(&mut buf).unwrap();
370 assert_eq!(buf, bytes);
371 }
372
373 #[test]
374 fn rejects_trailing_bytes() {
375 let bytes: &[u8] = &[0x00, 0x03, 0x00, 0x00, 0xFF];
377 assert!(matches!(
378 CompatibilityDescriptor::parse(bytes).unwrap_err(),
379 Error::InvalidDescriptor { .. }
380 ));
381 }
382
383 #[test]
384 fn rejects_truncated_entry_header() {
385 let bytes: &[u8] = &[0x00, 0x03, 0x00, 0x01, 0x01];
387 assert!(CompatibilityDescriptor::parse(bytes).is_err());
388 }
389
390 #[test]
391 fn rejects_truncated_sub_descriptor() {
392 let bytes: &[u8] = &[
395 0x00, 0x0D, 0x00, 0x01, 0x01, 0x09, 0x01, 0x00, 0x15, 0x0A, 0x12, 0x34, 0x00, 0x01,
396 0x01,
397 ];
398 assert!(CompatibilityDescriptor::parse(bytes).is_err());
399 }
400
401 #[test]
402 fn one_descriptor_with_sub_round_trip() {
403 let cd = CompatibilityDescriptor {
404 descriptors: vec![CompatibilityDescriptorEntry {
405 descriptor_type: 0x01,
406 specifier_type: 0x01,
407 specifier_data: [0x00, 0x15, 0x0A],
408 model: 0x1234,
409 version: 0x0001,
410 sub_descriptors: vec![
411 SubDescriptor {
412 sub_descriptor_type: 0x01,
413 data: &[0xAA, 0xBB],
414 },
415 SubDescriptor {
416 sub_descriptor_type: 0x02,
417 data: &[0xCC],
418 },
419 ],
420 }],
421 };
422 let mut buf = vec![0u8; cd.serialized_len()];
423 cd.serialize_into(&mut buf).unwrap();
424 let re = CompatibilityDescriptor::parse(&buf).unwrap();
425 assert_eq!(re.descriptors.len(), 1);
426 let e = &re.descriptors[0];
427 assert_eq!(e.descriptor_type, 0x01);
428 assert_eq!(e.specifier_type, 0x01);
429 assert_eq!(e.specifier_data, [0x00, 0x15, 0x0A]);
430 assert_eq!(e.model, 0x1234);
431 assert_eq!(e.version, 0x0001);
432 assert_eq!(e.sub_descriptors.len(), 2);
433 assert_eq!(e.sub_descriptors[0].sub_descriptor_type, 0x01);
434 assert_eq!(e.sub_descriptors[0].data, &[0xAA, 0xBB]);
435 assert_eq!(e.sub_descriptors[1].sub_descriptor_type, 0x02);
436 assert_eq!(e.sub_descriptors[1].data, &[0xCC]);
437 let mut buf2 = vec![0u8; cd.serialized_len()];
438 cd.serialize_into(&mut buf2).unwrap();
439 assert_eq!(buf, buf2, "byte-exact re-serialize");
440 assert_eq!(re, cd);
441 }
442
443 #[test]
444 fn two_descriptors_round_trip() {
445 let cd = CompatibilityDescriptor {
446 descriptors: vec![
447 CompatibilityDescriptorEntry {
448 descriptor_type: 0x01,
449 specifier_type: 0x01,
450 specifier_data: [0x00, 0x00, 0x00],
451 model: 0x0000,
452 version: 0x0000,
453 sub_descriptors: vec![],
454 },
455 CompatibilityDescriptorEntry {
456 descriptor_type: 0x02,
457 specifier_type: 0x01,
458 specifier_data: [0x00, 0x15, 0x5A],
459 model: 0x0100,
460 version: 0x0002,
461 sub_descriptors: vec![SubDescriptor {
462 sub_descriptor_type: 0x80,
463 data: &[0xDE, 0xAD, 0xBE, 0xEF],
464 }],
465 },
466 ],
467 };
468 let mut buf = vec![0u8; cd.serialized_len()];
469 cd.serialize_into(&mut buf).unwrap();
470 let re = CompatibilityDescriptor::parse(&buf).unwrap();
471 assert_eq!(re, cd);
472 }
473
474 #[test]
475 fn parse_rejects_short_buffer() {
476 assert!(matches!(
477 CompatibilityDescriptor::parse(&[0x00]).unwrap_err(),
478 Error::BufferTooShort { .. }
479 ));
480 }
481
482 #[test]
483 fn parse_rejects_truncated_body() {
484 assert!(matches!(
485 CompatibilityDescriptor::parse(&[0x00, 0x05, 0x00, 0x01]).unwrap_err(),
486 Error::SectionLengthOverflow { .. }
487 ));
488 }
489
490 #[test]
491 fn parse_rejects_descriptor_length_too_short() {
492 let bytes: &[u8] = &[
493 0x00, 0x06, 0x00, 0x01, 0x01, 0x02, 0xAA, 0xBB, ];
498 assert!(matches!(
499 CompatibilityDescriptor::parse(bytes).unwrap_err(),
500 Error::InvalidDescriptor { .. }
501 ));
502 }
503
504 #[test]
505 fn serialize_rejects_small_buffer() {
506 let cd = CompatibilityDescriptor {
507 descriptors: vec![],
508 };
509 assert!(matches!(
510 cd.serialize_into(&mut [0u8; 1]).unwrap_err(),
511 Error::OutputBufferTooSmall { .. }
512 ));
513 }
514}