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 {
76 return Err(Error::BadMarker("program_mux_rate markers"));
77 }
78
79 let program_mux_rate =
80 (u32::from(b[10]) << 14) | (u32::from(b[11]) << 6) | (u32::from(b[12]) >> 2);
81
82 if program_mux_rate == 0 {
83 return Err(Error::ZeroMuxRate);
84 }
85
86 let reserved = (b[13] >> 3) & 0x1F;
87 let stuffing_length = b[13] & 0x07;
88
89 let total = FIXED_LEN + stuffing_length as usize;
90 need_in(b, total, "pack_header stuffing bytes")?;
91
92 Ok(PackHeader {
93 scr,
94 program_mux_rate,
95 stuffing_length,
96 stuffing: &b[FIXED_LEN..total],
97 reserved,
98 })
99 }
100}
101
102impl Serialize for PackHeader<'_> {
103 type Error = Error;
104
105 fn serialized_len(&self) -> usize {
106 FIXED_LEN + self.stuffing_length as usize
107 }
108
109 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
110 if self.stuffing_length > STUFFING_LENGTH_MAX {
114 return Err(Error::StuffingLengthTooLarge(self.stuffing_length));
115 }
116 let mux = broadcast_common::len::fit_bits(
117 u64::from(self.program_mux_rate),
118 PROGRAM_MUX_RATE_BITS,
119 "pack_header.program_mux_rate",
120 )? as u32;
121 let reserved = broadcast_common::len::fit_bits(
122 u64::from(self.reserved),
123 RESERVED_BITS,
124 "pack_header.reserved",
125 )? as u8;
126 let len = self.serialized_len();
127 need_out(buf, len)?;
128
129 buf[0..4].copy_from_slice(&PACK_START_CODE.to_be_bytes());
131
132 buf[4..10].copy_from_slice(&scr::encode_scr_field(self.scr)?);
134
135 buf[10] = (mux >> 14) as u8;
139 buf[11] = (mux >> 6) as u8;
141 buf[12] = (((mux & 0x3F) as u8) << 2) | 0x03;
143 buf[13] = reserved << 3 | self.stuffing_length;
145
146 if self.stuffing.len() != self.stuffing_length as usize {
156 return Err(Error::StuffingLengthMismatch {
157 declared: self.stuffing_length,
158 actual: self.stuffing.len(),
159 });
160 }
161 buf[FIXED_LEN..len].copy_from_slice(self.stuffing);
162
163 Ok(len)
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use alloc::vec;
171
172 #[test]
175 fn serialize_into_too_small_output_reports_output_buffer_error() {
176 let bytes = vec![
177 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x43, 0x36, 0x3B, 0xF8,
178 ];
179 let h = PackHeader::parse(&bytes).unwrap();
180 let mut out = vec![0u8; h.serialized_len() - 1];
181 assert!(matches!(
182 h.serialize_into(&mut out),
183 Err(Error::OutputBufferTooSmall(_))
184 ));
185 }
186
187 #[test]
188 fn pack_header_round_trip_fixture_pattern() {
189 let bytes = vec![
196 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x43, 0x36, 0x3B, 0xF8, ];
199 let h = PackHeader::parse(&bytes).unwrap();
200 assert_eq!(
201 h.scr,
202 Scr {
203 base: 0,
204 extension: 0,
205 }
206 );
207 assert_eq!(h.program_mux_rate, 0x10CD8E);
208 assert_eq!(h.stuffing_length, 0);
209 assert_eq!(h.reserved, 0x1F);
210 assert!(h.stuffing.is_empty());
211
212 let mut out = vec![0u8; h.serialized_len()];
213 h.serialize_into(&mut out).unwrap();
214 assert_eq!(&out[..], &bytes[..], "round-trip mismatch");
215
216 let h_mut = PackHeader {
218 program_mux_rate: 0x12345,
219 ..h.clone()
220 };
221 let mut out2 = vec![0u8; h_mut.serialized_len()];
222 h_mut.serialize_into(&mut out2).unwrap();
223 assert_ne!(&out[..], &out2[..]);
224 }
225
226 #[test]
227 fn serialize_rejects_out_of_range_fields() {
228 let ok = PackHeader {
229 scr: Scr {
230 base: 0,
231 extension: 0,
232 },
233 program_mux_rate: 1,
234 stuffing_length: 0,
235 stuffing: &[],
236 reserved: 0x1F,
237 };
238 let mut out = vec![0u8; 64];
239 assert!(ok.serialize_into(&mut out).is_ok());
240
241 let long = [0xFFu8; 9];
242 let bad = PackHeader {
243 stuffing_length: 9,
244 stuffing: &long,
245 ..ok.clone()
246 };
247 assert_eq!(
248 bad.serialize_into(&mut out),
249 Err(Error::StuffingLengthTooLarge(9))
250 );
251 let bad = PackHeader {
252 program_mux_rate: 0x40_0000,
253 ..ok.clone()
254 };
255 assert!(matches!(
256 bad.serialize_into(&mut out),
257 Err(Error::FieldOverflow(_))
258 ));
259 let bad = PackHeader {
260 reserved: 0x20,
261 ..ok.clone()
262 };
263 assert!(matches!(
264 bad.serialize_into(&mut out),
265 Err(Error::FieldOverflow(_))
266 ));
267 }
268
269 #[test]
270 fn pack_header_round_trip_with_stuffing() {
271 let bytes = vec![
272 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x00, 0x01,
273 0x0F, 0x03, 0xFF, 0xFF, 0xFF,
276 ];
277 let h = PackHeader::parse(&bytes).unwrap();
278 assert_eq!(h.program_mux_rate, 0x43);
279 assert_eq!(h.stuffing_length, 3);
280 assert_eq!(h.stuffing, &[0xFF, 0xFF, 0xFF]);
281 assert_eq!(h.reserved, 0);
282
283 let mut out = vec![0u8; h.serialized_len()];
284 h.serialize_into(&mut out).unwrap();
285 assert_eq!(&out[..], &bytes[..]);
286
287 let h2 = PackHeader::parse(&out).unwrap();
289 assert_eq!(h, h2);
290
291 let h_mut = PackHeader {
293 reserved: 0x0A,
294 ..h.clone()
295 };
296 let mut out2 = vec![0u8; h_mut.serialized_len()];
297 h_mut.serialize_into(&mut out2).unwrap();
298 assert_ne!(&out[..], &out2[..]);
299 }
300
301 #[test]
302 fn pack_header_nonzero_scr() {
303 let scr = Scr {
304 base: 0x12345678,
305 extension: 0x0AA,
306 };
307 let scr_enc = scr::write_scr_field(scr);
308 let mut b = vec![0u8; 14];
309 b[0..4].copy_from_slice(&PACK_START_CODE.to_be_bytes());
310 b[4..10].copy_from_slice(&scr_enc);
311 b[10..14].copy_from_slice(&[0x00, 0x01, 0x0F, 0x00]); let h = PackHeader::parse(&b).unwrap();
314 assert_eq!(h.scr, scr);
315 assert_eq!(h.program_mux_rate, 0x43);
316
317 let mut out = vec![0u8; h.serialized_len()];
318 h.serialize_into(&mut out).unwrap();
319 assert_eq!(&out[..], &b[..]);
320 }
321
322 #[test]
328 fn non_0xff_stuffing_round_trips_byte_identically() {
329 let bytes = vec![
330 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x00, 0x01, 0x0F,
331 0x03, 0xAB, 0xCD, 0xEF, ];
334 let h = PackHeader::parse(&bytes).unwrap();
335 assert_eq!(h.stuffing, &[0xAB, 0xCD, 0xEF]);
336
337 let mut out = vec![0u8; h.serialized_len()];
338 h.serialize_into(&mut out).unwrap();
339 assert_eq!(&out[..], &bytes[..]);
340 }
341
342 #[test]
346 fn serialize_rejects_stuffing_length_mismatch() {
347 let bytes = vec![
348 0x00, 0x00, 0x01, 0xBA, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x00, 0x01, 0x0F, 0x03,
349 0xFF, 0xFF, 0xFF,
350 ];
351 let mut h = PackHeader::parse(&bytes).unwrap();
352 h.stuffing = &[0xFF, 0xFF]; let mut out = vec![0u8; h.serialized_len()];
355 let err = h.serialize_into(&mut out).unwrap_err();
356 assert!(matches!(
357 err,
358 Error::StuffingLengthMismatch {
359 declared: 3,
360 actual: 2
361 }
362 ));
363 }
364}