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