1use crate::error::{Error, Result};
9use crate::traits::Table;
10use dvb_common::{Parse, Serialize};
11
12pub const TABLE_ID_ACTUAL: u8 = 0x40;
14pub const TABLE_ID_OTHER: u8 = 0x41;
16pub const PID: u16 = 0x0010;
18
19const MIN_HEADER_LEN: usize = 3;
20const EXTENSION_HEADER_LEN: usize = 5;
21const POST_EXTENSION_LEN: usize = 2;
26const CRC_LEN: usize = 4;
27const TS_HEADER_LEN: usize = 6;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33pub enum NitKind {
34 Actual,
36 Other,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43pub struct NitTransportStream<'a> {
44 pub transport_stream_id: u16,
46 pub original_network_id: u16,
48 #[cfg_attr(feature = "serde", serde(borrow))]
50 pub descriptors: &'a [u8],
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56pub struct Nit<'a> {
57 pub kind: NitKind,
59 pub network_id: u16,
61 pub version_number: u8,
63 pub current_next_indicator: bool,
65 pub section_number: u8,
67 pub last_section_number: u8,
69 #[cfg_attr(feature = "serde", serde(borrow))]
71 pub network_descriptors: &'a [u8],
72 #[cfg_attr(feature = "serde", serde(borrow))]
74 pub transport_streams: Vec<NitTransportStream<'a>>,
75}
76
77impl<'a> Parse<'a> for Nit<'a> {
78 type Error = crate::error::Error;
79 fn parse(bytes: &'a [u8]) -> Result<Self> {
80 let min_len = MIN_HEADER_LEN + EXTENSION_HEADER_LEN + POST_EXTENSION_LEN + CRC_LEN;
81 if bytes.len() < min_len {
82 return Err(Error::BufferTooShort {
83 need: min_len,
84 have: bytes.len(),
85 what: "Nit",
86 });
87 }
88 let kind = match bytes[0] {
89 TABLE_ID_ACTUAL => NitKind::Actual,
90 TABLE_ID_OTHER => NitKind::Other,
91 other => {
92 return Err(Error::UnexpectedTableId {
93 table_id: other,
94 what: "Nit",
95 expected: &[TABLE_ID_ACTUAL, TABLE_ID_OTHER],
96 });
97 }
98 };
99
100 let section_length = ((bytes[1] & 0x0F) as u16) << 8 | bytes[2] as u16;
101 let total = MIN_HEADER_LEN + section_length as usize;
102 if bytes.len() < total {
103 return Err(Error::SectionLengthOverflow {
104 declared: section_length as usize,
105 available: bytes.len() - MIN_HEADER_LEN,
106 });
107 }
108
109 let network_id = u16::from_be_bytes([bytes[3], bytes[4]]);
115 let version_number = (bytes[5] >> 1) & 0x1F;
116 let current_next_indicator = (bytes[5] & 0x01) != 0;
117 let section_number = bytes[6];
118 let last_section_number = bytes[7];
119
120 let network_descriptors_length =
122 (((bytes[8] & 0x0F) as usize) << 8) | bytes[9] as usize;
123
124 let network_desc_start = MIN_HEADER_LEN + EXTENSION_HEADER_LEN + POST_EXTENSION_LEN;
125 let network_desc_end = network_desc_start + network_descriptors_length;
126
127 if network_desc_end > total - CRC_LEN {
129 return Err(Error::SectionLengthOverflow {
130 declared: network_descriptors_length,
131 available: (total - CRC_LEN) - network_desc_start,
132 });
133 }
134
135 let network_descriptors = &bytes[network_desc_start..network_desc_end];
136
137 let ts_loop_start = network_desc_end;
139 let ts_loop_end = total - CRC_LEN;
140
141 if ts_loop_end - ts_loop_start < 2 {
143 return Err(Error::BufferTooShort {
144 need: ts_loop_end - ts_loop_start + 2,
145 have: ts_loop_end - ts_loop_start,
146 what: "Nit transport_stream_loop",
147 });
148 }
149
150 let transport_stream_loop_length =
151 (((bytes[ts_loop_start] & 0x0F) as usize) << 8) | bytes[ts_loop_start + 1] as usize;
152
153 let mut pos = ts_loop_start + 2;
154 let loop_end = ts_loop_start + 2 + transport_stream_loop_length;
155
156 if loop_end > ts_loop_end {
157 return Err(Error::SectionLengthOverflow {
158 declared: transport_stream_loop_length,
159 available: ts_loop_end - (ts_loop_start + 2),
160 });
161 }
162
163 let mut transport_streams = Vec::new();
164
165 while pos < loop_end {
166 if pos + TS_HEADER_LEN > loop_end {
167 return Err(Error::BufferTooShort {
168 need: pos + TS_HEADER_LEN,
169 have: loop_end,
170 what: "Nit transport_stream_entry",
171 });
172 }
173
174 let transport_stream_id = u16::from_be_bytes([bytes[pos], bytes[pos + 1]]);
175 let original_network_id = u16::from_be_bytes([bytes[pos + 2], bytes[pos + 3]]);
176
177 let transport_descriptors_length =
179 (((bytes[pos + 4] & 0x0F) as usize) << 8) | bytes[pos + 5] as usize;
180
181 let desc_start = pos + TS_HEADER_LEN;
182 let desc_end = desc_start + transport_descriptors_length;
183
184 if desc_end > loop_end {
185 return Err(Error::SectionLengthOverflow {
186 declared: transport_descriptors_length,
187 available: loop_end - desc_start,
188 });
189 }
190
191 transport_streams.push(NitTransportStream {
192 transport_stream_id,
193 original_network_id,
194 descriptors: &bytes[desc_start..desc_end],
195 });
196
197 pos = desc_end;
198 }
199
200 Ok(Nit {
201 kind,
202 network_id,
203 version_number,
204 current_next_indicator,
205 section_number,
206 last_section_number,
207 network_descriptors,
208 transport_streams,
209 })
210 }
211}
212
213impl Serialize for Nit<'_> {
214 type Error = crate::error::Error;
215 fn serialized_len(&self) -> usize {
216 let net_desc_len = self.network_descriptors.len();
217 let ts_bytes: usize = self
218 .transport_streams
219 .iter()
220 .map(|ts| TS_HEADER_LEN + ts.descriptors.len())
221 .sum();
222 MIN_HEADER_LEN
223 + EXTENSION_HEADER_LEN
224 + POST_EXTENSION_LEN
225 + net_desc_len
226 + 2 + ts_bytes
228 + CRC_LEN
229 }
230
231 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
232 let len = self.serialized_len();
233 if buf.len() < len {
234 return Err(Error::OutputBufferTooSmall {
235 need: len,
236 have: buf.len(),
237 });
238 }
239
240 let section_length: u16 = (len - MIN_HEADER_LEN) as u16;
241 buf[0] = match self.kind {
242 NitKind::Actual => TABLE_ID_ACTUAL,
243 NitKind::Other => TABLE_ID_OTHER,
244 };
245 buf[1] = 0xB0 | ((section_length >> 8) as u8 & 0x0F);
246 buf[2] = (section_length & 0xFF) as u8;
247
248 buf[3..5].copy_from_slice(&self.network_id.to_be_bytes());
253 buf[5] = 0xC0 | ((self.version_number & 0x1F) << 1) | u8::from(self.current_next_indicator);
254 buf[6] = self.section_number;
255 buf[7] = self.last_section_number;
256
257 let net_dll = self.network_descriptors.len() as u16;
259 buf[8] = 0xF0 | ((net_dll >> 8) as u8 & 0x0F);
260 buf[9] = (net_dll & 0xFF) as u8;
261
262 let net_desc_start = MIN_HEADER_LEN + EXTENSION_HEADER_LEN + POST_EXTENSION_LEN;
263 buf[net_desc_start..net_desc_start + self.network_descriptors.len()]
264 .copy_from_slice(self.network_descriptors);
265
266 let ts_loop_start = net_desc_start + self.network_descriptors.len();
267 let ts_loop_length: u16 = (len - ts_loop_start - 2 - CRC_LEN) as u16;
268 buf[ts_loop_start] = 0xF0 | ((ts_loop_length >> 8) as u8 & 0x0F);
269 buf[ts_loop_start + 1] = (ts_loop_length & 0xFF) as u8;
270
271 let mut pos = ts_loop_start + 2;
272 for ts in &self.transport_streams {
273 buf[pos..pos + 2].copy_from_slice(&ts.transport_stream_id.to_be_bytes());
274 buf[pos + 2..pos + 4].copy_from_slice(&ts.original_network_id.to_be_bytes());
275 let ts_dll = ts.descriptors.len() as u16;
276 buf[pos + 4] = 0xF0 | ((ts_dll >> 8) as u8 & 0x0F);
277 buf[pos + 5] = (ts_dll & 0xFF) as u8;
278 let desc_start = pos + TS_HEADER_LEN;
279 buf[desc_start..desc_start + ts.descriptors.len()].copy_from_slice(ts.descriptors);
280 pos = desc_start + ts.descriptors.len();
281 }
282
283 let crc_pos = len - CRC_LEN;
284 let crc = dvb_common::crc32_mpeg2::compute(&buf[..crc_pos]);
285 buf[crc_pos..len].copy_from_slice(&crc.to_be_bytes());
286 Ok(len)
287 }
288}
289
290impl<'a> Table<'a> for Nit<'a> {
291 const TABLE_ID: u8 = TABLE_ID_ACTUAL;
292 const PID: u16 = PID;
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298
299 type TestTs = (u16, u16, Vec<u8>);
300
301 fn build_nit(
302 kind: NitKind,
303 network_id: u16,
304 network_desc: &[u8],
305 transport_streams: &[TestTs],
306 ) -> Vec<u8> {
307 let ts_bytes: usize = transport_streams
308 .iter()
309 .map(|(_, _, d)| TS_HEADER_LEN + d.len())
310 .sum();
311 let loop_length = ts_bytes as u16;
312 let section_length: u16 = (EXTENSION_HEADER_LEN
313 + POST_EXTENSION_LEN
314 + network_desc.len()
315 + 2
316 + ts_bytes
317 + CRC_LEN) as u16;
318 let mut v = Vec::new();
319 v.push(match kind {
320 NitKind::Actual => TABLE_ID_ACTUAL,
321 NitKind::Other => TABLE_ID_OTHER,
322 });
323 v.push(0xB0 | ((section_length >> 8) as u8 & 0x0F));
324 v.push((section_length & 0xFF) as u8);
325 v.extend_from_slice(&network_id.to_be_bytes());
327 v.push(0xC0 | 0x01); v.push(0); v.push(0); let net_dll = network_desc.len() as u16;
332 v.push(0xF0 | ((net_dll >> 8) as u8 & 0x0F));
333 v.push((net_dll & 0xFF) as u8);
334 v.extend_from_slice(network_desc);
335 v.push(0xF0 | ((loop_length >> 8) as u8 & 0x0F));
337 v.push((loop_length & 0xFF) as u8);
338 for (tsid, onid, desc) in transport_streams {
339 v.extend_from_slice(&tsid.to_be_bytes());
340 v.extend_from_slice(&onid.to_be_bytes());
341 let ts_dll = desc.len() as u16;
342 v.push(0xF0 | ((ts_dll >> 8) as u8 & 0x0F));
344 v.push((ts_dll & 0xFF) as u8);
345 v.extend_from_slice(desc);
346 }
347 v.extend_from_slice(&[0, 0, 0, 0]); v
349 }
350
351 #[test]
352 fn parse_actual_and_other_distinguished_by_table_id() {
353 let a = build_nit(NitKind::Actual, 0x0001, &[], &[]);
354 let o = build_nit(NitKind::Other, 0x0001, &[], &[]);
355 assert!(matches!(Nit::parse(&a).unwrap().kind, NitKind::Actual));
356 assert!(matches!(Nit::parse(&o).unwrap().kind, NitKind::Other));
357 }
358
359 #[test]
360 fn parse_network_id_extracted() {
361 let bytes = build_nit(NitKind::Actual, 0x0020, &[], &[]);
362 let nit = Nit::parse(&bytes).unwrap();
363 assert_eq!(nit.network_id, 0x0020);
364 }
365
366 #[test]
367 fn parse_network_wide_descriptors() {
368 let net_desc: [u8; 4] = [0x40, 0x02, 0x4E, 0x65]; let bytes = build_nit(NitKind::Actual, 0x0001, &net_desc, &[]);
370 let nit = Nit::parse(&bytes).unwrap();
371 assert_eq!(nit.network_descriptors, &net_desc[..]);
372 }
373
374 #[test]
375 fn parse_transport_stream_entries() {
376 let bytes = build_nit(
377 NitKind::Actual,
378 0x0001,
379 &[],
380 &[
381 (0x1234, 0x0020, vec![0x43, 0x07, 0x0B, 0xB8, 0x00, 0x02, 0x00, 0x05]),
382 (0x5678, 0x0020, vec![]),
383 ],
384 );
385 let nit = Nit::parse(&bytes).unwrap();
386 assert_eq!(nit.transport_streams.len(), 2);
387 assert_eq!(nit.transport_streams[0].transport_stream_id, 0x1234);
388 assert_eq!(nit.transport_streams[0].original_network_id, 0x0020);
389 assert_eq!(
390 nit.transport_streams[0].descriptors,
391 &[0x43, 0x07, 0x0B, 0xB8, 0x00, 0x02, 0x00, 0x05][..]
392 );
393 assert_eq!(nit.transport_streams[1].transport_stream_id, 0x5678);
394 assert_eq!(nit.transport_streams[1].descriptors.len(), 0);
395 }
396
397 #[test]
398 fn parse_version_and_current_next() {
399 let bytes = build_nit(NitKind::Actual, 0x0001, &[], &[]);
400 let nit = Nit::parse(&bytes).unwrap();
401 assert_eq!(nit.version_number, 0);
402 assert!(nit.current_next_indicator);
403 }
404
405 #[test]
406 fn serialize_round_trip() {
407 let net_desc: [u8; 4] = [0x40, 0x02, 0x4E, 0x65];
408 let ts_desc: [u8; 3] = [0x43, 0x01, 0x01];
409 let nit = Nit {
410 kind: NitKind::Actual,
411 network_id: 0x0020,
412 version_number: 3,
413 current_next_indicator: true,
414 section_number: 0,
415 last_section_number: 0,
416 network_descriptors: &net_desc,
417 transport_streams: vec![
418 NitTransportStream {
419 transport_stream_id: 0x1234,
420 original_network_id: 0x0020,
421 descriptors: &ts_desc,
422 },
423 NitTransportStream {
424 transport_stream_id: 0x5678,
425 original_network_id: 0x0020,
426 descriptors: &[],
427 },
428 ],
429 };
430 let mut buf = vec![0u8; nit.serialized_len()];
431 nit.serialize_into(&mut buf).unwrap();
432 let re = Nit::parse(&buf).unwrap();
433 assert_eq!(nit, re);
434 }
435
436 #[test]
437 fn zero_transport_streams_is_valid() {
438 let bytes = build_nit(NitKind::Actual, 0x0001, &[], &[]);
439 let nit = Nit::parse(&bytes).unwrap();
440 assert_eq!(nit.transport_streams.len(), 0);
441 }
442
443 #[test]
444 fn parse_rejects_short_buffer() {
445 let err = Nit::parse(&[0x40, 0x00]).unwrap_err();
446 assert!(matches!(err, Error::BufferTooShort { .. }));
447 }
448
449 #[test]
450 fn parse_rejects_wrong_table_id() {
451 let mut bytes = build_nit(NitKind::Actual, 0x0001, &[], &[]);
452 bytes[0] = 0x00;
453 let err = Nit::parse(&bytes).unwrap_err();
454 assert!(matches!(
455 err,
456 Error::UnexpectedTableId { table_id: 0x00, .. }
457 ));
458 }
459
460 #[test]
461 fn serialize_too_small_buffer_returns_error() {
462 let nit = Nit {
463 kind: NitKind::Actual,
464 network_id: 0x0001,
465 version_number: 0,
466 current_next_indicator: true,
467 section_number: 0,
468 last_section_number: 0,
469 network_descriptors: &[],
470 transport_streams: vec![],
471 };
472 let mut buf = vec![0u8; 2];
473 let err = nit.serialize_into(&mut buf).unwrap_err();
474 assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
475 }
476}