1use super::descriptor_body;
27use crate::error::{Error, Result};
28use dvb_common::{Parse, Serialize};
29
30pub const TAG: u8 = 0x6E;
32pub const HEADER_LEN: usize = 2;
34pub const INDICATOR_LEN: usize = 2;
36pub const TYPE_BYTE_LEN: usize = 1;
38pub const REFERENCE_LEN: usize = 7;
40
41const ANNOUNCEMENT_TYPE_MASK: u8 = 0xF0;
42const ANNOUNCEMENT_TYPE_SHIFT: u8 = 4;
43const RESERVED_BIT_MASK: u8 = 0x08;
44const REFERENCE_TYPE_MASK: u8 = 0x07;
45pub const ANNOUNCEMENT_TYPE_MAX: u8 = 0x0F;
47pub const REFERENCE_TYPE_MAX: u8 = 0x07;
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize))]
53pub struct AnnouncementReference {
54 pub original_network_id: u16,
56 pub transport_stream_id: u16,
58 pub service_id: u16,
60 pub component_tag: u8,
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize))]
67pub struct AnnouncementEntry {
68 pub announcement_type: u8,
70 pub reference_type: u8,
72 pub reference: Option<AnnouncementReference>,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
78#[cfg_attr(feature = "serde", derive(serde::Serialize))]
79pub struct AnnouncementSupportDescriptor {
80 pub announcement_support_indicator: u16,
82 pub entries: Vec<AnnouncementEntry>,
84}
85
86#[inline]
87fn reference_present(reference_type: u8) -> bool {
88 matches!(reference_type, 0x01..=0x03)
89}
90
91impl<'a> Parse<'a> for AnnouncementSupportDescriptor {
92 type Error = crate::error::Error;
93 fn parse(bytes: &'a [u8]) -> Result<Self> {
94 let body = descriptor_body(
95 bytes,
96 TAG,
97 "AnnouncementSupportDescriptor",
98 "unexpected tag for announcement_support_descriptor",
99 )?;
100 if body.len() < INDICATOR_LEN {
101 return Err(Error::InvalidDescriptor {
102 tag: TAG,
103 reason: "body too short (need announcement_support_indicator)",
104 });
105 }
106 let announcement_support_indicator = u16::from_be_bytes([body[0], body[1]]);
107 let mut entries = Vec::new();
108 let mut pos = INDICATOR_LEN;
109 while pos < body.len() {
110 let flags = body[pos];
111 pos += TYPE_BYTE_LEN;
112 let announcement_type = (flags & ANNOUNCEMENT_TYPE_MASK) >> ANNOUNCEMENT_TYPE_SHIFT;
114 let reference_type = flags & REFERENCE_TYPE_MASK;
115 let reference = if reference_present(reference_type) {
116 if pos + REFERENCE_LEN > body.len() {
117 return Err(Error::InvalidDescriptor {
118 tag: TAG,
119 reason: "announcement reference block truncated",
120 });
121 }
122 let r = AnnouncementReference {
123 original_network_id: u16::from_be_bytes([body[pos], body[pos + 1]]),
124 transport_stream_id: u16::from_be_bytes([body[pos + 2], body[pos + 3]]),
125 service_id: u16::from_be_bytes([body[pos + 4], body[pos + 5]]),
126 component_tag: body[pos + 6],
127 };
128 pos += REFERENCE_LEN;
129 Some(r)
130 } else {
131 None
132 };
133 entries.push(AnnouncementEntry {
134 announcement_type,
135 reference_type,
136 reference,
137 });
138 }
139 Ok(Self {
140 announcement_support_indicator,
141 entries,
142 })
143 }
144}
145
146impl AnnouncementSupportDescriptor {
147 fn body_len(&self) -> usize {
148 INDICATOR_LEN
149 + self
150 .entries
151 .iter()
152 .map(|e| {
153 TYPE_BYTE_LEN
154 + if reference_present(e.reference_type) {
155 REFERENCE_LEN
156 } else {
157 0
158 }
159 })
160 .sum::<usize>()
161 }
162}
163
164impl Serialize for AnnouncementSupportDescriptor {
165 type Error = crate::error::Error;
166 fn serialized_len(&self) -> usize {
167 HEADER_LEN + self.body_len()
168 }
169
170 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
171 for e in &self.entries {
172 if e.announcement_type > ANNOUNCEMENT_TYPE_MAX {
173 return Err(Error::InvalidDescriptor {
174 tag: TAG,
175 reason: "announcement_type exceeds 4 bits",
176 });
177 }
178 if e.reference_type > REFERENCE_TYPE_MAX {
179 return Err(Error::InvalidDescriptor {
180 tag: TAG,
181 reason: "reference_type exceeds 3 bits",
182 });
183 }
184 if reference_present(e.reference_type) != e.reference.is_some() {
186 return Err(Error::InvalidDescriptor {
187 tag: TAG,
188 reason: "reference presence does not match reference_type",
189 });
190 }
191 }
192 let body_len = self.body_len();
193 if body_len > u8::MAX as usize {
194 return Err(Error::InvalidDescriptor {
195 tag: TAG,
196 reason: "announcement_support_descriptor body exceeds 255 bytes",
197 });
198 }
199 let len = self.serialized_len();
200 if buf.len() < len {
201 return Err(Error::OutputBufferTooSmall {
202 need: len,
203 have: buf.len(),
204 });
205 }
206 buf[0] = TAG;
207 buf[1] = body_len as u8;
208 buf[HEADER_LEN..HEADER_LEN + INDICATOR_LEN]
209 .copy_from_slice(&self.announcement_support_indicator.to_be_bytes());
210 let mut pos = HEADER_LEN + INDICATOR_LEN;
211 for e in &self.entries {
212 let flags = ((e.announcement_type << ANNOUNCEMENT_TYPE_SHIFT) & ANNOUNCEMENT_TYPE_MASK)
214 | RESERVED_BIT_MASK
215 | (e.reference_type & REFERENCE_TYPE_MASK);
216 buf[pos] = flags;
217 pos += TYPE_BYTE_LEN;
218 if let Some(r) = &e.reference {
219 buf[pos..pos + 2].copy_from_slice(&r.original_network_id.to_be_bytes());
220 buf[pos + 2..pos + 4].copy_from_slice(&r.transport_stream_id.to_be_bytes());
221 buf[pos + 4..pos + 6].copy_from_slice(&r.service_id.to_be_bytes());
222 buf[pos + 6] = r.component_tag;
223 pos += REFERENCE_LEN;
224 }
225 }
226 Ok(len)
227 }
228}
229impl<'a> crate::traits::DescriptorDef<'a> for AnnouncementSupportDescriptor {
230 const TAG: u8 = TAG;
231 const NAME: &'static str = "ANNOUNCEMENT_SUPPORT";
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
237
238 #[test]
239 fn parse_entry_without_reference() {
240 let bytes = [TAG, 3, 0x00, 0x40, 0x68];
243 let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
244 assert_eq!(d.announcement_support_indicator, 0x0040);
245 assert_eq!(d.entries.len(), 1);
246 assert_eq!(d.entries[0].announcement_type, 0x06);
247 assert_eq!(d.entries[0].reference_type, 0x00);
248 assert!(d.entries[0].reference.is_none());
249 }
250
251 #[test]
252 fn parse_entry_with_reference() {
253 let bytes = [
256 TAG, 10, 0x00, 0x01,
257 0x1A, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x09,
259 ];
260 let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
261 assert_eq!(d.entries.len(), 1);
262 assert_eq!(d.entries[0].announcement_type, 0x01);
263 assert_eq!(d.entries[0].reference_type, 0x02);
264 let r = d.entries[0].reference.unwrap();
265 assert_eq!(r.original_network_id, 0xAABB);
266 assert_eq!(r.transport_stream_id, 0xCCDD);
267 assert_eq!(r.service_id, 0xEEFF);
268 assert_eq!(r.component_tag, 0x09);
269 }
270
271 #[test]
272 fn parse_mixed_entries() {
273 let bytes = [
275 TAG, 11, 0x12, 0x34, 0x40, 0x53, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
279 ];
280 let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
281 assert_eq!(d.entries.len(), 2);
282 assert!(d.entries[0].reference.is_none());
283 assert_eq!(d.entries[1].reference_type, 0x03);
284 assert!(d.entries[1].reference.is_some());
285 }
286
287 #[test]
288 fn parse_ignores_reserved_bit() {
289 let bytes = [TAG, 3, 0x00, 0x00, 0x60];
291 let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
292 assert_eq!(d.entries[0].announcement_type, 0x06);
293 assert_eq!(d.entries[0].reference_type, 0x00);
294 }
295
296 #[test]
297 fn parse_rejects_wrong_tag() {
298 assert!(matches!(
299 AnnouncementSupportDescriptor::parse(&[0x6F, 2, 0, 0]).unwrap_err(),
300 Error::InvalidDescriptor { tag: 0x6F, .. }
301 ));
302 }
303
304 #[test]
305 fn parse_rejects_body_too_short_for_indicator() {
306 assert!(matches!(
307 AnnouncementSupportDescriptor::parse(&[TAG, 1, 0]).unwrap_err(),
308 Error::InvalidDescriptor { tag: TAG, .. }
309 ));
310 }
311
312 #[test]
313 fn parse_rejects_reference_truncated() {
314 let bytes = [TAG, 3, 0x00, 0x00, 0x09]; assert!(matches!(
317 AnnouncementSupportDescriptor::parse(&bytes).unwrap_err(),
318 Error::InvalidDescriptor { tag: TAG, .. }
319 ));
320 }
321
322 #[test]
323 fn parse_rejects_buffer_shorter_than_length() {
324 let bytes = [TAG, 5, 0x00, 0x00];
325 assert!(matches!(
326 AnnouncementSupportDescriptor::parse(&bytes).unwrap_err(),
327 Error::BufferTooShort { .. }
328 ));
329 }
330
331 #[test]
332 fn serialize_round_trip_mixed() {
333 let d = AnnouncementSupportDescriptor {
334 announcement_support_indicator: 0xBEEF,
335 entries: vec![
336 AnnouncementEntry {
337 announcement_type: 0x04,
338 reference_type: 0x00,
339 reference: None,
340 },
341 AnnouncementEntry {
342 announcement_type: 0x01,
343 reference_type: 0x02,
344 reference: Some(AnnouncementReference {
345 original_network_id: 0xAABB,
346 transport_stream_id: 0xCCDD,
347 service_id: 0xEEFF,
348 component_tag: 0x09,
349 }),
350 },
351 ],
352 };
353 let mut buf = vec![0u8; d.serialized_len()];
354 d.serialize_into(&mut buf).unwrap();
355 assert_eq!(AnnouncementSupportDescriptor::parse(&buf).unwrap(), d);
356 }
357
358 #[test]
359 fn serialize_rejects_too_small_buffer() {
360 let d = AnnouncementSupportDescriptor {
361 announcement_support_indicator: 0,
362 entries: vec![],
363 };
364 let mut buf = vec![0u8; 3];
365 assert!(matches!(
366 d.serialize_into(&mut buf).unwrap_err(),
367 Error::OutputBufferTooSmall { .. }
368 ));
369 }
370
371 #[test]
372 fn serialize_rejects_over_range_announcement_type() {
373 let d = AnnouncementSupportDescriptor {
374 announcement_support_indicator: 0,
375 entries: vec![AnnouncementEntry {
376 announcement_type: 0x10, reference_type: 0,
378 reference: None,
379 }],
380 };
381 let mut buf = vec![0u8; d.serialized_len()];
382 assert!(matches!(
383 d.serialize_into(&mut buf).unwrap_err(),
384 Error::InvalidDescriptor { tag: TAG, .. }
385 ));
386 }
387
388 #[test]
389 fn serialize_rejects_reference_mismatch() {
390 let d = AnnouncementSupportDescriptor {
392 announcement_support_indicator: 0,
393 entries: vec![AnnouncementEntry {
394 announcement_type: 0,
395 reference_type: 0x02,
396 reference: None,
397 }],
398 };
399 let mut buf = vec![0u8; d.serialized_len()];
400 assert!(matches!(
401 d.serialize_into(&mut buf).unwrap_err(),
402 Error::InvalidDescriptor { tag: TAG, .. }
403 ));
404 }
405
406 #[cfg(feature = "serde")]
407 #[test]
408 fn serde_round_trip() {
409 let d = AnnouncementSupportDescriptor {
410 announcement_support_indicator: 0xBEEF,
411 entries: vec![AnnouncementEntry {
412 announcement_type: 0x01,
413 reference_type: 0x02,
414 reference: Some(AnnouncementReference {
415 original_network_id: 0xAABB,
416 transport_stream_id: 0xCCDD,
417 service_id: 0xEEFF,
418 component_tag: 0x09,
419 }),
420 }],
421 };
422 let json = serde_json::to_string(&d).unwrap();
423 let _v: serde_json::Value = serde_json::from_str(&json).unwrap();
425 }
426}