1use alloc::vec::Vec;
8
9use crate::error::{Error, Result};
10use broadcast_common::{Parse, Serialize, crc32_mpeg2};
11
12pub const PACKET_START_CODE_PREFIX: u32 = 0x00_0001;
14pub const MAP_STREAM_ID: u8 = 0xBC;
16pub const PSM_START_CODE: u32 = (PACKET_START_CODE_PREFIX << 8) | MAP_STREAM_ID as u32;
18
19const PREFIX_LEN: usize = 6;
21
22const MAP_LENGTH_MAX: usize = 1018;
24const FIXED_BODY_LEN: usize = 6;
27const CRC_LEN: usize = 4;
29const ES_ENTRY_HEADER_LEN: usize = 4;
31const PSEUDO_DESCRIPTOR_LEN: usize = 3;
34const PSEUDO_DESCRIPTOR_TAG: u8 = 0x00;
36const MARKER_BIT: u8 = 0x80;
38const EXTENSION_MASK: u8 = 0x7F;
40const FLAGS_RESERVED_BIT: u8 = 0x20;
42const VERSION_BITS: u32 = 5;
44const VERSION_MASK: u8 = 0x1F;
46
47#[derive(Debug, Clone, PartialEq, Eq)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize))]
50pub struct EsMapEntry<'a> {
51 pub stream_type: u8,
53 pub elementary_stream_id: u8,
55 pub stream_id_extension: Option<u8>,
58 #[cfg_attr(feature = "serde", serde(skip))]
60 pub descriptors: &'a [u8],
61}
62
63#[derive(Debug, Clone, PartialEq, Eq)]
65#[cfg_attr(feature = "serde", derive(serde::Serialize))]
66pub struct ProgramStreamMap<'a> {
67 pub current_next_indicator: bool,
69 pub single_extension_stream_flag: bool,
71 pub version: u8,
73 #[cfg_attr(feature = "serde", serde(skip))]
75 pub program_stream_info: &'a [u8],
76 pub elementary_stream_map: Vec<EsMapEntry<'a>>,
78 pub crc: u32,
80}
81
82impl<'a> Parse<'a> for ProgramStreamMap<'a> {
83 type Error = Error;
84
85 fn parse(b: &'a [u8]) -> Result<Self> {
86 if b.len() < PREFIX_LEN + 2 + 4 {
87 return Err(Error::BufferTooShort {
89 need: PREFIX_LEN + 2 + 4,
90 have: b.len(),
91 what: "program_stream_map",
92 });
93 }
94
95 let start = u32::from_be_bytes([0, b[0], b[1], b[2]]);
97 if start != PACKET_START_CODE_PREFIX {
98 return Err(Error::BadMapStreamId(b[3]));
99 }
100 if b[3] != MAP_STREAM_ID {
101 return Err(Error::BadMapStreamId(b[3]));
102 }
103
104 let map_length = u16::from_be_bytes([b[4], b[5]]) as usize;
105 let crc_end = PREFIX_LEN + map_length + 4;
106 if b.len() < crc_end {
107 return Err(Error::MapLengthOverflow {
108 map_length,
109 available: b.len().saturating_sub(PREFIX_LEN),
110 });
111 }
112
113 let crc_data_end = crc_end - 4;
115 let crc_data = &b[0..crc_data_end];
116 let stored_crc = u32::from_be_bytes([
117 b[crc_data_end],
118 b[crc_data_end + 1],
119 b[crc_data_end + 2],
120 b[crc_data_end + 3],
121 ]);
122 let computed_crc = crc32_mpeg2::compute(crc_data);
123 if computed_crc != stored_crc {
124 return Err(Error::BadCrc {
125 computed: computed_crc,
126 stored: stored_crc,
127 });
128 }
129
130 let flags = b[6];
132 let current_next_indicator = flags & 0x80 != 0;
133 let single_extension_stream_flag = flags & 0x40 != 0;
134 let version = flags & VERSION_MASK;
135
136 if b[7] & 0x01 == 0 {
138 return Err(Error::BadMarker("program_stream_map marker_bit"));
139 }
140
141 let program_stream_info_length = u16::from_be_bytes([b[8], b[9]]) as usize;
142
143 let info_start = PREFIX_LEN + 4; let info_end = info_start + program_stream_info_length;
145
146 if crc_data_end < info_end + 2 {
150 return Err(Error::MapLengthOverflow {
151 map_length,
152 available: b.len().saturating_sub(PREFIX_LEN),
153 });
154 }
155 let elementary_stream_map_length =
156 u16::from_be_bytes([b[info_end], b[info_end + 1]]) as usize;
157
158 let es_start = info_end + 2; let es_end = es_start + elementary_stream_map_length;
160
161 if crc_data_end < es_end {
162 return Err(Error::MapLengthOverflow {
163 map_length,
164 available: b.len().saturating_sub(PREFIX_LEN),
165 });
166 }
167
168 let program_stream_info = &b[info_start..info_end];
169
170 let es_data = &b[es_start..es_end];
172 let elementary_stream_map = parse_es_loop(es_data, single_extension_stream_flag)?;
173
174 Ok(ProgramStreamMap {
175 current_next_indicator,
176 single_extension_stream_flag,
177 version,
178 program_stream_info,
179 elementary_stream_map,
180 crc: stored_crc,
181 })
182 }
183}
184
185fn parse_es_loop(data: &[u8], single_flag: bool) -> Result<Vec<EsMapEntry<'_>>> {
186 let mut entries = Vec::new();
187 let mut pos = 0;
188 while pos + 4 <= data.len() {
189 let stream_type = data[pos];
190 let elementary_stream_id = data[pos + 1];
191 let es_info_length = u16::from_be_bytes([data[pos + 2], data[pos + 3]]) as usize;
192 let entry_hdr_end = pos + 4;
193 let entry_end = entry_hdr_end + es_info_length;
194 if entry_end > data.len() {
195 return Err(Error::BufferTooShort {
196 need: entry_end,
197 have: data.len(),
198 what: "elementary_stream_map entry descriptors",
199 });
200 }
201
202 let (stream_id_extension, descriptors) = if elementary_stream_id == 0xFD && !single_flag {
203 if es_info_length < 3 {
205 return Err(Error::BufferTooShort {
206 need: 3,
207 have: es_info_length,
208 what: "pseudo descriptor for stream_id_extension",
209 });
210 }
211 if data[entry_hdr_end + 2] & 0x80 == 0 {
213 return Err(Error::BadMarker("elementary_stream_id_extension marker"));
214 }
215 let ext = data[entry_hdr_end + 2] & 0x7F;
216 let desc = &data[entry_hdr_end + 3..entry_end];
217 (Some(ext), desc)
218 } else {
219 let desc = &data[entry_hdr_end..entry_end];
220 (None, desc)
221 };
222
223 entries.push(EsMapEntry {
224 stream_type,
225 elementary_stream_id,
226 stream_id_extension,
227 descriptors,
228 });
229
230 pos = entry_end;
231 }
232 Ok(entries)
233}
234
235fn es_entry_len(e: &EsMapEntry<'_>) -> usize {
239 ES_ENTRY_HEADER_LEN
240 + if e.stream_id_extension.is_some() {
241 PSEUDO_DESCRIPTOR_LEN
242 } else {
243 0
244 }
245 + e.descriptors.len()
246}
247
248fn write_es_loop(entries: &[EsMapEntry<'_>], out: &mut [u8]) -> Result<()> {
252 let mut at = 0usize;
253 for e in entries {
254 let entry_len = es_entry_len(e);
255 let dst = &mut out[at..at + entry_len];
256 dst[0] = e.stream_type;
257 dst[1] = e.elementary_stream_id;
258 let info_len = entry_len - ES_ENTRY_HEADER_LEN;
259 let info_len =
260 broadcast_common::len::fit_u16(info_len, "elementary_stream_map.ES_info_length")?;
261 dst[2..4].copy_from_slice(&info_len.to_be_bytes());
262 let mut c = ES_ENTRY_HEADER_LEN;
263 if let Some(ext) = e.stream_id_extension {
264 dst[c] = PSEUDO_DESCRIPTOR_TAG;
265 dst[c + 1] = broadcast_common::len::fit_u8(
269 1 + e.descriptors.len(),
270 "elementary_stream_map.pseudo_descriptor_length",
271 )?;
272 dst[c + 2] = MARKER_BIT | (ext & EXTENSION_MASK);
273 c += PSEUDO_DESCRIPTOR_LEN;
274 }
275 dst[c..].copy_from_slice(e.descriptors);
276 at += entry_len;
277 }
278 Ok(())
279}
280
281impl Serialize for ProgramStreamMap<'_> {
282 type Error = Error;
283
284 fn serialized_len(&self) -> usize {
285 let prog_info_len = self.program_stream_info.len();
286 let es_loop_len: usize = self.elementary_stream_map.iter().map(es_entry_len).sum();
287 PREFIX_LEN + FIXED_BODY_LEN + prog_info_len + es_loop_len + CRC_LEN
290 }
291
292 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
293 let total = self.serialized_len();
294 if buf.len() < total {
295 return Err(Error::BufferTooShort {
296 need: total,
297 have: buf.len(),
298 what: "program_stream_map serialize output",
299 });
300 }
301
302 buf[0..3].copy_from_slice(&PACKET_START_CODE_PREFIX.to_be_bytes()[1..]);
304 buf[3] = MAP_STREAM_ID;
306
307 let prog_info_len = self.program_stream_info.len();
308 let es_loop_len: usize = self.elementary_stream_map.iter().map(es_entry_len).sum();
309
310 let map_length = FIXED_BODY_LEN + prog_info_len + es_loop_len;
312 if map_length > MAP_LENGTH_MAX {
315 return Err(broadcast_common::len::FieldOverflow {
316 field: "program_stream_map.program_stream_map_length",
317 value: map_length as u64,
318 max: MAP_LENGTH_MAX as u64,
319 }
320 .into());
321 }
322 let map_length = broadcast_common::len::fit_u16(
323 map_length,
324 "program_stream_map.program_stream_map_length",
325 )?;
326 buf[4..6].copy_from_slice(&map_length.to_be_bytes());
327
328 let version = broadcast_common::len::fit_bits(
332 u64::from(self.version),
333 VERSION_BITS,
334 "program_stream_map.program_stream_map_version",
335 )? as u8;
336 buf[6] = (u8::from(self.current_next_indicator) << 7)
337 | (u8::from(self.single_extension_stream_flag) << 6)
338 | FLAGS_RESERVED_BIT
339 | version;
340
341 buf[7] = 0xFF;
347
348 let prog_info_len_u16 = broadcast_common::len::fit_u16(
353 prog_info_len,
354 "program_stream_map.program_stream_info_length",
355 )?;
356 let es_loop_len_u16 = broadcast_common::len::fit_u16(
357 es_loop_len,
358 "program_stream_map.elementary_stream_map_length",
359 )?;
360 buf[8..10].copy_from_slice(&prog_info_len_u16.to_be_bytes());
361
362 buf[10..10 + prog_info_len].copy_from_slice(self.program_stream_info);
366
367 let es_len_start = 10 + prog_info_len;
369 buf[es_len_start..es_len_start + 2].copy_from_slice(&es_loop_len_u16.to_be_bytes());
370 let es_start = es_len_start + 2;
371 write_es_loop(
372 &self.elementary_stream_map,
373 &mut buf[es_start..es_start + es_loop_len],
374 )?;
375
376 let crc_offset = es_start + es_loop_len;
378 let crc = crc32_mpeg2::compute(&buf[0..crc_offset]);
379 buf[crc_offset..crc_offset + 4].copy_from_slice(&crc.to_be_bytes());
380
381 Ok(total)
382 }
383}
384
385#[cfg(test)]
386mod tests {
387 use super::*;
388 use alloc::vec;
389
390 #[test]
391 fn serialize_rejects_version_over_5_bits() {
392 let psm = ProgramStreamMap {
393 current_next_indicator: true,
394 single_extension_stream_flag: false,
395 version: 0x20,
396 program_stream_info: &[],
397 elementary_stream_map: vec![],
398 crc: 0,
399 };
400 let mut buf = vec![0u8; 64];
401 assert!(matches!(
402 psm.serialize_into(&mut buf),
403 Err(Error::FieldOverflow(_))
404 ));
405 }
406
407 #[test]
409 fn psm_build_and_round_trip() {
410 let entries = vec![EsMapEntry {
411 stream_type: 0x02, elementary_stream_id: 0xE0,
413 stream_id_extension: None,
414 descriptors: &[0x0A, 0x04, b'H', b'E', b'L', b'L'], }];
416
417 let psm = ProgramStreamMap {
418 current_next_indicator: true,
419 single_extension_stream_flag: false,
420 version: 3,
421 program_stream_info: &[],
422 elementary_stream_map: entries,
423 crc: 0, };
425
426 let mut buf = vec![0u8; psm.serialized_len()];
427 psm.serialize_into(&mut buf).unwrap();
428
429 let parsed = ProgramStreamMap::parse(&buf).unwrap();
431 assert!(parsed.current_next_indicator);
432 assert!(!parsed.single_extension_stream_flag);
433 assert_eq!(parsed.version, 3);
434 assert!(parsed.program_stream_info.is_empty());
435 assert_eq!(parsed.elementary_stream_map.len(), 1);
436 assert_eq!(parsed.elementary_stream_map[0].stream_type, 0x02);
437 assert_eq!(parsed.elementary_stream_map[0].elementary_stream_id, 0xE0);
438 assert!(
439 parsed.elementary_stream_map[0]
440 .stream_id_extension
441 .is_none()
442 );
443 assert_eq!(
444 parsed.elementary_stream_map[0].descriptors,
445 &[0x0A, 0x04, b'H', b'E', b'L', b'L']
446 );
447
448 let mut out2 = vec![0u8; parsed.serialized_len()];
450 parsed.serialize_into(&mut out2).unwrap();
451 assert_eq!(&out2[..], &buf[..], "byte-exact round-trip mismatch");
452
453 let psm_mut = ProgramStreamMap {
455 current_next_indicator: true,
456 single_extension_stream_flag: false,
457 version: 7,
458 program_stream_info: &[],
459 elementary_stream_map: vec![EsMapEntry {
460 stream_type: 0x02,
461 elementary_stream_id: 0xE0,
462 stream_id_extension: None,
463 descriptors: &[0x0A, 0x04, b'H', b'E', b'L', b'L'],
464 }],
465 crc: 0,
466 };
467 let mut out3 = vec![0u8; psm_mut.serialized_len()];
468 psm_mut.serialize_into(&mut out3).unwrap();
469 assert_ne!(&buf[..], &out3[..]);
470 }
471
472 #[test]
473 fn psm_with_stream_id_extension() {
474 let entries = vec![EsMapEntry {
475 stream_type: 0x06, elementary_stream_id: 0xFD,
477 stream_id_extension: Some(0x0F),
478 descriptors: &[0x59, 0x02, 0x01, 0x02], }];
480
481 let psm = ProgramStreamMap {
482 current_next_indicator: true,
483 single_extension_stream_flag: false,
484 version: 1,
485 program_stream_info: &[],
486 elementary_stream_map: entries,
487 crc: 0,
488 };
489
490 let mut buf = vec![0u8; psm.serialized_len()];
491 psm.serialize_into(&mut buf).unwrap();
492
493 let parsed = ProgramStreamMap::parse(&buf).unwrap();
494 assert_eq!(parsed.elementary_stream_map.len(), 1);
495 assert_eq!(
496 parsed.elementary_stream_map[0].stream_id_extension,
497 Some(0x0F)
498 );
499 assert_eq!(
500 parsed.elementary_stream_map[0].descriptors,
501 &[0x59, 0x02, 0x01, 0x02]
502 );
503
504 let mut out2 = vec![0u8; parsed.serialized_len()];
506 parsed.serialize_into(&mut out2).unwrap();
507 assert_eq!(&out2[..], &buf[..]);
508 }
509
510 #[test]
515 fn pseudo_descriptor_length_overflow_is_rejected_not_wrapped() {
516 let entries = vec![EsMapEntry {
517 stream_type: 0x06,
518 elementary_stream_id: 0xFD,
519 stream_id_extension: Some(0x01),
520 descriptors: &[0u8; 255],
521 }];
522 let psm = ProgramStreamMap {
523 current_next_indicator: true,
524 single_extension_stream_flag: false,
525 version: 0,
526 program_stream_info: &[],
527 elementary_stream_map: entries,
528 crc: 0,
529 };
530 let mut buf = vec![0u8; psm.serialized_len()];
531 assert!(psm.serialize_into(&mut buf).is_err());
532 }
533
534 #[test]
537 fn program_stream_map_length_over_spec_max_is_rejected() {
538 let psm = ProgramStreamMap {
539 current_next_indicator: true,
540 single_extension_stream_flag: false,
541 version: 0,
542 program_stream_info: &[0u8; 1019],
543 elementary_stream_map: vec![],
544 crc: 0,
545 };
546 let mut buf = vec![0u8; psm.serialized_len()];
547 assert!(psm.serialize_into(&mut buf).is_err());
548 }
549
550 #[test]
552 fn program_stream_map_length_at_spec_max_round_trips() {
553 let psm = ProgramStreamMap {
555 current_next_indicator: true,
556 single_extension_stream_flag: false,
557 version: 0,
558 program_stream_info: &[0u8; 1012],
559 elementary_stream_map: vec![],
560 crc: 0,
561 };
562 let mut buf = vec![0u8; psm.serialized_len()];
563 psm.serialize_into(&mut buf).unwrap();
564 let parsed = ProgramStreamMap::parse(&buf).unwrap();
565 assert_eq!(parsed.program_stream_info.len(), 1012);
566 }
567
568 #[test]
580 fn psm_with_nonempty_program_descriptor_loop() {
581 let prog_descriptor: &[u8] = &[0x05, 0x04, b'T', b'E', b'S', b'T'];
583 let entries = vec![EsMapEntry {
584 stream_type: 0x02, elementary_stream_id: 0xE0,
586 stream_id_extension: None,
587 descriptors: &[],
588 }];
589
590 let psm = ProgramStreamMap {
591 current_next_indicator: true,
592 single_extension_stream_flag: false,
593 version: 5,
594 program_stream_info: prog_descriptor,
595 elementary_stream_map: entries,
596 crc: 0,
597 };
598
599 let mut buf = vec![0u8; psm.serialized_len()];
600 psm.serialize_into(&mut buf).unwrap();
601
602 assert_eq!(&buf[10..16], prog_descriptor);
606 let es_map_len = u16::from_be_bytes([buf[16], buf[17]]);
607 assert_eq!(es_map_len, 4, "one ES entry: stream_type+id+info_len(0)");
608
609 let parsed = ProgramStreamMap::parse(&buf).unwrap();
610 assert_eq!(parsed.program_stream_info, prog_descriptor);
611 assert_eq!(parsed.elementary_stream_map.len(), 1);
612 assert_eq!(parsed.elementary_stream_map[0].stream_type, 0x02);
613 assert_eq!(parsed.elementary_stream_map[0].elementary_stream_id, 0xE0);
614
615 let mut out2 = vec![0u8; parsed.serialized_len()];
617 parsed.serialize_into(&mut out2).unwrap();
618 assert_eq!(&out2[..], &buf[..]);
619 }
620
621 #[test]
628 fn reserved_bits_are_set_by_convention() {
629 let psm = ProgramStreamMap {
630 current_next_indicator: false,
631 single_extension_stream_flag: false,
632 version: 0,
633 program_stream_info: &[],
634 elementary_stream_map: vec![],
635 crc: 0,
636 };
637 let mut buf = vec![0u8; psm.serialized_len()];
638 psm.serialize_into(&mut buf).unwrap();
639 assert_eq!(
640 buf[6], 0x20,
641 "flags byte reserved bit (0x20) must be set even with both flags clear"
642 );
643 assert_eq!(buf[7], 0xFF, "reserved(7)+marker_bit(1) byte must be 0xFF");
644 }
645
646 #[test]
647 fn psm_bad_crc_rejected() {
648 let psm = ProgramStreamMap {
649 current_next_indicator: true,
650 single_extension_stream_flag: false,
651 version: 0,
652 program_stream_info: &[],
653 elementary_stream_map: vec![],
654 crc: 0,
655 };
656 let mut buf = vec![0u8; psm.serialized_len()];
657 psm.serialize_into(&mut buf).unwrap();
658 let crc_off = buf.len() - 4;
660 buf[crc_off] ^= 0xFF;
661 assert!(matches!(
662 ProgramStreamMap::parse(&buf),
663 Err(Error::BadCrc { .. })
664 ));
665 }
666}