1use crate::error::{Error, Result};
27use crate::traits::Descriptor;
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 if bytes.len() < HEADER_LEN {
95 return Err(Error::BufferTooShort {
96 need: HEADER_LEN,
97 have: bytes.len(),
98 what: "AnnouncementSupportDescriptor header",
99 });
100 }
101 if bytes[0] != TAG {
102 return Err(Error::InvalidDescriptor {
103 tag: bytes[0],
104 reason: "unexpected tag for announcement_support_descriptor",
105 });
106 }
107 let length = bytes[1] as usize;
108 let end = HEADER_LEN + length;
109 if bytes.len() < end {
110 return Err(Error::BufferTooShort {
111 need: end,
112 have: bytes.len(),
113 what: "AnnouncementSupportDescriptor body",
114 });
115 }
116 if length < INDICATOR_LEN {
117 return Err(Error::InvalidDescriptor {
118 tag: TAG,
119 reason: "body too short (need announcement_support_indicator)",
120 });
121 }
122 let body = &bytes[HEADER_LEN..end];
123 let announcement_support_indicator = u16::from_be_bytes([body[0], body[1]]);
124 let mut entries = Vec::new();
125 let mut pos = INDICATOR_LEN;
126 while pos < body.len() {
127 let flags = body[pos];
128 pos += TYPE_BYTE_LEN;
129 let announcement_type = (flags & ANNOUNCEMENT_TYPE_MASK) >> ANNOUNCEMENT_TYPE_SHIFT;
131 let reference_type = flags & REFERENCE_TYPE_MASK;
132 let reference = if reference_present(reference_type) {
133 if pos + REFERENCE_LEN > body.len() {
134 return Err(Error::InvalidDescriptor {
135 tag: TAG,
136 reason: "announcement reference block truncated",
137 });
138 }
139 let r = AnnouncementReference {
140 original_network_id: u16::from_be_bytes([body[pos], body[pos + 1]]),
141 transport_stream_id: u16::from_be_bytes([body[pos + 2], body[pos + 3]]),
142 service_id: u16::from_be_bytes([body[pos + 4], body[pos + 5]]),
143 component_tag: body[pos + 6],
144 };
145 pos += REFERENCE_LEN;
146 Some(r)
147 } else {
148 None
149 };
150 entries.push(AnnouncementEntry {
151 announcement_type,
152 reference_type,
153 reference,
154 });
155 }
156 Ok(Self {
157 announcement_support_indicator,
158 entries,
159 })
160 }
161}
162
163impl AnnouncementSupportDescriptor {
164 fn body_len(&self) -> usize {
165 INDICATOR_LEN
166 + self
167 .entries
168 .iter()
169 .map(|e| {
170 TYPE_BYTE_LEN
171 + if reference_present(e.reference_type) {
172 REFERENCE_LEN
173 } else {
174 0
175 }
176 })
177 .sum::<usize>()
178 }
179}
180
181impl Serialize for AnnouncementSupportDescriptor {
182 type Error = crate::error::Error;
183 fn serialized_len(&self) -> usize {
184 HEADER_LEN + self.body_len()
185 }
186
187 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
188 for e in &self.entries {
189 if e.announcement_type > ANNOUNCEMENT_TYPE_MAX {
190 return Err(Error::InvalidDescriptor {
191 tag: TAG,
192 reason: "announcement_type exceeds 4 bits",
193 });
194 }
195 if e.reference_type > REFERENCE_TYPE_MAX {
196 return Err(Error::InvalidDescriptor {
197 tag: TAG,
198 reason: "reference_type exceeds 3 bits",
199 });
200 }
201 if reference_present(e.reference_type) != e.reference.is_some() {
203 return Err(Error::InvalidDescriptor {
204 tag: TAG,
205 reason: "reference presence does not match reference_type",
206 });
207 }
208 }
209 let body_len = self.body_len();
210 if body_len > u8::MAX as usize {
211 return Err(Error::InvalidDescriptor {
212 tag: TAG,
213 reason: "announcement_support_descriptor body exceeds 255 bytes",
214 });
215 }
216 let len = self.serialized_len();
217 if buf.len() < len {
218 return Err(Error::OutputBufferTooSmall {
219 need: len,
220 have: buf.len(),
221 });
222 }
223 buf[0] = TAG;
224 buf[1] = body_len as u8;
225 buf[HEADER_LEN..HEADER_LEN + INDICATOR_LEN]
226 .copy_from_slice(&self.announcement_support_indicator.to_be_bytes());
227 let mut pos = HEADER_LEN + INDICATOR_LEN;
228 for e in &self.entries {
229 let flags = ((e.announcement_type << ANNOUNCEMENT_TYPE_SHIFT) & ANNOUNCEMENT_TYPE_MASK)
231 | RESERVED_BIT_MASK
232 | (e.reference_type & REFERENCE_TYPE_MASK);
233 buf[pos] = flags;
234 pos += TYPE_BYTE_LEN;
235 if let Some(r) = &e.reference {
236 buf[pos..pos + 2].copy_from_slice(&r.original_network_id.to_be_bytes());
237 buf[pos + 2..pos + 4].copy_from_slice(&r.transport_stream_id.to_be_bytes());
238 buf[pos + 4..pos + 6].copy_from_slice(&r.service_id.to_be_bytes());
239 buf[pos + 6] = r.component_tag;
240 pos += REFERENCE_LEN;
241 }
242 }
243 Ok(len)
244 }
245}
246
247impl<'a> Descriptor<'a> for AnnouncementSupportDescriptor {
248 const TAG: u8 = TAG;
249 fn descriptor_length(&self) -> u8 {
250 self.body_len() as u8
251 }
252}
253
254impl<'a> crate::traits::DescriptorDef<'a> for AnnouncementSupportDescriptor {
255 const TAG: u8 = TAG;
256 const NAME: &'static str = "ANNOUNCEMENT_SUPPORT";
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 #[test]
264 fn parse_entry_without_reference() {
265 let bytes = [TAG, 3, 0x00, 0x40, 0x68];
268 let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
269 assert_eq!(d.announcement_support_indicator, 0x0040);
270 assert_eq!(d.entries.len(), 1);
271 assert_eq!(d.entries[0].announcement_type, 0x06);
272 assert_eq!(d.entries[0].reference_type, 0x00);
273 assert!(d.entries[0].reference.is_none());
274 }
275
276 #[test]
277 fn parse_entry_with_reference() {
278 let bytes = [
281 TAG, 10, 0x00, 0x01,
282 0x1A, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x09,
284 ];
285 let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
286 assert_eq!(d.entries.len(), 1);
287 assert_eq!(d.entries[0].announcement_type, 0x01);
288 assert_eq!(d.entries[0].reference_type, 0x02);
289 let r = d.entries[0].reference.unwrap();
290 assert_eq!(r.original_network_id, 0xAABB);
291 assert_eq!(r.transport_stream_id, 0xCCDD);
292 assert_eq!(r.service_id, 0xEEFF);
293 assert_eq!(r.component_tag, 0x09);
294 }
295
296 #[test]
297 fn parse_mixed_entries() {
298 let bytes = [
300 TAG, 11, 0x12, 0x34, 0x40, 0x53, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
304 ];
305 let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
306 assert_eq!(d.entries.len(), 2);
307 assert!(d.entries[0].reference.is_none());
308 assert_eq!(d.entries[1].reference_type, 0x03);
309 assert!(d.entries[1].reference.is_some());
310 }
311
312 #[test]
313 fn parse_ignores_reserved_bit() {
314 let bytes = [TAG, 3, 0x00, 0x00, 0x60];
316 let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
317 assert_eq!(d.entries[0].announcement_type, 0x06);
318 assert_eq!(d.entries[0].reference_type, 0x00);
319 }
320
321 #[test]
322 fn parse_rejects_wrong_tag() {
323 assert!(matches!(
324 AnnouncementSupportDescriptor::parse(&[0x6F, 2, 0, 0]).unwrap_err(),
325 Error::InvalidDescriptor { tag: 0x6F, .. }
326 ));
327 }
328
329 #[test]
330 fn parse_rejects_body_too_short_for_indicator() {
331 assert!(matches!(
332 AnnouncementSupportDescriptor::parse(&[TAG, 1, 0]).unwrap_err(),
333 Error::InvalidDescriptor { tag: TAG, .. }
334 ));
335 }
336
337 #[test]
338 fn parse_rejects_reference_truncated() {
339 let bytes = [TAG, 3, 0x00, 0x00, 0x09]; assert!(matches!(
342 AnnouncementSupportDescriptor::parse(&bytes).unwrap_err(),
343 Error::InvalidDescriptor { tag: TAG, .. }
344 ));
345 }
346
347 #[test]
348 fn parse_rejects_buffer_shorter_than_length() {
349 let bytes = [TAG, 5, 0x00, 0x00];
350 assert!(matches!(
351 AnnouncementSupportDescriptor::parse(&bytes).unwrap_err(),
352 Error::BufferTooShort { .. }
353 ));
354 }
355
356 #[test]
357 fn serialize_round_trip_mixed() {
358 let d = AnnouncementSupportDescriptor {
359 announcement_support_indicator: 0xBEEF,
360 entries: vec![
361 AnnouncementEntry {
362 announcement_type: 0x04,
363 reference_type: 0x00,
364 reference: None,
365 },
366 AnnouncementEntry {
367 announcement_type: 0x01,
368 reference_type: 0x02,
369 reference: Some(AnnouncementReference {
370 original_network_id: 0xAABB,
371 transport_stream_id: 0xCCDD,
372 service_id: 0xEEFF,
373 component_tag: 0x09,
374 }),
375 },
376 ],
377 };
378 let mut buf = vec![0u8; d.serialized_len()];
379 d.serialize_into(&mut buf).unwrap();
380 assert_eq!(AnnouncementSupportDescriptor::parse(&buf).unwrap(), d);
381 }
382
383 #[test]
384 fn serialize_rejects_too_small_buffer() {
385 let d = AnnouncementSupportDescriptor {
386 announcement_support_indicator: 0,
387 entries: vec![],
388 };
389 let mut buf = vec![0u8; 3];
390 assert!(matches!(
391 d.serialize_into(&mut buf).unwrap_err(),
392 Error::OutputBufferTooSmall { .. }
393 ));
394 }
395
396 #[test]
397 fn serialize_rejects_over_range_announcement_type() {
398 let d = AnnouncementSupportDescriptor {
399 announcement_support_indicator: 0,
400 entries: vec![AnnouncementEntry {
401 announcement_type: 0x10, reference_type: 0,
403 reference: None,
404 }],
405 };
406 let mut buf = vec![0u8; d.serialized_len()];
407 assert!(matches!(
408 d.serialize_into(&mut buf).unwrap_err(),
409 Error::InvalidDescriptor { tag: TAG, .. }
410 ));
411 }
412
413 #[test]
414 fn serialize_rejects_reference_mismatch() {
415 let d = AnnouncementSupportDescriptor {
417 announcement_support_indicator: 0,
418 entries: vec![AnnouncementEntry {
419 announcement_type: 0,
420 reference_type: 0x02,
421 reference: None,
422 }],
423 };
424 let mut buf = vec![0u8; d.serialized_len()];
425 assert!(matches!(
426 d.serialize_into(&mut buf).unwrap_err(),
427 Error::InvalidDescriptor { tag: TAG, .. }
428 ));
429 }
430
431 #[cfg(feature = "serde")]
432 #[test]
433 fn serde_round_trip() {
434 let d = AnnouncementSupportDescriptor {
435 announcement_support_indicator: 0xBEEF,
436 entries: vec![AnnouncementEntry {
437 announcement_type: 0x01,
438 reference_type: 0x02,
439 reference: Some(AnnouncementReference {
440 original_network_id: 0xAABB,
441 transport_stream_id: 0xCCDD,
442 service_id: 0xEEFF,
443 component_tag: 0x09,
444 }),
445 }],
446 };
447 let json = serde_json::to_string(&d).unwrap();
448 let _v: serde_json::Value = serde_json::from_str(&json).unwrap();
450 }
451}