1use crate::error::{Error, Result};
8use crate::scr::{self, Scr};
9use broadcast_common::{Parse, Serialize};
10
11pub const PACK_START_CODE: u32 = 0x0000_01BA;
13
14const FIXED_LEN: usize = 14;
17
18const PROGRAM_MUX_RATE_BITS: u32 = 22;
20const RESERVED_BITS: u32 = 5;
22const STUFFING_LENGTH_MAX: u8 = 7;
24
25#[derive(Debug, Clone, PartialEq, Eq)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize))]
28pub struct PackHeader<'a> {
29 pub scr: Scr,
31 pub program_mux_rate: u32,
34 pub stuffing_length: u8,
36 #[cfg_attr(feature = "serde", serde(skip))]
38 pub stuffing: &'a [u8],
39 pub reserved: u8,
41}
42
43impl PackHeader<'_> {
44 #[must_use]
46 pub fn header_len(&self) -> usize {
47 self.serialized_len()
48 }
49}
50
51impl<'a> Parse<'a> for PackHeader<'a> {
52 type Error = Error;
53
54 fn parse(b: &'a [u8]) -> Result<Self> {
55 if b.len() < FIXED_LEN {
56 return Err(Error::BufferTooShort {
57 need: FIXED_LEN,
58 have: b.len(),
59 what: "pack_header",
60 });
61 }
62
63 if u32::from_be_bytes([b[0], b[1], b[2], b[3]]) != PACK_START_CODE {
64 return Err(Error::BadPackStartCode(u32::from_be_bytes([
65 b[0], b[1], b[2], b[3],
66 ])));
67 }
68
69 let scr = scr::read_scr_field(&b[4..10], "SCR")?;
70
71 if b[12] & 0x03 != 0x03 {
82 return Err(Error::BadMarker("program_mux_rate markers"));
83 }
84
85 let program_mux_rate =
86 (u32::from(b[10]) << 14) | (u32::from(b[11]) << 6) | (u32::from(b[12]) >> 2);
87
88 if program_mux_rate == 0 {
89 return Err(Error::ZeroMuxRate);
90 }
91
92 let reserved = (b[13] >> 3) & 0x1F;
93 let stuffing_length = b[13] & 0x07;
94
95 let total = FIXED_LEN + stuffing_length as usize;
96 if b.len() < total {
97 return Err(Error::BufferTooShort {
98 need: total,
99 have: b.len(),
100 what: "pack_header stuffing bytes",
101 });
102 }
103
104 Ok(PackHeader {
105 scr,
106 program_mux_rate,
107 stuffing_length,
108 stuffing: &b[FIXED_LEN..total],
109 reserved,
110 })
111 }
112}
113
114impl Serialize for PackHeader<'_> {
115 type Error = Error;
116
117 fn serialized_len(&self) -> usize {
118 FIXED_LEN + self.stuffing_length as usize
119 }
120
121 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
122 if self.stuffing_length > STUFFING_LENGTH_MAX {
126 return Err(Error::StuffingLengthTooLarge(self.stuffing_length));
127 }
128 let mux = broadcast_common::len::fit_bits(
129 u64::from(self.program_mux_rate),
130 PROGRAM_MUX_RATE_BITS,
131 "pack_header.program_mux_rate",
132 )? as u32;
133 let reserved = broadcast_common::len::fit_bits(
134 u64::from(self.reserved),
135 RESERVED_BITS,
136 "pack_header.reserved",
137 )? as u8;
138 let len = self.serialized_len();
139 if buf.len() < len {
140 return Err(Error::BufferTooShort {
141 need: len,
142 have: buf.len(),
143 what: "pack_header serialize output",
144 });
145 }
146
147 buf[0..4].copy_from_slice(&PACK_START_CODE.to_be_bytes());
149
150 buf[4..10].copy_from_slice(&scr::write_scr_field(self.scr));
152
153 buf[10] = (mux >> 14) as u8;
157 buf[11] = (mux >> 6) as u8;
159 buf[12] = (((mux & 0x3F) as u8) << 2) | 0x03;
161 buf[13] = reserved << 3 | self.stuffing_length;
163
164 if self.stuffing.len() != self.stuffing_length as usize {
174 return Err(Error::StuffingLengthMismatch {
175 declared: self.stuffing_length,
176 actual: self.stuffing.len(),
177 });
178 }
179 buf[FIXED_LEN..len].copy_from_slice(self.stuffing);
180
181 Ok(len)
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use alloc::vec;
189
190 #[test]
191 fn pack_header_round_trip_fixture_pattern() {
192 let bytes = vec![
199 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x43, 0x36, 0x3B, 0xF8, ];
202 let h = PackHeader::parse(&bytes).unwrap();
203 assert_eq!(
204 h.scr,
205 Scr {
206 base: 0,
207 extension: 0,
208 }
209 );
210 assert_eq!(h.program_mux_rate, 0x10CD8E);
211 assert_eq!(h.stuffing_length, 0);
212 assert_eq!(h.reserved, 0x1F);
213 assert!(h.stuffing.is_empty());
214
215 let mut out = vec![0u8; h.serialized_len()];
216 h.serialize_into(&mut out).unwrap();
217 assert_eq!(&out[..], &bytes[..], "round-trip mismatch");
218
219 let h_mut = PackHeader {
221 program_mux_rate: 0x12345,
222 ..h.clone()
223 };
224 let mut out2 = vec![0u8; h_mut.serialized_len()];
225 h_mut.serialize_into(&mut out2).unwrap();
226 assert_ne!(&out[..], &out2[..]);
227 }
228
229 #[test]
230 fn serialize_rejects_out_of_range_fields() {
231 let ok = PackHeader {
232 scr: Scr {
233 base: 0,
234 extension: 0,
235 },
236 program_mux_rate: 1,
237 stuffing_length: 0,
238 stuffing: &[],
239 reserved: 0x1F,
240 };
241 let mut out = vec![0u8; 64];
242 assert!(ok.serialize_into(&mut out).is_ok());
243
244 let long = [0xFFu8; 9];
245 let bad = PackHeader {
246 stuffing_length: 9,
247 stuffing: &long,
248 ..ok.clone()
249 };
250 assert_eq!(
251 bad.serialize_into(&mut out),
252 Err(Error::StuffingLengthTooLarge(9))
253 );
254 let bad = PackHeader {
255 program_mux_rate: 0x40_0000,
256 ..ok.clone()
257 };
258 assert!(matches!(
259 bad.serialize_into(&mut out),
260 Err(Error::FieldOverflow(_))
261 ));
262 let bad = PackHeader {
263 reserved: 0x20,
264 ..ok.clone()
265 };
266 assert!(matches!(
267 bad.serialize_into(&mut out),
268 Err(Error::FieldOverflow(_))
269 ));
270 }
271
272 #[test]
273 fn pack_header_round_trip_with_stuffing() {
274 let bytes = vec![
275 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x00, 0x01,
276 0x0F, 0x03, 0xFF, 0xFF, 0xFF,
279 ];
280 let h = PackHeader::parse(&bytes).unwrap();
281 assert_eq!(h.program_mux_rate, 0x43);
282 assert_eq!(h.stuffing_length, 3);
283 assert_eq!(h.stuffing, &[0xFF, 0xFF, 0xFF]);
284 assert_eq!(h.reserved, 0);
285
286 let mut out = vec![0u8; h.serialized_len()];
287 h.serialize_into(&mut out).unwrap();
288 assert_eq!(&out[..], &bytes[..]);
289
290 let h2 = PackHeader::parse(&out).unwrap();
292 assert_eq!(h, h2);
293
294 let h_mut = PackHeader {
296 reserved: 0x0A,
297 ..h.clone()
298 };
299 let mut out2 = vec![0u8; h_mut.serialized_len()];
300 h_mut.serialize_into(&mut out2).unwrap();
301 assert_ne!(&out[..], &out2[..]);
302 }
303
304 #[test]
305 fn pack_header_nonzero_scr() {
306 let scr = Scr {
307 base: 0x12345678,
308 extension: 0x0AA,
309 };
310 let scr_enc = scr::write_scr_field(scr);
311 let mut b = vec![0u8; 14];
312 b[0..4].copy_from_slice(&PACK_START_CODE.to_be_bytes());
313 b[4..10].copy_from_slice(&scr_enc);
314 b[10..14].copy_from_slice(&[0x00, 0x01, 0x0F, 0x00]); let h = PackHeader::parse(&b).unwrap();
317 assert_eq!(h.scr, scr);
318 assert_eq!(h.program_mux_rate, 0x43);
319
320 let mut out = vec![0u8; h.serialized_len()];
321 h.serialize_into(&mut out).unwrap();
322 assert_eq!(&out[..], &b[..]);
323 }
324
325 #[test]
331 fn non_0xff_stuffing_round_trips_byte_identically() {
332 let bytes = vec![
333 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x00, 0x01, 0x0F,
334 0x03, 0xAB, 0xCD, 0xEF, ];
337 let h = PackHeader::parse(&bytes).unwrap();
338 assert_eq!(h.stuffing, &[0xAB, 0xCD, 0xEF]);
339
340 let mut out = vec![0u8; h.serialized_len()];
341 h.serialize_into(&mut out).unwrap();
342 assert_eq!(&out[..], &bytes[..]);
343 }
344
345 #[test]
349 fn serialize_rejects_stuffing_length_mismatch() {
350 let bytes = vec![
351 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x00, 0x01, 0x0F, 0x03,
352 0xFF, 0xFF, 0xFF,
353 ];
354 let mut h = PackHeader::parse(&bytes).unwrap();
355 h.stuffing = &[0xFF, 0xFF]; let mut out = vec![0u8; h.serialized_len()];
358 let err = h.serialize_into(&mut out).unwrap_err();
359 assert!(matches!(
360 err,
361 Error::StuffingLengthMismatch {
362 declared: 3,
363 actual: 2
364 }
365 ));
366 }
367}