1use super::descriptor_body;
17use crate::error::{Error, Result};
18use dvb_common::{Parse, Serialize};
19
20pub const TAG: u8 = 0x4A;
22const HEADER_LEN: usize = 2;
23const FIXED_FIELDS_LEN: usize = 7;
24
25const HANDOVER_TYPE_MASK: u8 = 0xF0;
26const ORIGIN_TYPE_MASK: u8 = 0x01;
27const RESERVED_HANDOVER_MASK: u8 = 0x0E;
28
29const TARGET_LISTED_MASK: u8 = 0x80;
30const EVENT_SIMULCAST_MASK: u8 = 0x40;
31const RESERVED_EVENT_MASK: u8 = 0x3F;
32
33const EXT_TARGET_LISTED_MASK: u8 = 0x80;
34const EXT_EVENT_SIMULCAST_MASK: u8 = 0x40;
35const EXT_LINK_TYPE_MASK: u8 = 0x30;
36const EXT_TARGET_ID_TYPE_MASK: u8 = 0x0C;
37const EXT_ONID_FLAG_MASK: u8 = 0x02;
38const EXT_SID_FLAG_MASK: u8 = 0x01;
39
40#[derive(Debug, Clone, PartialEq, Eq)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize))]
43pub struct MobileHandOverInfo {
44 pub hand_over_type: u8,
46 pub origin_type: bool,
48 pub network_id: Option<u16>,
50 pub initial_service_id: Option<u16>,
52}
53
54impl MobileHandOverInfo {
55 fn serialized_len(&self) -> usize {
56 1 + self.network_id.map_or(0, |_| 2) + self.initial_service_id.map_or(0, |_| 2)
57 }
58
59 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
60 let len = self.serialized_len();
61 if buf.len() < len {
62 return Err(Error::OutputBufferTooSmall {
63 need: len,
64 have: buf.len(),
65 });
66 }
67 let flags_byte =
68 (self.hand_over_type << 4) | RESERVED_HANDOVER_MASK | u8::from(self.origin_type);
69 buf[0] = flags_byte;
70 let mut pos = 1;
71 if let Some(nid) = self.network_id {
72 buf[pos..pos + 2].copy_from_slice(&nid.to_be_bytes());
73 pos += 2;
74 }
75 if let Some(sid) = self.initial_service_id {
76 buf[pos..pos + 2].copy_from_slice(&sid.to_be_bytes());
77 }
78 Ok(len)
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
84#[cfg_attr(feature = "serde", derive(serde::Serialize))]
85pub struct EventLinkageInfo {
86 pub target_event_id: u16,
88 pub target_listed: bool,
90 pub event_simulcast: bool,
92}
93
94impl EventLinkageInfo {
95 const SERIALIZED_LEN: usize = 3;
96
97 fn serialized_len(&self) -> usize {
98 Self::SERIALIZED_LEN
99 }
100
101 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
102 if buf.len() < Self::SERIALIZED_LEN {
103 return Err(Error::OutputBufferTooSmall {
104 need: Self::SERIALIZED_LEN,
105 have: buf.len(),
106 });
107 }
108 buf[0..2].copy_from_slice(&self.target_event_id.to_be_bytes());
109 let mut byte2: u8 = RESERVED_EVENT_MASK;
110 if self.target_listed {
111 byte2 |= TARGET_LISTED_MASK;
112 }
113 if self.event_simulcast {
114 byte2 |= EVENT_SIMULCAST_MASK;
115 }
116 buf[2] = byte2;
117 Ok(Self::SERIALIZED_LEN)
118 }
119}
120
121#[derive(Debug, Clone, PartialEq, Eq)]
123#[cfg_attr(feature = "serde", derive(serde::Serialize))]
124pub enum TargetId {
125 UserDefined {
127 user_defined_id: u16,
129 },
130 Dvb {
132 target_id_type: u8,
134 target_transport_stream_id: Option<u16>,
136 target_original_network_id: Option<u16>,
138 target_service_id: Option<u16>,
140 },
141}
142
143impl TargetId {
144 fn serialized_len(&self) -> usize {
145 match self {
146 TargetId::UserDefined { .. } => 2,
147 TargetId::Dvb {
148 target_transport_stream_id,
149 target_original_network_id,
150 target_service_id,
151 ..
152 } => {
153 usize::from(target_transport_stream_id.is_some()) * 2
154 + usize::from(target_original_network_id.is_some()) * 2
155 + usize::from(target_service_id.is_some()) * 2
156 }
157 }
158 }
159
160 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
161 let len = self.serialized_len();
162 if buf.len() < len {
163 return Err(Error::OutputBufferTooSmall {
164 need: len,
165 have: buf.len(),
166 });
167 }
168 match self {
169 TargetId::UserDefined { user_defined_id } => {
170 buf[..2].copy_from_slice(&user_defined_id.to_be_bytes());
171 }
172 TargetId::Dvb {
173 target_transport_stream_id,
174 target_original_network_id,
175 target_service_id,
176 ..
177 } => {
178 let ts_len = target_transport_stream_id.map_or(0, |_| 2);
179 let onid_len = target_original_network_id.map_or(0, |_| 2);
180 if let Some(ts_id) = target_transport_stream_id {
181 buf[..2].copy_from_slice(&ts_id.to_be_bytes());
182 }
183 if let Some(onid) = target_original_network_id {
184 buf[ts_len..ts_len + 2].copy_from_slice(&onid.to_be_bytes());
185 }
186 if let Some(sid) = target_service_id {
187 let off = ts_len + onid_len;
188 buf[off..off + 2].copy_from_slice(&sid.to_be_bytes());
189 }
190 }
191 }
192 Ok(len)
193 }
194}
195
196#[derive(Debug, Clone, PartialEq, Eq)]
198#[cfg_attr(feature = "serde", derive(serde::Serialize))]
199pub struct ExtendedEventLinkageEntry {
200 pub target_event_id: u16,
202 pub target_listed: bool,
204 pub event_simulcast: bool,
206 pub link_type: u8,
208 pub target_id_type: u8,
210 pub original_network_id_flag: bool,
212 pub service_id_flag: bool,
214 pub target_id: TargetId,
216}
217
218impl ExtendedEventLinkageEntry {
219 fn serialized_len(&self) -> usize {
220 2 + 1 + self.target_id.serialized_len()
221 }
222
223 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
224 let flags_byte_len = 3;
225 if buf.len() < flags_byte_len {
226 return Err(Error::OutputBufferTooSmall {
227 need: flags_byte_len,
228 have: buf.len(),
229 });
230 }
231 buf[0..2].copy_from_slice(&self.target_event_id.to_be_bytes());
232 let mut byte2: u8 = 0;
233 if self.target_listed {
234 byte2 |= EXT_TARGET_LISTED_MASK;
235 }
236 if self.event_simulcast {
237 byte2 |= EXT_EVENT_SIMULCAST_MASK;
238 }
239 byte2 |= (self.link_type & 0x03) << 4;
240 byte2 |= (self.target_id_type & 0x03) << 2;
241 if self.original_network_id_flag {
242 byte2 |= EXT_ONID_FLAG_MASK;
243 }
244 if self.service_id_flag {
245 byte2 |= EXT_SID_FLAG_MASK;
246 }
247 buf[2] = byte2;
248 let tid_written = self.target_id.serialize_into(&mut buf[3..])?;
249 Ok(3 + tid_written)
250 }
251}
252
253#[derive(Debug, Clone, PartialEq, Eq)]
256#[cfg_attr(feature = "serde", derive(serde::Serialize))]
257pub struct ExtendedEventLinkageInfo {
258 pub entries: Vec<ExtendedEventLinkageEntry>,
260}
261
262impl ExtendedEventLinkageInfo {
263 fn serialized_len(&self) -> usize {
264 1 + self
265 .entries
266 .iter()
267 .map(|e| e.serialized_len())
268 .sum::<usize>()
269 }
270
271 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
272 let loop_len: usize = self.entries.iter().map(|e| e.serialized_len()).sum();
273 let total = 1 + loop_len;
274 if buf.len() < total {
275 return Err(Error::OutputBufferTooSmall {
276 need: total,
277 have: buf.len(),
278 });
279 }
280 buf[0] = loop_len as u8;
281 let mut pos = 1;
282 for entry in &self.entries {
283 let written = entry.serialize_into(&mut buf[pos..])?;
284 pos += written;
285 }
286 Ok(total)
287 }
288}
289
290#[derive(Debug, Clone, PartialEq, Eq)]
300#[non_exhaustive]
301#[cfg_attr(feature = "serde", derive(serde::Serialize))]
302pub enum LinkageData<'a> {
303 MobileHandOver(MobileHandOverInfo),
305 EventLinkage(EventLinkageInfo),
307 ExtendedEventLinkage(ExtendedEventLinkageInfo),
309 None,
312 #[cfg_attr(feature = "serde", serde(borrow))]
317 Other(&'a [u8]),
318}
319
320impl LinkageData<'_> {
321 fn serialized_len(&self) -> usize {
322 match self {
323 LinkageData::MobileHandOver(m) => m.serialized_len(),
324 LinkageData::EventLinkage(e) => e.serialized_len(),
325 LinkageData::ExtendedEventLinkage(x) => x.serialized_len(),
326 LinkageData::None => 0,
327 LinkageData::Other(b) => b.len(),
328 }
329 }
330
331 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
332 match self {
333 LinkageData::MobileHandOver(m) => m.serialize_into(buf),
334 LinkageData::EventLinkage(e) => e.serialize_into(buf),
335 LinkageData::ExtendedEventLinkage(x) => x.serialize_into(buf),
336 LinkageData::None => Ok(0),
337 LinkageData::Other(b) => {
338 if buf.len() < b.len() {
339 return Err(Error::OutputBufferTooSmall {
340 need: b.len(),
341 have: buf.len(),
342 });
343 }
344 buf[..b.len()].copy_from_slice(b);
345 Ok(b.len())
346 }
347 }
348 }
349}
350
351fn parse_mobile_handover(bytes: &[u8], end: usize) -> Result<MobileHandOverInfo> {
352 if end < 1 {
353 return Err(Error::InvalidDescriptor {
354 tag: TAG,
355 reason: "mobile hand-over info needs at least flags byte",
356 });
357 }
358 let flags_byte = bytes[0];
359 let hand_over_type = (flags_byte & HANDOVER_TYPE_MASK) >> 4;
360 let origin_type = (flags_byte & ORIGIN_TYPE_MASK) != 0;
361 let mut pos = 1;
362 let network_id = if matches!(hand_over_type, 0x01..=0x03) {
363 if pos + 2 > end {
364 return Err(Error::InvalidDescriptor {
365 tag: TAG,
366 reason: "mobile hand-over info with gated network_id needs at least 3 bytes",
367 });
368 }
369 let nid = u16::from_be_bytes([bytes[pos], bytes[pos + 1]]);
370 pos += 2;
371 Some(nid)
372 } else {
373 None
374 };
375 let initial_service_id = if !origin_type {
376 if pos + 2 > end {
377 return Err(Error::InvalidDescriptor {
378 tag: TAG,
379 reason: "mobile hand-over info with origin_type=NIT needs initial_service_id",
380 });
381 }
382 Some(u16::from_be_bytes([bytes[pos], bytes[pos + 1]]))
383 } else {
384 None
385 };
386 Ok(MobileHandOverInfo {
387 hand_over_type,
388 origin_type,
389 network_id,
390 initial_service_id,
391 })
392}
393
394fn parse_event_linkage(bytes: &[u8]) -> Result<EventLinkageInfo> {
395 if bytes.len() < 3 {
396 return Err(Error::InvalidDescriptor {
397 tag: TAG,
398 reason: "event linkage info needs 3 bytes",
399 });
400 }
401 let target_event_id = u16::from_be_bytes([bytes[0], bytes[1]]);
402 let target_listed = (bytes[2] & TARGET_LISTED_MASK) != 0;
403 let event_simulcast = (bytes[2] & EVENT_SIMULCAST_MASK) != 0;
404 Ok(EventLinkageInfo {
405 target_event_id,
406 target_listed,
407 event_simulcast,
408 })
409}
410
411fn parse_extended_event_linkage(bytes: &[u8]) -> Result<ExtendedEventLinkageInfo> {
412 if bytes.is_empty() {
413 return Err(Error::InvalidDescriptor {
414 tag: TAG,
415 reason: "extended event linkage info needs at least loop_length byte",
416 });
417 }
418 let loop_length = bytes[0] as usize;
419 let loop_end = 1 + loop_length;
420 if bytes.len() < loop_end {
421 return Err(Error::BufferTooShort {
422 need: loop_end,
423 have: bytes.len(),
424 what: "extended event linkage info loop",
425 });
426 }
427 let mut entries = Vec::new();
428 let mut pos = 1;
429 let read_u16 = |p: &mut usize| -> Result<u16> {
430 if *p + 2 > loop_end {
431 return Err(Error::InvalidDescriptor {
432 tag: TAG,
433 reason: "extended event linkage entry truncated (need u16)",
434 });
435 }
436 let v = u16::from_be_bytes([bytes[*p], bytes[*p + 1]]);
437 *p += 2;
438 Ok(v)
439 };
440 while pos < loop_end {
441 let target_event_id = read_u16(&mut pos)?;
442 if pos >= loop_end {
443 return Err(Error::InvalidDescriptor {
444 tag: TAG,
445 reason: "extended event linkage entry truncated (need flags byte)",
446 });
447 }
448 let fb = bytes[pos];
449 pos += 1;
450 let target_listed = (fb & EXT_TARGET_LISTED_MASK) != 0;
451 let event_simulcast = (fb & EXT_EVENT_SIMULCAST_MASK) != 0;
452 let link_type = (fb & EXT_LINK_TYPE_MASK) >> 4;
453 let target_id_type = (fb & EXT_TARGET_ID_TYPE_MASK) >> 2;
454 let original_network_id_flag = (fb & EXT_ONID_FLAG_MASK) != 0;
455 let service_id_flag = (fb & EXT_SID_FLAG_MASK) != 0;
456
457 let target_id = if target_id_type == 3 {
458 let user_defined_id = read_u16(&mut pos)?;
459 TargetId::UserDefined { user_defined_id }
460 } else {
461 let target_transport_stream_id = if target_id_type == 1 {
462 Some(read_u16(&mut pos)?)
463 } else {
464 None
465 };
466 let target_original_network_id = if original_network_id_flag {
467 Some(read_u16(&mut pos)?)
468 } else {
469 None
470 };
471 let target_service_id = if service_id_flag {
472 Some(read_u16(&mut pos)?)
473 } else {
474 None
475 };
476 TargetId::Dvb {
477 target_id_type,
478 target_transport_stream_id,
479 target_original_network_id,
480 target_service_id,
481 }
482 };
483 entries.push(ExtendedEventLinkageEntry {
484 target_event_id,
485 target_listed,
486 event_simulcast,
487 link_type,
488 target_id_type,
489 original_network_id_flag,
490 service_id_flag,
491 target_id,
492 });
493 }
494 Ok(ExtendedEventLinkageInfo { entries })
495}
496
497#[derive(Debug, Clone, PartialEq, Eq)]
499#[cfg_attr(feature = "serde", derive(serde::Serialize))]
500#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
501pub struct LinkageDescriptor<'a> {
502 pub transport_stream_id: u16,
504 pub original_network_id: u16,
506 pub service_id: u16,
509 pub linkage_type: u8,
517 pub linkage_data: LinkageData<'a>,
519 pub private_data: &'a [u8],
522}
523
524const LINKAGE_TYPES_WITH_OTHER: &[u8] = &[0x09, 0x0A, 0x0B, 0x0C, 0x20, 0x21];
525
526impl<'a> Parse<'a> for LinkageDescriptor<'a> {
527 type Error = crate::error::Error;
528 fn parse(bytes: &'a [u8]) -> Result<Self> {
529 let body = descriptor_body(
530 bytes,
531 TAG,
532 "LinkageDescriptor",
533 "unexpected tag for linkage_descriptor",
534 )?;
535 if body.len() < FIXED_FIELDS_LEN {
536 return Err(Error::InvalidDescriptor {
537 tag: TAG,
538 reason: "linkage_descriptor body shorter than minimum 7 bytes",
539 });
540 }
541 let transport_stream_id = u16::from_be_bytes([body[0], body[1]]);
542 let original_network_id = u16::from_be_bytes([body[2], body[3]]);
543 let service_id = u16::from_be_bytes([body[4], body[5]]);
544 let linkage_type = body[6];
545 let tail = &body[FIXED_FIELDS_LEN..];
546 let tail_len = tail.len();
547
548 let (linkage_data, private_data) = match linkage_type {
549 0x08 => {
550 let info = parse_mobile_handover(tail, tail_len)?;
551 let consumed = info.serialized_len();
552 (LinkageData::MobileHandOver(info), &tail[consumed..])
553 }
554 0x0D => {
555 let info = parse_event_linkage(tail)?;
556 let consumed = EventLinkageInfo::SERIALIZED_LEN;
557 (LinkageData::EventLinkage(info), &tail[consumed..])
558 }
559 0x0E..=0x1F => {
560 let info = parse_extended_event_linkage(tail)?;
561 let consumed = info.serialized_len();
562 (LinkageData::ExtendedEventLinkage(info), &tail[consumed..])
563 }
564 lt if LINKAGE_TYPES_WITH_OTHER.contains(<) || (0x80..=0xFE).contains(<) => {
565 (LinkageData::Other(tail), &[] as &[u8])
566 }
567 _ => (LinkageData::None, tail),
568 };
569 Ok(Self {
570 transport_stream_id,
571 original_network_id,
572 service_id,
573 linkage_type,
574 linkage_data,
575 private_data,
576 })
577 }
578}
579
580impl Serialize for LinkageDescriptor<'_> {
581 type Error = crate::error::Error;
582 fn serialized_len(&self) -> usize {
583 HEADER_LEN + FIXED_FIELDS_LEN + self.linkage_data.serialized_len() + self.private_data.len()
584 }
585
586 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
587 let len = self.serialized_len();
588 if buf.len() < len {
589 return Err(Error::OutputBufferTooSmall {
590 need: len,
591 have: buf.len(),
592 });
593 }
594 buf[0] = TAG;
595 buf[1] = (len - HEADER_LEN) as u8;
596 let bs = HEADER_LEN;
597 buf[bs..bs + 2].copy_from_slice(&self.transport_stream_id.to_be_bytes());
598 buf[bs + 2..bs + 4].copy_from_slice(&self.original_network_id.to_be_bytes());
599 buf[bs + 4..bs + 6].copy_from_slice(&self.service_id.to_be_bytes());
600 buf[bs + 6] = self.linkage_type;
601 let ld_start = bs + FIXED_FIELDS_LEN;
602 let ld_written = self.linkage_data.serialize_into(&mut buf[ld_start..])?;
603 let pd_start = ld_start + ld_written;
604 if !self.private_data.is_empty() {
605 buf[pd_start..pd_start + self.private_data.len()].copy_from_slice(self.private_data);
606 }
607 Ok(len)
608 }
609}
610impl<'a> crate::traits::DescriptorDef<'a> for LinkageDescriptor<'a> {
611 const TAG: u8 = TAG;
612 const NAME: &'static str = "LINKAGE";
613}
614
615#[cfg(test)]
616mod tests {
617 use super::*;
618
619 #[test]
620 fn parse_extracts_tsid_onid_sid() {
621 let bytes = [
622 TAG, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x05, 0xAA, 0xBB,
623 ];
624 let d = LinkageDescriptor::parse(&bytes).unwrap();
625 assert_eq!(d.transport_stream_id, 0x0001);
626 assert_eq!(d.original_network_id, 0x0002);
627 assert_eq!(d.service_id, 0x0003);
628 }
629
630 #[test]
631 fn parse_extracts_linkage_type() {
632 let bytes = [TAG, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x06];
633 let d = LinkageDescriptor::parse(&bytes).unwrap();
634 assert_eq!(d.linkage_type, 0x06);
635 }
636
637 #[test]
638 fn parse_none_type_preserves_private_data() {
639 let bytes = [
640 TAG, 0x0A, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x05, 0xAA, 0xBB, 0xCC,
641 ];
642 let d = LinkageDescriptor::parse(&bytes).unwrap();
643 assert!(matches!(d.linkage_data, LinkageData::None));
644 assert_eq!(d.private_data, &[0xAA, 0xBB, 0xCC]);
645 }
646
647 #[test]
648 fn parse_accepts_empty_private_data() {
649 let bytes = [TAG, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x05];
650 let d = LinkageDescriptor::parse(&bytes).unwrap();
651 assert!(d.private_data.is_empty());
652 }
653
654 #[test]
655 fn parse_mobile_handover_with_initial_sid() {
656 let bytes = [
657 TAG, 0x0E, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x08, 0x12, 0x00, 0x10, 0x00, 0x20, 0xDE, 0xAD, ];
667 let d = LinkageDescriptor::parse(&bytes).unwrap();
668 assert_eq!(d.linkage_type, 0x08);
669 match &d.linkage_data {
670 LinkageData::MobileHandOver(m) => {
671 assert_eq!(m.hand_over_type, 1);
672 assert!(!m.origin_type);
673 assert_eq!(m.network_id, Some(0x0010));
674 assert_eq!(m.initial_service_id, Some(0x0020));
675 }
676 other => panic!("expected MobileHandOver, got {other:?}"),
677 }
678 assert_eq!(d.private_data, &[0xDE, 0xAD]);
679 }
680
681 #[test]
682 fn parse_mobile_handover_sdt_no_initial_sid() {
683 let bytes = [
684 TAG, 0x0C, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x08, 0x2F, 0x00, 0x10, 0xCA, 0xFE, ];
693 let d = LinkageDescriptor::parse(&bytes).unwrap();
694 match &d.linkage_data {
695 LinkageData::MobileHandOver(m) => {
696 assert_eq!(m.hand_over_type, 2);
697 assert!(m.origin_type);
698 assert_eq!(m.network_id, Some(0x0010));
699 assert_eq!(m.initial_service_id, None);
700 }
701 other => panic!("expected MobileHandOver, got {other:?}"),
702 }
703 assert_eq!(d.private_data, &[0xCA, 0xFE]);
704 }
705
706 #[test]
707 fn parse_event_linkage() {
708 let bytes = [
709 TAG, 0x0C, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x0D, 0xAB, 0xCD, 0xC0, 0xBE, 0xEF, ];
718 let d = LinkageDescriptor::parse(&bytes).unwrap();
719 match &d.linkage_data {
720 LinkageData::EventLinkage(e) => {
721 assert_eq!(e.target_event_id, 0xABCD);
722 assert!(e.target_listed);
723 assert!(e.event_simulcast);
724 }
725 other => panic!("expected EventLinkage, got {other:?}"),
726 }
727 assert_eq!(d.private_data, &[0xBE, 0xEF]);
728 }
729
730 #[test]
731 fn parse_extended_event_linkage_user_defined() {
732 let bytes = [
733 TAG, 0x0E, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x0E, 0x05, 0x12, 0x34, 0xCC, 0x56, 0x78, 0xCC, ];
744 let d = LinkageDescriptor::parse(&bytes).unwrap();
745 match &d.linkage_data {
746 LinkageData::ExtendedEventLinkage(x) => {
747 assert_eq!(x.entries.len(), 1);
748 let e = &x.entries[0];
749 assert_eq!(e.target_event_id, 0x1234);
750 assert!(e.target_listed);
751 assert!(e.event_simulcast);
752 assert_eq!(e.link_type, 0);
753 assert_eq!(e.target_id_type, 3);
754 assert_eq!(
755 e.target_id,
756 TargetId::UserDefined {
757 user_defined_id: 0x5678
758 }
759 );
760 }
761 other => panic!("expected ExtendedEventLinkage, got {other:?}"),
762 }
763 assert_eq!(d.private_data, &[0xCC]);
764 }
765
766 #[test]
767 fn parse_extended_event_linkage_dvb_target() {
768 let bytes = [
769 TAG, 0x0F, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x0F, 0x07, 0xAA, 0xBB, 0x26, 0x00, 0x11, 0x00, 0x22, ];
780 let d = LinkageDescriptor::parse(&bytes).unwrap();
781 match &d.linkage_data {
782 LinkageData::ExtendedEventLinkage(x) => {
783 assert_eq!(x.entries.len(), 1);
784 let e = &x.entries[0];
785 assert_eq!(e.target_id_type, 1);
786 assert!(e.original_network_id_flag);
787 assert!(!e.service_id_flag);
788 assert_eq!(
789 e.target_id,
790 TargetId::Dvb {
791 target_id_type: 1,
792 target_transport_stream_id: Some(0x0011),
793 target_original_network_id: Some(0x0022),
794 target_service_id: None,
795 }
796 );
797 }
798 other => panic!("expected ExtendedEventLinkage, got {other:?}"),
799 }
800 assert_eq!(d.private_data, &[] as &[u8]);
801 }
802
803 #[test]
804 fn parse_other_type_captures_raw_tail() {
805 let bytes = [
806 TAG, 0x0A, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x0B, 0xAA, 0xBB, 0xCC, ];
813 let d = LinkageDescriptor::parse(&bytes).unwrap();
814 match &d.linkage_data {
815 LinkageData::Other(b) => assert_eq!(*b, &[0xAA, 0xBB, 0xCC]),
816 other => panic!("expected Other, got {other:?}"),
817 }
818 assert!(d.private_data.is_empty());
819 }
820
821 #[test]
822 fn parse_user_defined_type_is_other() {
823 let bytes = [
824 TAG, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x90, 0xFF, 0xFE, ];
831 let d = LinkageDescriptor::parse(&bytes).unwrap();
832 assert!(matches!(d.linkage_data, LinkageData::Other(_)));
833 }
834
835 #[test]
836 fn parse_rejects_wrong_tag() {
837 let err = LinkageDescriptor::parse(&[0x4B, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x05])
838 .unwrap_err();
839 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x4B, .. }));
840 }
841
842 #[test]
843 fn parse_rejects_body_shorter_than_seven() {
844 let bytes = [TAG, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00];
845 let err = LinkageDescriptor::parse(&bytes).unwrap_err();
846 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
847 }
848
849 #[test]
850 fn parse_rejects_truncated_buffer() {
851 let err = LinkageDescriptor::parse(&[TAG]).unwrap_err();
852 assert!(matches!(err, Error::BufferTooShort { .. }));
853 }
854
855 #[test]
856 fn parse_rejects_truncated_mobile_handover() {
857 let bytes = [
858 TAG, 0x08, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x08, 0x10, 0x00, 0x10, ];
863 let err = LinkageDescriptor::parse(&bytes).unwrap_err();
864 assert!(
865 matches!(err, Error::InvalidDescriptor { .. }),
866 "expected InvalidDescriptor for truncated mobile hand-over, got {err:?}"
867 );
868 }
869
870 #[test]
871 fn serialize_round_trip_no_linkage_data() {
872 let d = LinkageDescriptor {
873 transport_stream_id: 0x1234,
874 original_network_id: 0x5678,
875 service_id: 0xABCD,
876 linkage_type: 0x02,
877 linkage_data: LinkageData::None,
878 private_data: &[],
879 };
880 let mut buf = vec![0u8; d.serialized_len()];
881 d.serialize_into(&mut buf).unwrap();
882 let re = LinkageDescriptor::parse(&buf).unwrap();
883 assert_eq!(d, re);
884 }
885
886 #[test]
887 fn serialize_round_trip_with_private_data() {
888 let d = LinkageDescriptor {
889 transport_stream_id: 0x0001,
890 original_network_id: 0x0002,
891 service_id: 0x0003,
892 linkage_type: 0x05,
893 linkage_data: LinkageData::None,
894 private_data: &[0xDE, 0xAD, 0xBE, 0xEF],
895 };
896 let mut buf = vec![0u8; d.serialized_len()];
897 d.serialize_into(&mut buf).unwrap();
898 let re = LinkageDescriptor::parse(&buf).unwrap();
899 assert_eq!(d, re);
900 }
901
902 #[test]
903 fn serialize_round_trip_mobile_handover() {
904 let d = LinkageDescriptor {
905 transport_stream_id: 0x0001,
906 original_network_id: 0x0002,
907 service_id: 0x0003,
908 linkage_type: 0x08,
909 linkage_data: LinkageData::MobileHandOver(MobileHandOverInfo {
910 hand_over_type: 3,
911 origin_type: false,
912 network_id: Some(0x0044),
913 initial_service_id: Some(0x0055),
914 }),
915 private_data: &[0xFF],
916 };
917 let mut buf = vec![0u8; d.serialized_len()];
918 d.serialize_into(&mut buf).unwrap();
919 let re = LinkageDescriptor::parse(&buf).unwrap();
920 assert_eq!(d, re);
921 }
922
923 #[test]
924 fn serialize_round_trip_event_linkage() {
925 let d = LinkageDescriptor {
926 transport_stream_id: 0x0001,
927 original_network_id: 0x0002,
928 service_id: 0x0003,
929 linkage_type: 0x0D,
930 linkage_data: LinkageData::EventLinkage(EventLinkageInfo {
931 target_event_id: 0x1234,
932 target_listed: true,
933 event_simulcast: false,
934 }),
935 private_data: &[],
936 };
937 let mut buf = vec![0u8; d.serialized_len()];
938 d.serialize_into(&mut buf).unwrap();
939 let re = LinkageDescriptor::parse(&buf).unwrap();
940 assert_eq!(d, re);
941 }
942
943 #[test]
944 fn serialize_round_trip_extended_event_linkage() {
945 let d = LinkageDescriptor {
946 transport_stream_id: 0x0001,
947 original_network_id: 0x0002,
948 service_id: 0x0003,
949 linkage_type: 0x0E,
950 linkage_data: LinkageData::ExtendedEventLinkage(ExtendedEventLinkageInfo {
951 entries: vec![ExtendedEventLinkageEntry {
952 target_event_id: 0xAAAA,
953 target_listed: true,
954 event_simulcast: true,
955 link_type: 1,
956 target_id_type: 1,
957 original_network_id_flag: true,
958 service_id_flag: true,
959 target_id: TargetId::Dvb {
960 target_id_type: 1,
961 target_transport_stream_id: Some(0x1111),
962 target_original_network_id: Some(0x2222),
963 target_service_id: Some(0x3333),
964 },
965 }],
966 }),
967 private_data: &[0xCC],
968 };
969 let mut buf = vec![0u8; d.serialized_len()];
970 d.serialize_into(&mut buf).unwrap();
971 let re = LinkageDescriptor::parse(&buf).unwrap();
972 assert_eq!(d, re);
973 }
974
975 #[test]
976 fn serialize_round_trip_other() {
977 let raw = [0xAA, 0xBB, 0xCC];
978 let d = LinkageDescriptor {
979 transport_stream_id: 0x0001,
980 original_network_id: 0x0002,
981 service_id: 0x0003,
982 linkage_type: 0x0B,
983 linkage_data: LinkageData::Other(&raw),
984 private_data: &[],
985 };
986 let mut buf = vec![0u8; d.serialized_len()];
987 d.serialize_into(&mut buf).unwrap();
988 let re = LinkageDescriptor::parse(&buf).unwrap();
989 assert_eq!(d, re);
990 }
991
992 #[test]
993 fn serialize_reserved_bits_are_set() {
994 let d = LinkageDescriptor {
995 transport_stream_id: 0x0001,
996 original_network_id: 0x0002,
997 service_id: 0x0003,
998 linkage_type: 0x0D,
999 linkage_data: LinkageData::EventLinkage(EventLinkageInfo {
1000 target_event_id: 0x0000,
1001 target_listed: false,
1002 event_simulcast: false,
1003 }),
1004 private_data: &[],
1005 };
1006 let mut buf = vec![0u8; d.serialized_len()];
1007 d.serialize_into(&mut buf).unwrap();
1008 assert_eq!(buf[11] & RESERVED_EVENT_MASK, RESERVED_EVENT_MASK);
1009
1010 let d2 = LinkageDescriptor {
1011 transport_stream_id: 0x0001,
1012 original_network_id: 0x0002,
1013 service_id: 0x0003,
1014 linkage_type: 0x08,
1015 linkage_data: LinkageData::MobileHandOver(MobileHandOverInfo {
1016 hand_over_type: 0,
1017 origin_type: true,
1018 network_id: None,
1019 initial_service_id: None,
1020 }),
1021 private_data: &[],
1022 };
1023 let mut buf2 = vec![0u8; d2.serialized_len()];
1024 d2.serialize_into(&mut buf2).unwrap();
1025 assert_eq!(buf2[9] & RESERVED_HANDOVER_MASK, RESERVED_HANDOVER_MASK);
1026 }
1027
1028 #[test]
1029 fn parse_mobile_handover_type4_no_network_id() {
1030 let bytes = [
1031 TAG, 0x0A, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x08, 0x4E, 0x00, 0x20, ];
1039 let d = LinkageDescriptor::parse(&bytes).unwrap();
1040 match &d.linkage_data {
1041 LinkageData::MobileHandOver(m) => {
1042 assert_eq!(m.hand_over_type, 4);
1043 assert!(!m.origin_type);
1044 assert_eq!(m.network_id, None);
1045 assert_eq!(m.initial_service_id, Some(0x0020));
1046 }
1047 other => panic!("expected MobileHandOver, got {other:?}"),
1048 }
1049 }
1050
1051 #[test]
1052 fn parse_mobile_handover_type1_network_id_present() {
1053 let bytes = [
1054 TAG, 0x0C, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x08, 0x1F, 0x00, 0x10, 0xCA, 0xFE, ];
1063 let d = LinkageDescriptor::parse(&bytes).unwrap();
1064 match &d.linkage_data {
1065 LinkageData::MobileHandOver(m) => {
1066 assert_eq!(m.hand_over_type, 1);
1067 assert!(m.origin_type);
1068 assert_eq!(m.network_id, Some(0x0010));
1069 assert_eq!(m.initial_service_id, None);
1070 }
1071 other => panic!("expected MobileHandOver, got {other:?}"),
1072 }
1073 assert_eq!(d.private_data, &[0xCA, 0xFE]);
1074 }
1075}