1use crate::descriptors::DescriptorLoop;
7use crate::error::{Error, Result};
8use crate::traits::Table;
9use dvb_common::{Parse, Serialize};
10
11pub const TABLE_ID: u8 = 0x74;
13pub const PID: u16 = 0x0000;
15
16const MIN_HEADER_LEN: usize = 3;
17const EXTENSION_HEADER_LEN: usize = 5;
18const COMMON_DESC_LEN_BYTES: usize = 2;
19const APP_LOOP_LEN_BYTES: usize = 2;
20const CRC_LEN: usize = 4;
21const APP_HEADER_LEN: usize = 9;
22
23#[derive(Debug, Clone, PartialEq, Eq)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize))]
26pub struct ApplicationIdentifier {
27 pub organisation_id: u32,
29 pub application_id: u16,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize))]
36pub struct AitApplication<'a> {
37 pub identifier: ApplicationIdentifier,
39 pub control_code: u8,
41 pub descriptors: DescriptorLoop<'a>,
45}
46
47#[derive(Debug, Clone, PartialEq, Eq)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize))]
50pub struct Ait<'a> {
51 pub application_type: u16,
53 pub test_application_flag: bool,
55 pub version_number: u8,
57 pub current_next_indicator: bool,
59 pub section_number: u8,
61 pub last_section_number: u8,
63 pub common_descriptors: DescriptorLoop<'a>,
67 pub applications: Vec<AitApplication<'a>>,
69}
70
71impl<'a> Parse<'a> for Ait<'a> {
72 type Error = crate::error::Error;
73 fn parse(bytes: &'a [u8]) -> Result<Self> {
74 let min_len = MIN_HEADER_LEN
75 + EXTENSION_HEADER_LEN
76 + COMMON_DESC_LEN_BYTES
77 + APP_LOOP_LEN_BYTES
78 + CRC_LEN;
79 if bytes.len() < min_len {
80 return Err(Error::BufferTooShort {
81 need: min_len,
82 have: bytes.len(),
83 what: "Ait",
84 });
85 }
86
87 if bytes[0] != TABLE_ID {
88 return Err(Error::UnexpectedTableId {
89 table_id: bytes[0],
90 what: "Ait",
91 expected: &[TABLE_ID],
92 });
93 }
94
95 let section_length = ((bytes[1] & 0x0F) as u16) << 8 | bytes[2] as u16;
96 let total = MIN_HEADER_LEN + section_length as usize;
97 if bytes.len() < total {
98 return Err(Error::SectionLengthOverflow {
99 declared: section_length as usize,
100 available: bytes.len() - MIN_HEADER_LEN,
101 });
102 }
103
104 let test_application_flag = (bytes[3] & 0x80) != 0;
105 let application_type = (((bytes[3] & 0x7F) as u16) << 8) | (bytes[4] as u16);
106 let version_number = (bytes[5] >> 1) & 0x1F;
107 let current_next_indicator = (bytes[5] & 0x01) != 0;
108 let section_number = bytes[6];
109 let last_section_number = bytes[7];
110
111 let common_descriptors_length = (((bytes[8] & 0x0F) as usize) << 8) | bytes[9] as usize;
112 let common_desc_start = MIN_HEADER_LEN + EXTENSION_HEADER_LEN + COMMON_DESC_LEN_BYTES;
113 let common_desc_end = common_desc_start + common_descriptors_length;
114 let app_loop_end = total - CRC_LEN;
115 if common_desc_end > app_loop_end {
116 return Err(Error::SectionLengthOverflow {
117 declared: common_descriptors_length,
118 available: app_loop_end - common_desc_start,
119 });
120 }
121 let common_descriptors = DescriptorLoop::new(&bytes[common_desc_start..common_desc_end]);
122
123 let app_loop_length =
124 (((bytes[common_desc_end] & 0x0F) as usize) << 8) | bytes[common_desc_end + 1] as usize;
125 let app_loop_start = common_desc_end + APP_LOOP_LEN_BYTES;
126 let app_loop_actual_end = app_loop_start + app_loop_length;
127 if app_loop_actual_end > app_loop_end {
128 return Err(Error::SectionLengthOverflow {
129 declared: app_loop_length,
130 available: app_loop_end - app_loop_start,
131 });
132 }
133
134 let mut applications = Vec::new();
135 let mut pos = app_loop_start;
136 while pos + APP_HEADER_LEN <= app_loop_actual_end {
137 let organisation_id = ((bytes[pos] as u32) << 24)
138 | ((bytes[pos + 1] as u32) << 16)
139 | ((bytes[pos + 2] as u32) << 8)
140 | (bytes[pos + 3] as u32);
141 let application_id = u16::from_be_bytes([bytes[pos + 4], bytes[pos + 5]]);
142 let control_code = bytes[pos + 6];
143 let app_desc_length =
144 (((bytes[pos + 7] & 0x0F) as usize) << 8) | bytes[pos + 8] as usize;
145 let app_desc_start = pos + APP_HEADER_LEN;
146 let app_desc_end = app_desc_start + app_desc_length;
147 if app_desc_end > app_loop_actual_end {
148 return Err(Error::SectionLengthOverflow {
149 declared: app_desc_length,
150 available: app_loop_actual_end - app_desc_start,
151 });
152 }
153 applications.push(AitApplication {
154 identifier: ApplicationIdentifier {
155 organisation_id,
156 application_id,
157 },
158 control_code,
159 descriptors: DescriptorLoop::new(&bytes[app_desc_start..app_desc_end]),
160 });
161 pos = app_desc_end;
162 }
163
164 Ok(Ait {
165 application_type,
166 test_application_flag,
167 version_number,
168 current_next_indicator,
169 section_number,
170 last_section_number,
171 common_descriptors,
172 applications,
173 })
174 }
175}
176
177impl Serialize for Ait<'_> {
178 type Error = crate::error::Error;
179 fn serialized_len(&self) -> usize {
180 let app_bytes: usize = self
181 .applications
182 .iter()
183 .map(|a| APP_HEADER_LEN + a.descriptors.len())
184 .sum();
185 MIN_HEADER_LEN
186 + EXTENSION_HEADER_LEN
187 + COMMON_DESC_LEN_BYTES
188 + self.common_descriptors.len()
189 + APP_LOOP_LEN_BYTES
190 + app_bytes
191 + CRC_LEN
192 }
193
194 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
195 let len = self.serialized_len();
196 if buf.len() < len {
197 return Err(Error::OutputBufferTooSmall {
198 need: len,
199 have: buf.len(),
200 });
201 }
202
203 let section_length: u16 = (len - MIN_HEADER_LEN) as u16;
204 buf[0] = TABLE_ID;
205 buf[1] = 0xB0 | ((section_length >> 8) as u8 & 0x0F);
206 buf[2] = (section_length & 0xFF) as u8;
207 buf[3] = (u8::from(self.test_application_flag) << 7)
208 | ((self.application_type >> 8) as u8 & 0x7F);
209 buf[4] = (self.application_type & 0xFF) as u8;
210 buf[5] = 0xC0 | ((self.version_number & 0x1F) << 1) | u8::from(self.current_next_indicator);
211 buf[6] = self.section_number;
212 buf[7] = self.last_section_number;
213
214 let cdl = self.common_descriptors.len() as u16;
215 buf[8] = 0xF0 | ((cdl >> 8) as u8 & 0x0F);
216 buf[9] = (cdl & 0xFF) as u8;
217
218 let common_desc_start = MIN_HEADER_LEN + EXTENSION_HEADER_LEN + COMMON_DESC_LEN_BYTES;
219 buf[common_desc_start..common_desc_start + self.common_descriptors.len()]
220 .copy_from_slice(self.common_descriptors.raw());
221
222 let app_loop_start = common_desc_start + self.common_descriptors.len();
223 let app_bytes: usize = self
224 .applications
225 .iter()
226 .map(|a| APP_HEADER_LEN + a.descriptors.len())
227 .sum();
228 let apl = app_bytes as u16;
229 buf[app_loop_start] = 0xF0 | ((apl >> 8) as u8 & 0x0F);
230 buf[app_loop_start + 1] = (apl & 0xFF) as u8;
231
232 let mut pos = app_loop_start + APP_LOOP_LEN_BYTES;
233 for app in &self.applications {
234 buf[pos..pos + 4].copy_from_slice(&app.identifier.organisation_id.to_be_bytes());
235 buf[pos + 4..pos + 6].copy_from_slice(&app.identifier.application_id.to_be_bytes());
236 buf[pos + 6] = app.control_code;
237 let adl = app.descriptors.len() as u16;
238 buf[pos + 7] = 0xF0 | ((adl >> 8) as u8 & 0x0F);
239 buf[pos + 8] = (adl & 0xFF) as u8;
240 let desc_start = pos + APP_HEADER_LEN;
241 buf[desc_start..desc_start + app.descriptors.len()]
242 .copy_from_slice(app.descriptors.raw());
243 pos = desc_start + app.descriptors.len();
244 }
245
246 let crc_pos = len - CRC_LEN;
247 let crc = dvb_common::crc32_mpeg2::compute(&buf[..crc_pos]);
248 buf[crc_pos..len].copy_from_slice(&crc.to_be_bytes());
249 Ok(len)
250 }
251}
252
253impl<'a> Table<'a> for Ait<'a> {
254 const TABLE_ID: u8 = TABLE_ID;
255 const PID: u16 = PID;
256}
257
258impl<'a> crate::traits::TableDef<'a> for Ait<'a> {
259 const TABLE_ID_RANGES: &'static [(u8, u8)] = &[(TABLE_ID, TABLE_ID)];
260 const NAME: &'static str = "APPLICATION_INFORMATION";
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266
267 fn build_ait(
268 application_type: u16,
269 test_flag: bool,
270 version: u8,
271 common_descriptors: &[u8],
272 applications: &[(u32, u16, u8, Vec<u8>)],
273 ) -> Vec<u8> {
274 let app_bytes: usize = applications
275 .iter()
276 .map(|(_, _, _, d)| APP_HEADER_LEN + d.len())
277 .sum();
278 let section_length: u16 = (EXTENSION_HEADER_LEN
279 + COMMON_DESC_LEN_BYTES
280 + common_descriptors.len()
281 + APP_LOOP_LEN_BYTES
282 + app_bytes
283 + CRC_LEN) as u16;
284 let mut v = vec![
285 TABLE_ID,
286 0xB0 | ((section_length >> 8) as u8 & 0x0F),
287 (section_length & 0xFF) as u8,
288 (u8::from(test_flag) << 7) | ((application_type >> 8) as u8 & 0x7F),
289 (application_type & 0xFF) as u8,
290 0xC0 | ((version & 0x1F) << 1) | 0x01,
291 0,
292 0,
293 ];
294 let cdl = common_descriptors.len() as u16;
295 v.push(0xF0 | ((cdl >> 8) as u8 & 0x0F));
296 v.push((cdl & 0xFF) as u8);
297 v.extend_from_slice(common_descriptors);
298 let apl = app_bytes as u16;
299 v.push(0xF0 | ((apl >> 8) as u8 & 0x0F));
300 v.push((apl & 0xFF) as u8);
301 for &(org_id, app_id, cc, ref desc) in applications {
302 v.extend_from_slice(&org_id.to_be_bytes());
303 v.extend_from_slice(&app_id.to_be_bytes());
304 v.push(cc);
305 let adl = desc.len() as u16;
306 v.push(0xF0 | ((adl >> 8) as u8 & 0x0F));
307 v.push((adl & 0xFF) as u8);
308 v.extend_from_slice(desc);
309 }
310 v.extend_from_slice(&[0, 0, 0, 0]);
311 v
312 }
313
314 #[test]
315 fn parse_rejects_wrong_table_id() {
316 let mut bytes = build_ait(0x0010, false, 0, &[], &[]);
317 bytes[0] = 0x00;
318 let err = Ait::parse(&bytes).unwrap_err();
319 assert!(matches!(
320 err,
321 Error::UnexpectedTableId { table_id: 0x00, .. }
322 ));
323 }
324
325 #[test]
326 fn parse_rejects_short_buffer() {
327 let err = Ait::parse(&[0x74, 0x00]).unwrap_err();
328 assert!(matches!(err, Error::BufferTooShort { .. }));
329 }
330
331 #[test]
332 fn parse_empty_ait_no_applications() {
333 let bytes = build_ait(0x0010, false, 5, &[], &[]);
334 let ait = Ait::parse(&bytes).expect("parse");
335 assert_eq!(ait.application_type, 0x0010);
336 assert!(!ait.test_application_flag);
337 assert_eq!(ait.version_number, 5);
338 assert!(ait.current_next_indicator);
339 assert_eq!(ait.section_number, 0);
340 assert_eq!(ait.last_section_number, 0);
341 assert_eq!(ait.common_descriptors.len(), 0);
342 assert_eq!(ait.applications.len(), 0);
343 }
344
345 #[test]
346 fn parse_test_application_flag_extracted() {
347 let bytes = build_ait(0x0010, true, 0, &[], &[]);
348 let ait = Ait::parse(&bytes).unwrap();
349 assert!(ait.test_application_flag);
350 }
351
352 #[test]
353 fn parse_common_descriptors_preserved() {
354 let desc = vec![0x00, 0x02, 0xAA, 0xBB];
355 let bytes = build_ait(0x0010, false, 0, &desc, &[]);
356 let ait = Ait::parse(&bytes).unwrap();
357 assert_eq!(ait.common_descriptors.raw(), &desc[..]);
358 }
359
360 #[test]
361 fn parse_single_application() {
362 let desc = vec![0x02, 0x03, 0xCC, 0xDD, 0xEE];
363 let bytes = build_ait(
364 0x0010,
365 false,
366 0,
367 &[],
368 &[(0x12345678, 0xABCD, 0x01, desc.clone())],
369 );
370 let ait = Ait::parse(&bytes).unwrap();
371 assert_eq!(ait.applications.len(), 1);
372 assert_eq!(ait.applications[0].identifier.organisation_id, 0x12345678);
373 assert_eq!(ait.applications[0].identifier.application_id, 0xABCD);
374 assert_eq!(ait.applications[0].control_code, 0x01);
375 assert_eq!(ait.applications[0].descriptors.raw(), &desc[..]);
376 }
377
378 #[test]
379 fn parse_multiple_applications_preserve_order() {
380 let bytes = build_ait(
381 0x0010,
382 false,
383 0,
384 &[],
385 &[
386 (0x00000001, 0x0001, 0x01, vec![]),
387 (0x00000002, 0x0002, 0x02, vec![0x01]),
388 (0x00000003, 0x0003, 0x03, vec![0x02, 0x03]),
389 ],
390 );
391 let ait = Ait::parse(&bytes).unwrap();
392 assert_eq!(ait.applications.len(), 3);
393 assert_eq!(ait.applications[0].identifier.organisation_id, 1);
394 assert_eq!(ait.applications[1].identifier.organisation_id, 2);
395 assert_eq!(ait.applications[2].identifier.organisation_id, 3);
396 }
397
398 #[test]
399 fn serialize_round_trip_empty() {
400 let ait = Ait {
401 application_type: 0x0010,
402 test_application_flag: false,
403 version_number: 3,
404 current_next_indicator: true,
405 section_number: 0,
406 last_section_number: 0,
407 common_descriptors: DescriptorLoop::new(&[]),
408 applications: vec![],
409 };
410 let mut buf = vec![0u8; ait.serialized_len()];
411 ait.serialize_into(&mut buf).unwrap();
412 let reparsed = Ait::parse(&buf).unwrap();
413 assert_eq!(ait, reparsed);
414 }
415
416 #[test]
417 fn serialize_round_trip_with_applications() {
418 let desc1: [u8; 2] = [0xAA, 0xBB];
419 let ait = Ait {
420 application_type: 0x0010,
421 test_application_flag: true,
422 version_number: 7,
423 current_next_indicator: true,
424 section_number: 1,
425 last_section_number: 2,
426 common_descriptors: DescriptorLoop::new(&[0x01, 0x00]),
427 applications: vec![
428 AitApplication {
429 identifier: ApplicationIdentifier {
430 organisation_id: 0x12345678,
431 application_id: 0xABCD,
432 },
433 control_code: 0x01,
434 descriptors: DescriptorLoop::new(&desc1),
435 },
436 AitApplication {
437 identifier: ApplicationIdentifier {
438 organisation_id: 0x87654321,
439 application_id: 0x00EF,
440 },
441 control_code: 0x02,
442 descriptors: DescriptorLoop::new(&[]),
443 },
444 ],
445 };
446 let mut buf = vec![0u8; ait.serialized_len()];
447 ait.serialize_into(&mut buf).unwrap();
448 let reparsed = Ait::parse(&buf).unwrap();
449 assert_eq!(ait, reparsed);
450 }
451}