1use alloc::vec::Vec;
10
11use broadcast_common::{Parse, Serialize};
12
13use crate::Result;
14use crate::pack_header::{PACK_START_CODE, PackHeader};
15use crate::system_header::{SYSTEM_HEADER_START_CODE, SystemHeader};
16
17const PROGRAM_END_CODE: u32 = 0x0000_01B9;
19
20#[derive(Debug, Clone)]
23pub struct Pack<'a> {
24 pub pack_header: PackHeader<'a>,
26 pub system_header: Option<SystemHeader>,
28 pub pes_packets: Vec<mpeg_pes::PesPacket<'a>>,
30}
31
32fn find_next_boundary(b: &[u8], from: usize) -> Option<usize> {
34 let mut i = from;
35 while i + 4 <= b.len() {
36 let word = u32::from_be_bytes([b[i], b[i + 1], b[i + 2], b[i + 3]]);
37 if word == PACK_START_CODE || word == PROGRAM_END_CODE {
38 return Some(i);
39 }
40 i += 1;
41 }
42 None
43}
44
45pub fn parse_pack(b: &[u8]) -> Result<(Option<Pack<'_>>, usize)> {
50 use crate::error::Error;
51
52 if b.len() < 4 {
53 return Err(Error::BufferTooShort {
54 need: 4,
55 have: b.len(),
56 what: "pack start_code or end_code",
57 });
58 }
59
60 let start = u32::from_be_bytes([b[0], b[1], b[2], b[3]]);
61 if start == PROGRAM_END_CODE {
62 return Ok((None, 4));
63 }
64
65 let pack_header = PackHeader::parse(b)?;
67 let hdr_len = pack_header.header_len();
68 let rest = &b[hdr_len..];
69
70 let boundary = find_next_boundary(rest, 0);
72
73 let (system_header, pes_start, _sh_len) = if rest.len() >= 4 {
75 let maybe_sh = u32::from_be_bytes([rest[0], rest[1], rest[2], rest[3]]);
76 if maybe_sh == SYSTEM_HEADER_START_CODE {
77 let sh = SystemHeader::parse(rest)?;
78 let slen = sh.serialized_len();
79 (Some(sh), slen, slen)
80 } else {
81 (None, 0, 0)
82 }
83 } else {
84 (None, 0, 0)
85 };
86
87 let pes_data = &rest[pes_start..];
88 let pes_end = boundary.map_or(pes_data.len(), |b| {
93 b.saturating_sub(pes_start).min(pes_data.len())
94 });
95
96 let (pes_packets, _pes_consumed) = parse_pes_loop(&pes_data[..pes_end])?;
98
99 let consumed = hdr_len + pes_start + _pes_consumed;
100 Ok((
101 Some(Pack {
102 pack_header,
103 system_header,
104 pes_packets,
105 }),
106 consumed,
107 ))
108}
109
110fn parse_pes_loop(data: &[u8]) -> Result<(Vec<mpeg_pes::PesPacket<'_>>, usize)> {
111 use crate::error::Error;
112
113 let mut packets = Vec::new();
114 let mut pos = 0;
115
116 while pos + 6 <= data.len()
117 && data[pos] == 0x00
118 && data[pos + 1] == 0x00
119 && data[pos + 2] == 0x01
120 {
121 match mpeg_pes::PesPacket::parse(&data[pos..]) {
122 Ok(pkt) => {
123 let pkt_len = pkt.serialized_len();
124 packets.push(pkt);
125 pos += pkt_len;
126 }
127 Err(e) => return Err(Error::Pes(e)),
128 }
129 }
130
131 Ok((packets, pos))
132}
133
134pub fn parse_all_packs(b: &[u8]) -> Result<(Vec<Pack<'_>>, &[u8])> {
138 let mut packs = Vec::new();
139 let mut remaining = b;
140 while remaining.len() >= 4 {
141 let (pack_opt, consumed) = parse_pack(remaining)?;
142 match pack_opt {
143 Some(pack) => {
144 remaining = &remaining[consumed..];
145 packs.push(pack);
146 }
147 None => {
148 remaining = &remaining[4..];
150 break;
151 }
152 }
153 }
154 Ok((packs, remaining))
155}
156
157#[cfg(test)]
158mod tests {
159 use super::parse_pack;
160
161 #[test]
175 fn fuzz_regression_mpeg_ps_boundary_underflow() {
176 let crashing: &[u8] = &[
177 0x00, 0x00, 0x01, 0xba, 0x5c, 0xf5, 0xf5, 0xc0, 0xff, 0xff, 0x21, 0xf3, 0xf3, 0xf3,
178 0x90, 0xf3, 0xbb, 0x00, 0x00, 0x01, 0xbb, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
179 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
180 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
181 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
182 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
183 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
184 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
185 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
186 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
187 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
188 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0xba, 0x5c,
189 0xf5, 0xf5, 0xc0, 0xff, 0xff, 0xf3, 0xf3, 0xf3, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
190 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
191 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
192 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
193 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
194 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
195 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
196 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
197 0x00, 0x00,
198 ];
199 let _ = parse_pack(crashing);
201 }
202}