#![cfg(feature = "ts")]
use dvb_common::Serialize;
use dvb_si::demux::SiDemux;
use dvb_si::descriptors::parse_loop;
use dvb_si::tables::sdt::{Sdt, SdtKind};
struct Lcg(u64);
impl Lcg {
fn new(seed: u64) -> Self {
Self(seed)
}
fn next_u8(&mut self) -> u8 {
self.0 = self
.0
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1_442_695_040_888_963_407);
(self.0 >> 33) as u8
}
}
fn build_sdt_bytes() -> Vec<u8> {
use dvb_si::tables::sdt::SdtService;
let sdt = Sdt {
kind: SdtKind::Actual,
transport_stream_id: 0x1234,
version_number: 3,
current_next_indicator: true,
section_number: 0,
last_section_number: 0,
original_network_id: 0x5678,
services: vec![SdtService {
service_id: 0x0001,
eit_schedule_flag: false,
eit_present_following_flag: true,
running_status: 4,
free_ca_mode: false,
descriptors: dvb_si::descriptors::DescriptorLoop::new(&[]),
}],
};
let mut buf = vec![0u8; sdt.serialized_len()];
sdt.serialize_into(&mut buf).expect("SDT serialize");
buf
}
#[test]
fn hostility_garbage_ts_packets_no_panic() {
let mut demux = SiDemux::builder().build();
let mut lcg = Lcg::new(0xDEAD_CAFE_1234_5678u64);
const N: usize = 10_000;
for _ in 0..N {
let mut pkt = [0u8; 188];
for b in &mut pkt {
*b = lcg.next_u8();
}
let _ = demux.feed(&pkt).count();
}
let s = demux.stats();
assert_eq!(s.packets, N as u64, "packets counter must equal feed count");
assert!(
s.malformed_packets > 9_000,
"LCG garbage rarely has 0x47 sync — nearly all 10k must count as malformed (got {})",
s.malformed_packets
);
}
#[test]
fn hostility_sdt_all_truncations_no_panic() {
use dvb_si::tables::AnyTable;
let full = build_sdt_bytes();
for len in 0..=full.len() {
let prefix = &full[..len];
let _ = AnyTable::parse(prefix);
let _ = parse_loop(prefix).count();
}
}
#[test]
fn hostility_random_descriptor_loops_no_panic() {
let mut lcg = Lcg::new(0xABCD_EF01_2345_6789u64);
for _ in 0..1_000u32 {
let len_hi = lcg.next_u8();
let len_lo = lcg.next_u8();
let len = (len_hi as usize & 0x01) * 256 + len_lo as usize;
let data: Vec<u8> = (0..len).map(|_| lcg.next_u8()).collect();
let _ = parse_loop(&data).count();
}
}
#[test]
fn hostility_descriptor_loop_truncations_no_panic() {
let valid_loop: &[u8] = &[
0x4D, 0x0C, b'f', b'r', b'e', 0x07, b'J', b'o', b'u', b'r', b'n', b'a', b'l', 0x00,
];
let items: Vec<_> = parse_loop(valid_loop).collect();
assert_eq!(items.len(), 1, "one descriptor in the loop");
assert!(items[0].is_ok(), "full descriptor must parse OK");
for len in 0..valid_loop.len() {
let _ = parse_loop(&valid_loop[..len]).count();
}
}