1use crate::error::{Error, Result};
17use broadcast_common::len::{need_in, need_out};
18use broadcast_common::{Parse, Serialize};
19
20pub const TABLE_ID: u8 = 0x06;
22const MIN_HEADER_LEN: usize = 3;
23const EXTENSION_HEADER_LEN: usize = 5;
24use super::CRC_LEN;
25const MIN_SECTION_LEN: usize = MIN_HEADER_LEN + EXTENSION_HEADER_LEN + CRC_LEN;
26pub const RESERVED_DEFAULT: u8 = 0xFF;
28
29const B1_SSI: u8 = 0x80;
30const B1_PRIVATE: u8 = 0x40;
31const B1_RANDOM_ACCESS: u8 = 0x20;
32const B1_DECODER_CONFIG: u8 = 0x10;
33const FRAGMENT_SHIFT: u32 = 6;
34const FRAGMENT_MASK: u8 = 0x03;
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize))]
39#[non_exhaustive]
40pub enum SectionFragmentIndication {
41 Complete,
43 First,
45 Last,
47 Middle,
49}
50
51impl SectionFragmentIndication {
52 #[must_use]
54 pub const fn from_u8(v: u8) -> Self {
55 match v & FRAGMENT_MASK {
56 0b11 => Self::Complete,
57 0b10 => Self::First,
58 0b01 => Self::Last,
59 _ => Self::Middle,
60 }
61 }
62
63 #[must_use]
65 pub const fn to_u8(self) -> u8 {
66 match self {
67 Self::Complete => 0b11,
68 Self::First => 0b10,
69 Self::Last => 0b01,
70 Self::Middle => 0b00,
71 }
72 }
73
74 #[must_use]
76 pub fn name(&self) -> &'static str {
77 match self {
78 Self::Complete => "complete metadata Access Unit",
79 Self::First => "first section",
80 Self::Last => "last section",
81 Self::Middle => "neither first nor last section",
82 }
83 }
84}
85broadcast_common::impl_spec_display!(SectionFragmentIndication);
86
87#[derive(Debug, Clone, PartialEq, Eq)]
89#[cfg_attr(feature = "serde", derive(serde::Serialize))]
90#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
91#[non_exhaustive]
92pub struct MetadataSection<'a> {
93 pub section_syntax_indicator: bool,
95 pub private_indicator: bool,
97 pub random_access_indicator: bool,
99 pub decoder_config_flag: bool,
101 pub metadata_service_id: u8,
103 pub reserved: u8,
105 pub section_fragment_indication: SectionFragmentIndication,
107 pub version_number: u8,
109 pub current_next_indicator: bool,
111 pub section_number: u8,
113 pub last_section_number: u8,
115 pub metadata_bytes: &'a [u8],
118}
119
120impl<'a> MetadataSection<'a> {
121 #[must_use]
123 pub fn new(
124 metadata_service_id: u8,
125 section_fragment_indication: SectionFragmentIndication,
126 version_number: u8,
127 section_number: u8,
128 last_section_number: u8,
129 metadata_bytes: &'a [u8],
130 ) -> Self {
131 Self {
132 section_syntax_indicator: true,
133 private_indicator: false,
134 random_access_indicator: false,
135 decoder_config_flag: false,
136 metadata_service_id,
137 reserved: RESERVED_DEFAULT,
138 section_fragment_indication,
139 version_number,
140 current_next_indicator: true,
141 section_number,
142 last_section_number,
143 metadata_bytes,
144 }
145 }
146}
147
148impl<'a> Parse<'a> for MetadataSection<'a> {
149 type Error = Error;
150
151 fn parse(bytes: &'a [u8]) -> Result<Self> {
152 need_in(bytes, MIN_SECTION_LEN, "MetadataSection")?;
153 if bytes[0] != TABLE_ID {
154 return Err(Error::UnexpectedTableId {
155 table_id: bytes[0],
156 what: "MetadataSection",
157 expected: &[TABLE_ID],
158 });
159 }
160 let total = super::check_section_length(
161 bytes.len(),
162 MIN_HEADER_LEN,
163 super::section_length_of(bytes),
164 MIN_SECTION_LEN,
165 )?;
166 let b1 = bytes[1];
167 Ok(Self {
168 section_syntax_indicator: b1 & B1_SSI != 0,
169 private_indicator: b1 & B1_PRIVATE != 0,
170 random_access_indicator: b1 & B1_RANDOM_ACCESS != 0,
171 decoder_config_flag: b1 & B1_DECODER_CONFIG != 0,
172 metadata_service_id: bytes[3],
173 reserved: bytes[4],
174 section_fragment_indication: SectionFragmentIndication::from_u8(
175 bytes[5] >> FRAGMENT_SHIFT,
176 ),
177 version_number: super::version_number_of(bytes[5]),
178 current_next_indicator: super::current_next_of(bytes[5]),
179 section_number: bytes[6],
180 last_section_number: bytes[7],
181 metadata_bytes: &bytes[MIN_HEADER_LEN + EXTENSION_HEADER_LEN..total - CRC_LEN],
182 })
183 }
184}
185
186impl Serialize for MetadataSection<'_> {
187 type Error = Error;
188
189 fn serialized_len(&self) -> usize {
190 MIN_SECTION_LEN + self.metadata_bytes.len()
191 }
192
193 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
194 let len = self.serialized_len();
195 need_out(buf, len)?;
196 buf[0] = TABLE_ID;
197 buf[1] = (u8::from(self.section_syntax_indicator) * B1_SSI)
198 | (u8::from(self.private_indicator) * B1_PRIVATE)
199 | (u8::from(self.random_access_indicator) * B1_RANDOM_ACCESS)
200 | (u8::from(self.decoder_config_flag) * B1_DECODER_CONFIG);
201 super::write_section_length(buf, len - MIN_HEADER_LEN)?;
202 buf[3] = self.metadata_service_id;
203 buf[4] = self.reserved;
204 buf[5] = super::b5_of(
207 self.section_fragment_indication.to_u8(),
208 self.version_number,
209 self.current_next_indicator,
210 )?;
211 buf[6] = self.section_number;
212 buf[7] = self.last_section_number;
213 let start = MIN_HEADER_LEN + EXTENSION_HEADER_LEN;
214 buf[start..start + self.metadata_bytes.len()].copy_from_slice(self.metadata_bytes);
215 super::write_crc(buf, len - CRC_LEN);
216 Ok(len)
217 }
218}
219
220impl<'a> crate::traits::TableDef<'a> for MetadataSection<'a> {
221 const TABLE_ID_RANGES: &'static [(u8, u8)] = &[(TABLE_ID, TABLE_ID)];
222 const NAME: &'static str = "METADATA";
223}
224
225#[cfg(test)]
226#[allow(clippy::unusual_byte_groupings)] mod tests {
228 use super::*;
229
230 fn rt(s: &MetadataSection<'_>) -> Vec<u8> {
231 let mut out = vec![0u8; s.serialized_len()];
232 s.serialize_into(&mut out).unwrap();
233 let p = MetadataSection::parse(&out).unwrap();
234 assert_eq!(&p, s);
235 out
236 }
237
238 #[test]
239 fn spec_vector_table_2_158() {
240 let s = MetadataSection {
243 random_access_indicator: true,
244 ..MetadataSection::new(0x21, SectionFragmentIndication::First, 5, 0, 2, &[1, 2, 3])
245 };
246 let b = rt(&s);
247 assert_eq!(&b[..8], &[0x06, 0xA0, 0x0C, 0x21, 0xFF, 0b10_00101_1, 0, 2]);
249 assert_eq!(&b[8..11], &[1, 2, 3]);
250 assert_eq!(broadcast_common::crc32_mpeg2::compute(&b), 0);
251 }
252
253 #[test]
254 fn all_flags_reserved_and_fragments_preserved() {
255 for f in [
256 SectionFragmentIndication::Complete,
257 SectionFragmentIndication::First,
258 SectionFragmentIndication::Last,
259 SectionFragmentIndication::Middle,
260 ] {
261 let mut s = MetadataSection::new(1, f, 31, 4, 9, &[]);
262 s.private_indicator = true;
263 s.decoder_config_flag = true;
264 s.reserved = 0x00;
265 s.current_next_indicator = false;
266 let b = rt(&s);
267 assert_eq!(MetadataSection::parse(&b).unwrap().reserved, 0);
268 }
269 }
270
271 #[test]
272 fn rejects_bad_input() {
273 assert!(matches!(
274 MetadataSection::parse(&[0x06, 0xB0, 0x00]),
275 Err(Error::BufferTooShort(..))
276 ));
277 let mut b = vec![0u8; 12];
278 b[0] = 0x05;
279 assert!(matches!(
280 MetadataSection::parse(&b),
281 Err(Error::UnexpectedTableId { .. })
282 ));
283 let s = MetadataSection::new(1, SectionFragmentIndication::Complete, 32, 0, 0, &[]);
284 assert!(matches!(
285 s.serialize_into(&mut [0u8; 16]),
286 Err(Error::FieldOverflow(..))
287 ));
288 let big = vec![0u8; 4090];
289 let s = MetadataSection::new(1, SectionFragmentIndication::Complete, 0, 0, 0, &big);
290 assert!(matches!(
291 &(s.serialize_into(&mut vec![0u8; 5000])),
292 Err(crate::error::Error::FieldOverflow(_))
293 ));
294 }
295}