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