1use super::descriptor_body;
11use crate::error::{Error, Result};
12use dvb_common::{Parse, Serialize};
13
14pub const TAG: u8 = 0x6F;
16const HEADER_LEN: usize = 2;
17const ENTRY_LEN: usize = 3;
18
19const APPLICATION_TYPE_MAX: u16 = 0x7FFF;
21const AIT_VERSION_MAX: u8 = 0x1F;
23
24#[must_use]
31pub fn application_type_name(val: u16) -> Option<&'static str> {
32 match crate::tables::ait::ApplicationType::from_u16(val) {
33 crate::tables::ait::ApplicationType::DvbJ
34 | crate::tables::ait::ApplicationType::DvbHtml
35 | crate::tables::ait::ApplicationType::HbbTv
36 | crate::tables::ait::ApplicationType::OipfDae => {
37 Some(crate::tables::ait::ApplicationType::from_u16(val).name())
38 }
39 _ => None,
40 }
41}
42
43#[derive(Debug, Clone, PartialEq, Eq)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize))]
46pub struct ApplicationSignallingEntry {
47 pub application_type: u16,
49 pub ait_version_number: u8,
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize))]
56pub struct ApplicationSignallingDescriptor {
57 pub entries: Vec<ApplicationSignallingEntry>,
59}
60
61impl<'a> Parse<'a> for ApplicationSignallingDescriptor {
62 type Error = crate::error::Error;
63 fn parse(bytes: &'a [u8]) -> Result<Self> {
64 let body = descriptor_body(
65 bytes,
66 TAG,
67 "ApplicationSignallingDescriptor",
68 "unexpected tag for application_signalling_descriptor",
69 )?;
70 if body.len() % ENTRY_LEN != 0 {
71 return Err(Error::InvalidDescriptor {
72 tag: TAG,
73 reason: "application_signalling_descriptor length must be a multiple of 3",
74 });
75 }
76 let mut entries = Vec::with_capacity(body.len() / ENTRY_LEN);
77 for chunk in body.chunks_exact(ENTRY_LEN) {
78 let application_type = u16::from_be_bytes([chunk[0], chunk[1]]) & APPLICATION_TYPE_MAX;
80 let ait_version_number = chunk[2] & AIT_VERSION_MAX;
82 entries.push(ApplicationSignallingEntry {
83 application_type,
84 ait_version_number,
85 });
86 }
87 Ok(Self { entries })
88 }
89}
90
91impl Serialize for ApplicationSignallingDescriptor {
92 type Error = crate::error::Error;
93 fn serialized_len(&self) -> usize {
94 HEADER_LEN + self.entries.len() * ENTRY_LEN
95 }
96
97 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
98 for e in &self.entries {
99 if e.application_type > APPLICATION_TYPE_MAX {
100 return Err(Error::InvalidDescriptor {
101 tag: TAG,
102 reason: "application_type exceeds 15 bits",
103 });
104 }
105 if e.ait_version_number > AIT_VERSION_MAX {
106 return Err(Error::InvalidDescriptor {
107 tag: TAG,
108 reason: "ait_version_number exceeds 5 bits",
109 });
110 }
111 }
112 if self.entries.len() * ENTRY_LEN > u8::MAX as usize {
113 return Err(Error::InvalidDescriptor {
114 tag: TAG,
115 reason: "application_signalling_descriptor body exceeds 255 bytes",
116 });
117 }
118 let len = self.serialized_len();
119 if buf.len() < len {
120 return Err(Error::OutputBufferTooSmall {
121 need: len,
122 have: buf.len(),
123 });
124 }
125 buf[0] = TAG;
126 buf[1] = (self.entries.len() * ENTRY_LEN) as u8;
127 let mut pos = HEADER_LEN;
128 for e in &self.entries {
129 let word = 0x8000 | (e.application_type & APPLICATION_TYPE_MAX);
131 buf[pos..pos + 2].copy_from_slice(&word.to_be_bytes());
132 buf[pos + 2] = 0xE0 | (e.ait_version_number & AIT_VERSION_MAX);
134 pos += ENTRY_LEN;
135 }
136 Ok(len)
137 }
138}
139impl<'a> crate::traits::DescriptorDef<'a> for ApplicationSignallingDescriptor {
140 const TAG: u8 = TAG;
141 const NAME: &'static str = "APPLICATION_SIGNALLING";
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn parse_single_entry() {
150 let bytes = [TAG, 3, 0x80, 0x10, 0xE3];
152 let d = ApplicationSignallingDescriptor::parse(&bytes).unwrap();
153 assert_eq!(d.entries.len(), 1);
154 assert_eq!(d.entries[0].application_type, 0x0010);
155 assert_eq!(d.entries[0].ait_version_number, 3);
156 }
157
158 #[test]
159 fn parse_multiple_entries() {
160 let bytes = [TAG, 6, 0x00, 0x01, 0x05, 0x7F, 0xFF, 0x1F];
161 let d = ApplicationSignallingDescriptor::parse(&bytes).unwrap();
162 assert_eq!(d.entries.len(), 2);
163 assert_eq!(d.entries[0].application_type, 0x0001);
164 assert_eq!(d.entries[0].ait_version_number, 5);
165 assert_eq!(d.entries[1].application_type, 0x7FFF);
166 assert_eq!(d.entries[1].ait_version_number, 0x1F);
167 }
168
169 #[test]
170 fn parse_ignores_reserved_bits() {
171 let bytes = [TAG, 3, 0xFF, 0xFF, 0xFF];
173 let d = ApplicationSignallingDescriptor::parse(&bytes).unwrap();
174 assert_eq!(d.entries[0].application_type, 0x7FFF);
175 assert_eq!(d.entries[0].ait_version_number, 0x1F);
176 }
177
178 #[test]
179 fn application_type_name_verified() {
180 assert_eq!(application_type_name(0x0001), Some("DVB-J"));
181 assert_eq!(application_type_name(0x0002), Some("DVB-HTML"));
182 assert_eq!(application_type_name(0x0010), Some("HbbTV"));
183 assert_eq!(application_type_name(0x0011), Some("OIPF DAE"));
184 }
185
186 #[test]
187 fn application_type_name_removed_entries_return_none() {
188 assert_eq!(application_type_name(0x0003), None);
189 assert_eq!(application_type_name(0x0004), None);
190 assert_eq!(application_type_name(0x0005), None);
191 assert_eq!(application_type_name(0x0012), None);
192 assert_eq!(application_type_name(0x0013), None);
193 assert_eq!(application_type_name(0x0020), None);
194 }
195
196 #[test]
197 fn application_type_name_unknown() {
198 assert_eq!(application_type_name(0x0000), None);
199 assert_eq!(application_type_name(0xFFFF), None);
200 }
201
202 #[test]
203 fn parse_rejects_wrong_tag() {
204 assert!(matches!(
205 ApplicationSignallingDescriptor::parse(&[0x70, 0]).unwrap_err(),
206 Error::InvalidDescriptor { tag: 0x70, .. }
207 ));
208 }
209
210 #[test]
211 fn parse_rejects_length_not_multiple_of_3() {
212 let bytes = [TAG, 4, 0, 0, 0, 0];
213 assert!(matches!(
214 ApplicationSignallingDescriptor::parse(&bytes).unwrap_err(),
215 Error::InvalidDescriptor { .. }
216 ));
217 }
218
219 #[test]
220 fn empty_descriptor_valid() {
221 let bytes = [TAG, 0];
222 let d = ApplicationSignallingDescriptor::parse(&bytes).unwrap();
223 assert!(d.entries.is_empty());
224 }
225
226 #[test]
227 fn serialize_round_trip() {
228 let d = ApplicationSignallingDescriptor {
229 entries: vec![
230 ApplicationSignallingEntry {
231 application_type: 0x0001,
232 ait_version_number: 7,
233 },
234 ApplicationSignallingEntry {
235 application_type: 0x0010,
236 ait_version_number: 0,
237 },
238 ],
239 };
240 let mut buf = vec![0u8; d.serialized_len()];
241 d.serialize_into(&mut buf).unwrap();
242 assert_eq!(ApplicationSignallingDescriptor::parse(&buf).unwrap(), d);
243 }
244
245 #[test]
246 fn serialize_rejects_application_type_over_range() {
247 let d = ApplicationSignallingDescriptor {
248 entries: vec![ApplicationSignallingEntry {
249 application_type: 0x8000,
250 ait_version_number: 0,
251 }],
252 };
253 let mut buf = vec![0u8; d.serialized_len()];
254 assert!(matches!(
255 d.serialize_into(&mut buf).unwrap_err(),
256 Error::InvalidDescriptor { .. }
257 ));
258 }
259
260 #[test]
261 fn serialize_rejects_ait_version_over_range() {
262 let d = ApplicationSignallingDescriptor {
263 entries: vec![ApplicationSignallingEntry {
264 application_type: 0,
265 ait_version_number: 0x20,
266 }],
267 };
268 let mut buf = vec![0u8; d.serialized_len()];
269 assert!(matches!(
270 d.serialize_into(&mut buf).unwrap_err(),
271 Error::InvalidDescriptor { .. }
272 ));
273 }
274
275 #[cfg(feature = "serde")]
276 #[test]
277 fn serde_round_trip() {
278 let d = ApplicationSignallingDescriptor {
279 entries: vec![ApplicationSignallingEntry {
280 application_type: 0x0010,
281 ait_version_number: 4,
282 }],
283 };
284 let j = serde_json::to_string(&d).unwrap();
285 let _v: serde_json::Value = serde_json::from_str(&j).unwrap();
287 }
288}