1use alloc::vec::Vec;
9
10use crate::error::{Error, Result};
11use broadcast_common::{Parse, Serialize};
12
13pub const SYSTEM_HEADER_START_CODE: u32 = 0x0000_01BB;
15
16const EXT_STREAM_ID: u8 = 0xB7;
18
19pub(crate) const PREFIX_LEN: usize = 6;
21const RESERVED_BITS_MASK: u8 = 0x7F;
23
24#[derive(Debug, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize))]
27pub struct StdBufferBound {
28 pub stream_id: u8,
30 pub stream_id_extension: Option<u8>,
33 pub buffer_bound_scale: bool,
35 pub buffer_size_bound: u16,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq)]
41#[cfg_attr(feature = "serde", derive(serde::Serialize))]
42pub struct SystemHeader {
43 pub rate_bound: u32,
45 pub audio_bound: u8,
47 pub fixed_flag: bool,
49 pub csps_flag: bool,
51 pub system_audio_lock_flag: bool,
53 pub system_video_lock_flag: bool,
55 pub video_bound: u8,
57 pub packet_rate_restriction_flag: bool,
59 pub reserved_bits: u8,
64 pub std_buffer_bounds: Vec<StdBufferBound>,
66 pub trailing_reserved: Vec<u8>,
71}
72
73fn stream_loop_len(system_header: &SystemHeader) -> usize {
81 let mut len: usize = 0;
82 for b in &system_header.std_buffer_bounds {
83 if b.stream_id_extension.is_some() {
84 len += 6;
85 } else {
86 len += 3;
87 }
88 }
89 len + system_header.trailing_reserved.len()
90}
91
92impl<'a> Parse<'a> for SystemHeader {
93 type Error = Error;
94
95 fn parse(b: &'a [u8]) -> Result<Self> {
96 if b.len() < PREFIX_LEN {
97 return Err(Error::BufferTooShort {
98 need: PREFIX_LEN,
99 have: b.len(),
100 what: "system_header prefix",
101 });
102 }
103
104 if u32::from_be_bytes([b[0], b[1], b[2], b[3]]) != SYSTEM_HEADER_START_CODE {
105 return Err(Error::BadSystemHeaderStartCode(u32::from_be_bytes([
106 b[0], b[1], b[2], b[3],
107 ])));
108 }
109
110 let header_length = u16::from_be_bytes([b[4], b[5]]) as usize;
111 let body_end = PREFIX_LEN + header_length;
112 if b.len() < body_end {
113 return Err(Error::HeaderLengthOverflow {
114 header_length,
115 available: b.len().saturating_sub(PREFIX_LEN),
116 });
117 }
118 let body = &b[PREFIX_LEN..body_end];
119
120 if body.len() < 6 {
129 return Err(Error::BufferTooShort {
130 need: 6 + PREFIX_LEN,
131 have: b.len(),
132 what: "system_header fixed body",
133 });
134 }
135
136 if body[0] & 0x80 == 0 {
138 return Err(Error::BadMarker("system_header rate_bound marker 1"));
139 }
140 if body[2] & 0x01 == 0 {
141 return Err(Error::BadMarker("system_header rate_bound marker 2"));
142 }
143 if body[4] & 0x20 == 0 {
144 return Err(Error::BadMarker("system_header video_bound marker"));
145 }
146
147 let rate_bound = ((u32::from(body[0] & 0x7F) << 15)
149 | (u32::from(body[1]) << 7)
150 | u32::from(body[2] >> 1))
151 & 0x3F_FFFF;
152
153 let audio_bound = (body[3] >> 2) & 0x3F;
155 let fixed_flag = body[3] & 0x02 != 0;
156 let csps_flag = body[3] & 0x01 != 0;
157
158 let system_audio_lock_flag = body[4] & 0x80 != 0;
160 let system_video_lock_flag = body[4] & 0x40 != 0;
161 let video_bound = body[4] & 0x1F;
166
167 let packet_rate_restriction_flag = body[5] & 0x80 != 0;
169 let reserved_bits = body[5] & RESERVED_BITS_MASK;
170
171 let mut pos = 6;
173 let mut std_buffer_bounds = Vec::new();
174 while pos < body.len() && body[pos] & 0x80 != 0 {
175 let stream_id = body[pos];
176 if stream_id == EXT_STREAM_ID {
177 if pos + 6 > body.len() {
179 return Err(Error::BufferTooShort {
180 need: pos + 6,
181 have: body.len(),
182 what: "system_header extended stream entry",
183 });
184 }
185 if body[pos + 1] & 0xC0 != 0xC0 {
187 return Err(Error::BadStreamIdExtensionPrefix(body[pos + 1]));
188 }
189 let stream_id_extension = body[pos + 2] & 0x7F;
191 if body[pos + 3] != 0xB6 {
193 return Err(Error::BadStreamIdExtensionPrefix(body[pos + 3]));
194 }
195 if body[pos + 4] & 0xC0 != 0xC0 {
197 return Err(Error::BadMarker("P-STD_buffer_bound_scale prefix (ext)"));
198 }
199 let buffer_bound_scale = body[pos + 4] & 0x20 != 0;
200 let buffer_size_bound =
203 (u16::from(body[pos + 4] & 0x1F) << 8) | u16::from(body[pos + 5]);
204 std_buffer_bounds.push(StdBufferBound {
205 stream_id,
206 stream_id_extension: Some(stream_id_extension),
207 buffer_bound_scale,
208 buffer_size_bound,
209 });
210 pos += 6;
211 } else {
212 if pos + 3 > body.len() {
214 return Err(Error::BufferTooShort {
215 need: pos + 3,
216 have: body.len(),
217 what: "system_header stream entry",
218 });
219 }
220 if body[pos + 1] & 0xC0 != 0xC0 {
222 return Err(Error::BadMarker("P-STD_buffer_bound_scale prefix"));
223 }
224 let buffer_bound_scale = body[pos + 1] & 0x20 != 0;
225 let buffer_size_bound =
227 (u16::from(body[pos + 1] & 0x1F) << 8) | u16::from(body[pos + 2]);
228 std_buffer_bounds.push(StdBufferBound {
229 stream_id,
230 stream_id_extension: None,
231 buffer_bound_scale,
232 buffer_size_bound,
233 });
234 pos += 3;
235 }
236 }
237
238 Ok(SystemHeader {
239 rate_bound,
240 audio_bound,
241 fixed_flag,
242 csps_flag,
243 system_audio_lock_flag,
244 system_video_lock_flag,
245 video_bound,
246 packet_rate_restriction_flag,
247 reserved_bits,
248 std_buffer_bounds,
249 trailing_reserved: body[pos..].to_vec(),
250 })
251 }
252}
253
254impl SystemHeader {
255 fn validate_stream_loop(&self) -> Result<()> {
259 for b in &self.std_buffer_bounds {
260 if b.stream_id & 0x80 == 0 {
261 return Err(Error::InvalidField {
262 field: "system_header.stream_id",
263 reason: "stream_id MSB is 0, so the entry would end the stream loop on parse",
264 });
265 }
266 match b.stream_id_extension {
267 Some(ext) => {
268 if b.stream_id != EXT_STREAM_ID {
269 return Err(Error::InvalidField {
270 field: "system_header.stream_id_extension",
271 reason: "stream_id_extension requires stream_id 0xB7",
272 });
273 }
274 broadcast_common::len::fit_bits(
275 u64::from(ext),
276 7,
277 "system_header.stream_id_extension",
278 )?;
279 }
280 None => {
281 if b.stream_id == EXT_STREAM_ID {
282 return Err(Error::InvalidField {
283 field: "system_header.stream_id",
284 reason: "stream_id 0xB7 requires stream_id_extension",
285 });
286 }
287 }
288 }
289 broadcast_common::len::fit_bits(
290 u64::from(b.buffer_size_bound),
291 13,
292 "system_header.P-STD_buffer_size_bound",
293 )?;
294 }
295 if self
296 .trailing_reserved
297 .first()
298 .is_some_and(|f| f & 0x80 != 0)
299 {
300 return Err(Error::InvalidField {
301 field: "system_header.trailing_reserved",
302 reason: "first byte has its MSB set, so it would be re-read as a stream-bound entry",
303 });
304 }
305 Ok(())
306 }
307}
308
309impl Serialize for SystemHeader {
310 type Error = Error;
311
312 fn serialized_len(&self) -> usize {
313 PREFIX_LEN + 6 + stream_loop_len(self)
314 }
315
316 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
317 let total = self.serialized_len();
318 if buf.len() < total {
319 return Err(Error::BufferTooShort {
320 need: total,
321 have: buf.len(),
322 what: "system_header serialize output",
323 });
324 }
325
326 buf[0..4].copy_from_slice(&SYSTEM_HEADER_START_CODE.to_be_bytes());
328
329 let header_length = broadcast_common::len::fit_u16(
331 6 + stream_loop_len(self),
332 "system_header.header_length",
333 )?;
334 buf[4..6].copy_from_slice(&header_length.to_be_bytes());
335
336 let rate_bound = broadcast_common::len::fit_bits(
337 u64::from(self.rate_bound),
338 22,
339 "system_header.rate_bound",
340 )? as u32;
341 let audio_bound = broadcast_common::len::fit_bits(
342 u64::from(self.audio_bound),
343 6,
344 "system_header.audio_bound",
345 )? as u8;
346 let video_bound = broadcast_common::len::fit_bits(
347 u64::from(self.video_bound),
348 5,
349 "system_header.video_bound",
350 )? as u8;
351 let reserved_bits = broadcast_common::len::fit_mask(
352 self.reserved_bits,
353 RESERVED_BITS_MASK,
354 "system_header.reserved_bits",
355 )?;
356 self.validate_stream_loop()?;
357 buf[6] = 0x80 | ((rate_bound >> 15) & 0x7F) as u8;
359 buf[7] = ((rate_bound >> 7) & 0xFF) as u8;
361 buf[8] = (((rate_bound & 0x7F) as u8) << 1) | 0x01;
363 buf[9] = audio_bound << 2 | (u8::from(self.fixed_flag) << 1) | u8::from(self.csps_flag);
365 buf[10] = (u8::from(self.system_audio_lock_flag) << 7)
367 | (u8::from(self.system_video_lock_flag) << 6)
368 | 0x20 | video_bound;
370 buf[11] = (u8::from(self.packet_rate_restriction_flag) << 7) | reserved_bits;
372
373 let mut pos = 12;
375 for bound in &self.std_buffer_bounds {
376 if let Some(ext) = bound.stream_id_extension {
377 buf[pos] = bound.stream_id;
378 buf[pos + 1] = 0xC0;
379 buf[pos + 2] = ext;
380 buf[pos + 3] = 0xB6;
381 buf[pos + 4] = 0xC0
382 | (u8::from(bound.buffer_bound_scale) << 5)
383 | (bound.buffer_size_bound >> 8) as u8;
384 buf[pos + 5] = (bound.buffer_size_bound & 0xFF) as u8;
385 pos += 6;
386 } else {
387 buf[pos] = bound.stream_id;
388 buf[pos + 1] = 0xC0
389 | (u8::from(bound.buffer_bound_scale) << 5)
390 | (bound.buffer_size_bound >> 8) as u8;
391 buf[pos + 2] = (bound.buffer_size_bound & 0xFF) as u8;
392 pos += 3;
393 }
394 }
395 buf[pos..pos + self.trailing_reserved.len()].copy_from_slice(&self.trailing_reserved);
396
397 Ok(total)
398 }
399}
400
401#[cfg(test)]
402mod tests {
403 use super::*;
404 use alloc::vec;
405
406 #[test]
407 fn system_header_round_trip_no_streams() {
408 let bytes = vec![
409 0x00, 0x00, 0x01, 0xBB, 0x00, 0x06, 0x80, 0x00, 0x01, 0x04, 0x20, 0xFF, ];
416 let h = SystemHeader::parse(&bytes).unwrap();
417 assert_eq!(h.rate_bound, 0);
418 assert_eq!(h.audio_bound, 1);
419 assert!(!h.fixed_flag);
420 assert!(!h.csps_flag);
421 assert!(!h.system_audio_lock_flag);
422 assert!(!h.system_video_lock_flag);
423 assert_eq!(h.video_bound, 0);
424 assert!(h.packet_rate_restriction_flag);
425 assert!(h.std_buffer_bounds.is_empty());
426
427 let mut out = vec![0u8; h.serialized_len()];
428 h.serialize_into(&mut out).unwrap();
429 assert_eq!(&out[..], &bytes[..]);
430
431 let h2 = SystemHeader::parse(&out).unwrap();
432 assert_eq!(h, h2);
433 }
434
435 #[test]
440 fn video_bound_bit_4_round_trips() {
441 let bytes = vec![
442 0x00,
443 0x00,
444 0x01,
445 0xBB, 0x00,
447 0x06, 0x80,
449 0x00,
450 0x01, 0x04, 0x20 | 0x1F, 0xFF,
454 ];
455 let h = SystemHeader::parse(&bytes).unwrap();
456 assert_eq!(
457 h.video_bound, 31,
458 "bit 4 of video_bound must not be dropped"
459 );
460
461 let mut out = vec![0u8; h.serialized_len()];
462 h.serialize_into(&mut out).unwrap();
463 assert_eq!(&out[..], &bytes[..]);
464 }
465
466 #[test]
467 fn system_header_round_trip_with_streams() {
468 let bytes = vec![
469 0x00, 0x00, 0x01, 0xBB, 0x00,
470 0x0C, 0x80, 0x00, 0x01, 0x04, 0x20, 0xFF,
472 0xE0, 0xFF, 0xFF, 0xC0, 0xC1, 0x00,
475 ];
476 let h = SystemHeader::parse(&bytes).unwrap();
477 assert_eq!(h.std_buffer_bounds.len(), 2);
478 assert_eq!(h.std_buffer_bounds[0].stream_id, 0xE0);
479 assert!(h.std_buffer_bounds[0].stream_id_extension.is_none());
480 assert!(h.std_buffer_bounds[0].buffer_bound_scale);
481 assert_eq!(h.std_buffer_bounds[0].buffer_size_bound, 0x1FFF);
482
483 assert_eq!(h.std_buffer_bounds[1].stream_id, 0xC0);
484 assert!(h.std_buffer_bounds[1].stream_id_extension.is_none());
485 assert!(!h.std_buffer_bounds[1].buffer_bound_scale);
486 assert_eq!(h.std_buffer_bounds[1].buffer_size_bound, 0x0100);
487
488 let mut out = vec![0u8; h.serialized_len()];
489 h.serialize_into(&mut out).unwrap();
490 assert_eq!(&out[..], &bytes[..]);
491
492 let h2 = SystemHeader::parse(&out).unwrap();
493 assert_eq!(h, h2);
494
495 let h_mut = SystemHeader {
497 rate_bound: 12345,
498 ..h.clone()
499 };
500 let mut out2 = vec![0u8; h_mut.serialized_len()];
501 h_mut.serialize_into(&mut out2).unwrap();
502 assert_ne!(&out[..], &out2[..]);
503 }
504
505 #[test]
509 fn trailing_bytes_after_stream_loop_round_trip() {
510 let bytes = vec![
511 0x00,
512 0x00,
513 0x01,
514 0xBB, 0x00,
516 0x0C, 0x80,
518 0x00,
519 0x01,
520 0x04,
521 0x20 | 0x01,
522 0xFF, 0xE0,
524 0xE0,
525 0x80, 0x00,
527 0x7F,
528 0xAB, ];
530 let h = SystemHeader::parse(&bytes).unwrap();
531 assert_eq!(h.std_buffer_bounds.len(), 1);
532 assert_eq!(h.trailing_reserved, vec![0x00, 0x7F, 0xAB]);
533 let mut out = vec![0u8; h.serialized_len()];
534 h.serialize_into(&mut out).unwrap();
535 assert_eq!(out, bytes);
536 }
537
538 #[test]
541 fn non_conventional_reserved_bits_round_trip() {
542 let bytes = vec![
543 0x00, 0x00, 0x01, 0xBB, 0x00, 0x06, 0x80, 0x00, 0x01, 0x04, 0x20, 0x2A, ];
550 let h = SystemHeader::parse(&bytes).unwrap();
551 assert_eq!(h.reserved_bits, 0x2A);
552 assert!(!h.packet_rate_restriction_flag);
553 let mut out = vec![0u8; h.serialized_len()];
554 h.serialize_into(&mut out).unwrap();
555 assert_eq!(out, bytes);
556 }
557
558 #[test]
570 fn many_bounds_past_old_u16_overflow_point_errs_not_panics() {
571 let std_buffer_bounds = (0..11_000)
572 .map(|_| StdBufferBound {
573 stream_id: EXT_STREAM_ID,
574 stream_id_extension: Some(0x05),
575 buffer_bound_scale: false,
576 buffer_size_bound: 0,
577 })
578 .collect::<Vec<_>>();
579 let h = SystemHeader {
580 rate_bound: 0,
581 audio_bound: 0,
582 fixed_flag: false,
583 csps_flag: false,
584 system_audio_lock_flag: false,
585 system_video_lock_flag: false,
586 video_bound: 0,
587 packet_rate_restriction_flag: false,
588 reserved_bits: RESERVED_BITS_MASK,
589 std_buffer_bounds,
590 trailing_reserved: Vec::new(),
591 };
592 let mut buf = vec![0u8; h.serialized_len()];
596 assert!(h.serialize_into(&mut buf).is_err());
597 }
598
599 #[test]
602 fn header_length_over_u16_is_rejected_not_wrapped() {
603 let std_buffer_bounds = (0..25_000)
604 .map(|_| StdBufferBound {
605 stream_id: 0xC0,
606 stream_id_extension: None,
607 buffer_bound_scale: false,
608 buffer_size_bound: 0,
609 })
610 .collect::<Vec<_>>();
611 let h = SystemHeader {
612 rate_bound: 0,
613 audio_bound: 0,
614 fixed_flag: false,
615 csps_flag: false,
616 system_audio_lock_flag: false,
617 system_video_lock_flag: false,
618 video_bound: 0,
619 packet_rate_restriction_flag: false,
620 reserved_bits: RESERVED_BITS_MASK,
621 std_buffer_bounds,
622 trailing_reserved: Vec::new(),
623 };
624 let mut buf = vec![0u8; h.serialized_len()];
625 assert!(h.serialize_into(&mut buf).is_err());
626 }
627
628 #[test]
631 fn many_bounds_within_u16_header_length_round_trips() {
632 let std_buffer_bounds = (0..1000)
633 .map(|_| StdBufferBound {
634 stream_id: 0xC0,
635 stream_id_extension: None,
636 buffer_bound_scale: false,
637 buffer_size_bound: 0x0100,
638 })
639 .collect::<Vec<_>>();
640 let h = SystemHeader {
641 rate_bound: 0,
642 audio_bound: 0,
643 fixed_flag: false,
644 csps_flag: false,
645 system_audio_lock_flag: false,
646 system_video_lock_flag: false,
647 video_bound: 0,
648 packet_rate_restriction_flag: false,
649 reserved_bits: RESERVED_BITS_MASK,
650 std_buffer_bounds,
651 trailing_reserved: Vec::new(),
652 };
653 let mut buf = vec![0u8; h.serialized_len()];
654 h.serialize_into(&mut buf).unwrap();
655 let back = SystemHeader::parse(&buf).unwrap();
656 assert_eq!(back.std_buffer_bounds.len(), 1000);
657 }
658
659 #[test]
660 fn system_header_round_trip_extended_stream_id() {
661 let bytes = vec![
662 0x00, 0x00, 0x01, 0xBB, 0x00, 0x0C, 0x80, 0x00, 0x01, 0x04, 0x20, 0xFF,
664 0xB7, 0xC0, 0x05, 0xB6, 0xE1, 0x00,
666 ];
667 let h = SystemHeader::parse(&bytes).unwrap();
668 assert_eq!(h.std_buffer_bounds.len(), 1);
669 assert_eq!(h.std_buffer_bounds[0].stream_id, 0xB7);
670 assert_eq!(h.std_buffer_bounds[0].stream_id_extension, Some(0x05));
671 assert!(h.std_buffer_bounds[0].buffer_bound_scale);
672 assert_eq!(h.std_buffer_bounds[0].buffer_size_bound, 0x100);
673
674 let mut out = vec![0u8; h.serialized_len()];
675 h.serialize_into(&mut out).unwrap();
676 assert_eq!(&out[..], &bytes[..]);
677 }
678}