Skip to main content

dvb_si/descriptors/extension/
protection_message.rs

1//! Protection Message Descriptor — ETSI TS 102 809 §9.3.3, Table 40 (tag_extension 0x18).
2use super::*;
3
4impl<'a> ExtensionBodyDef<'a> for ProtectionMessage<'a> {
5    const TAG_EXTENSION: u8 = 0x18;
6    const NAME: &'static str = "PROTECTION_MESSAGE";
7}
8
9/// Largest `component_count` the 4-bit field can carry.
10const MAX_COMPONENT_COUNT: usize = 0x0F;
11
12/// protection_message body (Table 40, §9.3.3): the list of protected
13/// `component_tag`s. `component_count` is a 4-bit field, so at most 15 tags.
14#[derive(Debug, Clone, PartialEq, Eq)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize))]
16#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
17pub struct ProtectionMessage<'a> {
18    /// reserved(4) — preserved verbatim for byte-exact round-trip.
19    pub reserved: u8,
20    /// The `component_tag` list (one `u8` per protected component;
21    /// `component_count` is its length).
22    #[cfg_attr(feature = "serde", serde(borrow))]
23    pub component_tags: &'a [u8],
24}
25
26impl<'a> Parse<'a> for ProtectionMessage<'a> {
27    type Error = crate::error::Error;
28    fn parse(sel: &'a [u8]) -> Result<Self> {
29        let first = *sel.first().ok_or(Error::BufferTooShort {
30            need: 1,
31            have: 0,
32            what: "protection_message body",
33        })?;
34        let reserved = first >> 4;
35        let component_count = usize::from(first & 0x0F);
36        let component_tags = sel
37            .get(1..1 + component_count)
38            .ok_or(Error::BufferTooShort {
39                need: 1 + component_count,
40                have: sel.len(),
41                what: "protection_message component_tags",
42            })?;
43        Ok(ProtectionMessage {
44            reserved,
45            component_tags,
46        })
47    }
48}
49
50impl Serialize for ProtectionMessage<'_> {
51    type Error = crate::error::Error;
52    fn serialized_len(&self) -> usize {
53        1 + self.component_tags.len()
54    }
55    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
56        if self.component_tags.len() > MAX_COMPONENT_COUNT {
57            return Err(Error::ValueOutOfRange {
58                field: "protection_message component_count",
59                reason: "more than 15 component_tags (4-bit field)",
60            });
61        }
62        let len = self.serialized_len();
63        if buf.len() < len {
64            return Err(Error::OutputBufferTooSmall {
65                need: len,
66                have: buf.len(),
67            });
68        }
69        buf[0] = ((self.reserved & 0x0F) << 4) | (self.component_tags.len() as u8 & 0x0F);
70        buf[1..len].copy_from_slice(self.component_tags);
71        Ok(len)
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use crate::descriptors::extension::test_support::*;
79    use crate::descriptors::extension::{ExtensionBody, ExtensionDescriptor};
80
81    #[test]
82    fn parse_protection_message_structured() {
83        // reserved=0xF, component_count=3, tags 0x10/0x20/0x30
84        let sel = [0xF3, 0x10, 0x20, 0x30];
85        let bytes = wrap(0x18, &sel);
86        let d = ExtensionDescriptor::parse(&bytes).unwrap();
87        match &d.body {
88            ExtensionBody::ProtectionMessage(b) => {
89                assert_eq!(b.reserved, 0x0F);
90                assert_eq!(b.component_tags, &[0x10, 0x20, 0x30]);
91            }
92            other => panic!("expected ProtectionMessage, got {other:?}"),
93        }
94        round_trip(&d);
95    }
96
97    #[test]
98    fn parse_protection_message_empty() {
99        let sel = [0xF0]; // reserved=0xF, component_count=0
100        let bytes = wrap(0x18, &sel);
101        let d = ExtensionDescriptor::parse(&bytes).unwrap();
102        match &d.body {
103            ExtensionBody::ProtectionMessage(b) => assert!(b.component_tags.is_empty()),
104            other => panic!("expected ProtectionMessage, got {other:?}"),
105        }
106        round_trip(&d);
107    }
108
109    #[test]
110    fn serialize_rejects_oversized_component_list() {
111        let tags = [0u8; 16];
112        let pm = ProtectionMessage {
113            reserved: 0x0F,
114            component_tags: &tags,
115        };
116        let mut buf = [0u8; 32];
117        assert!(matches!(
118            pm.serialize_into(&mut buf),
119            Err(Error::ValueOutOfRange { .. })
120        ));
121    }
122}