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