1use crate::error::{Error, Result};
8use crate::scr::{self, Scr};
9use broadcast_common::len::{need_in, need_out};
10use broadcast_common::{Parse, Serialize};
11
12pub const PACK_START_CODE: u32 = 0x0000_01BA;
14
15const FIXED_LEN: usize = 14;
18
19const PROGRAM_MUX_RATE_BITS: u32 = 22;
21const RESERVED_BITS: u32 = 5;
23const STUFFING_LENGTH_MAX: u8 = 7;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize))]
29pub struct PackHeader<'a> {
30 pub scr: Scr,
32 pub program_mux_rate: u32,
35 pub stuffing_length: u8,
37 #[cfg_attr(feature = "serde", serde(skip))]
39 pub stuffing: &'a [u8],
40 pub reserved: u8,
42}
43
44impl PackHeader<'_> {
45 #[must_use]
47 pub fn header_len(&self) -> usize {
48 self.serialized_len()
49 }
50}
51
52impl<'a> Parse<'a> for PackHeader<'a> {
53 type Error = Error;
54
55 fn parse(b: &'a [u8]) -> Result<Self> {
56 need_in(b, FIXED_LEN, "pack_header")?;
57
58 if u32::from_be_bytes([b[0], b[1], b[2], b[3]]) != PACK_START_CODE {
59 return Err(Error::BadPackStartCode(u32::from_be_bytes([
60 b[0], b[1], b[2], b[3],
61 ])));
62 }
63
64 let scr = scr::read_scr_field(&b[4..10], "SCR")?;
65
66 if b[12] & 0x03 != 0x03 {
77 return Err(Error::BadMarker("program_mux_rate markers"));
78 }
79
80 let program_mux_rate =
81 (u32::from(b[10]) << 14) | (u32::from(b[11]) << 6) | (u32::from(b[12]) >> 2);
82
83 if program_mux_rate == 0 {
84 return Err(Error::ZeroMuxRate);
85 }
86
87 let reserved = (b[13] >> 3) & 0x1F;
88 let stuffing_length = b[13] & 0x07;
89
90 let total = FIXED_LEN + stuffing_length as usize;
91 need_in(b, total, "pack_header stuffing bytes")?;
92
93 Ok(PackHeader {
94 scr,
95 program_mux_rate,
96 stuffing_length,
97 stuffing: &b[FIXED_LEN..total],
98 reserved,
99 })
100 }
101}
102
103impl Serialize for PackHeader<'_> {
104 type Error = Error;
105
106 fn serialized_len(&self) -> usize {
107 FIXED_LEN + self.stuffing_length as usize
108 }
109
110 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
111 if self.stuffing_length > STUFFING_LENGTH_MAX {
115 return Err(Error::StuffingLengthTooLarge(self.stuffing_length));
116 }
117 let mux = broadcast_common::len::fit_bits(
118 u64::from(self.program_mux_rate),
119 PROGRAM_MUX_RATE_BITS,
120 "pack_header.program_mux_rate",
121 )? as u32;
122 let reserved = broadcast_common::len::fit_bits(
123 u64::from(self.reserved),
124 RESERVED_BITS,
125 "pack_header.reserved",
126 )? as u8;
127 let len = self.serialized_len();
128 need_out(buf, len)?;
129
130 buf[0..4].copy_from_slice(&PACK_START_CODE.to_be_bytes());
132
133 buf[4..10].copy_from_slice(&scr::encode_scr_field(self.scr)?);
135
136 buf[10] = (mux >> 14) as u8;
140 buf[11] = (mux >> 6) as u8;
142 buf[12] = (((mux & 0x3F) as u8) << 2) | 0x03;
144 buf[13] = reserved << 3 | self.stuffing_length;
146
147 if self.stuffing.len() != self.stuffing_length as usize {
157 return Err(Error::StuffingLengthMismatch {
158 declared: self.stuffing_length,
159 actual: self.stuffing.len(),
160 });
161 }
162 buf[FIXED_LEN..len].copy_from_slice(self.stuffing);
163
164 Ok(len)
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171 use alloc::vec;
172
173 #[test]
174 fn pack_header_round_trip_fixture_pattern() {
175 let bytes = vec![
182 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x43, 0x36, 0x3B, 0xF8, ];
185 let h = PackHeader::parse(&bytes).unwrap();
186 assert_eq!(
187 h.scr,
188 Scr {
189 base: 0,
190 extension: 0,
191 }
192 );
193 assert_eq!(h.program_mux_rate, 0x10CD8E);
194 assert_eq!(h.stuffing_length, 0);
195 assert_eq!(h.reserved, 0x1F);
196 assert!(h.stuffing.is_empty());
197
198 let mut out = vec![0u8; h.serialized_len()];
199 h.serialize_into(&mut out).unwrap();
200 assert_eq!(&out[..], &bytes[..], "round-trip mismatch");
201
202 let h_mut = PackHeader {
204 program_mux_rate: 0x12345,
205 ..h.clone()
206 };
207 let mut out2 = vec![0u8; h_mut.serialized_len()];
208 h_mut.serialize_into(&mut out2).unwrap();
209 assert_ne!(&out[..], &out2[..]);
210 }
211
212 #[test]
213 fn serialize_rejects_out_of_range_fields() {
214 let ok = PackHeader {
215 scr: Scr {
216 base: 0,
217 extension: 0,
218 },
219 program_mux_rate: 1,
220 stuffing_length: 0,
221 stuffing: &[],
222 reserved: 0x1F,
223 };
224 let mut out = vec![0u8; 64];
225 assert!(ok.serialize_into(&mut out).is_ok());
226
227 let long = [0xFFu8; 9];
228 let bad = PackHeader {
229 stuffing_length: 9,
230 stuffing: &long,
231 ..ok.clone()
232 };
233 assert_eq!(
234 bad.serialize_into(&mut out),
235 Err(Error::StuffingLengthTooLarge(9))
236 );
237 let bad = PackHeader {
238 program_mux_rate: 0x40_0000,
239 ..ok.clone()
240 };
241 assert!(matches!(
242 bad.serialize_into(&mut out),
243 Err(Error::FieldOverflow(_))
244 ));
245 let bad = PackHeader {
246 reserved: 0x20,
247 ..ok.clone()
248 };
249 assert!(matches!(
250 bad.serialize_into(&mut out),
251 Err(Error::FieldOverflow(_))
252 ));
253 }
254
255 #[test]
256 fn pack_header_round_trip_with_stuffing() {
257 let bytes = vec![
258 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x00, 0x01,
259 0x0F, 0x03, 0xFF, 0xFF, 0xFF,
262 ];
263 let h = PackHeader::parse(&bytes).unwrap();
264 assert_eq!(h.program_mux_rate, 0x43);
265 assert_eq!(h.stuffing_length, 3);
266 assert_eq!(h.stuffing, &[0xFF, 0xFF, 0xFF]);
267 assert_eq!(h.reserved, 0);
268
269 let mut out = vec![0u8; h.serialized_len()];
270 h.serialize_into(&mut out).unwrap();
271 assert_eq!(&out[..], &bytes[..]);
272
273 let h2 = PackHeader::parse(&out).unwrap();
275 assert_eq!(h, h2);
276
277 let h_mut = PackHeader {
279 reserved: 0x0A,
280 ..h.clone()
281 };
282 let mut out2 = vec![0u8; h_mut.serialized_len()];
283 h_mut.serialize_into(&mut out2).unwrap();
284 assert_ne!(&out[..], &out2[..]);
285 }
286
287 #[test]
288 fn pack_header_nonzero_scr() {
289 let scr = Scr {
290 base: 0x12345678,
291 extension: 0x0AA,
292 };
293 let scr_enc = scr::write_scr_field(scr);
294 let mut b = vec![0u8; 14];
295 b[0..4].copy_from_slice(&PACK_START_CODE.to_be_bytes());
296 b[4..10].copy_from_slice(&scr_enc);
297 b[10..14].copy_from_slice(&[0x00, 0x01, 0x0F, 0x00]); let h = PackHeader::parse(&b).unwrap();
300 assert_eq!(h.scr, scr);
301 assert_eq!(h.program_mux_rate, 0x43);
302
303 let mut out = vec![0u8; h.serialized_len()];
304 h.serialize_into(&mut out).unwrap();
305 assert_eq!(&out[..], &b[..]);
306 }
307
308 #[test]
314 fn non_0xff_stuffing_round_trips_byte_identically() {
315 let bytes = vec![
316 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x00, 0x01, 0x0F,
317 0x03, 0xAB, 0xCD, 0xEF, ];
320 let h = PackHeader::parse(&bytes).unwrap();
321 assert_eq!(h.stuffing, &[0xAB, 0xCD, 0xEF]);
322
323 let mut out = vec![0u8; h.serialized_len()];
324 h.serialize_into(&mut out).unwrap();
325 assert_eq!(&out[..], &bytes[..]);
326 }
327
328 #[test]
332 fn serialize_rejects_stuffing_length_mismatch() {
333 let bytes = vec![
334 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x00, 0x01, 0x0F, 0x03,
335 0xFF, 0xFF, 0xFF,
336 ];
337 let mut h = PackHeader::parse(&bytes).unwrap();
338 h.stuffing = &[0xFF, 0xFF]; let mut out = vec![0u8; h.serialized_len()];
341 let err = h.serialize_into(&mut out).unwrap_err();
342 assert!(matches!(
343 err,
344 Error::StuffingLengthMismatch {
345 declared: 3,
346 actual: 2
347 }
348 ));
349 }
350}