Skip to main content

dvb_si/descriptors/
private_data_specifier.rs

1//! Private Data Specifier Descriptor — ETSI EN 300 468 §6.2.31 (tag 0x5F).
2//!
3//! Table 85 (PDF p. 98). A single 32-bit `private_data_specifier` value
4//! (registered in EN 300 468 Annex/TR 101 162) that scopes the interpretation
5//! of any subsequent private (user-defined) descriptors in the same loop.
6
7use super::descriptor_body;
8use crate::error::{Error, Result};
9use dvb_common::{Parse, Serialize};
10
11/// Descriptor tag for private_data_specifier_descriptor.
12pub const TAG: u8 = 0x5F;
13const HEADER_LEN: usize = 2;
14/// Fixed payload length: a single 32-bit specifier (EN 300 468 Table 85).
15const BODY_LEN: u8 = 4;
16
17/// Best-effort, non-exhaustive mapping from a 32-bit `private_data_specifier`
18/// to a human-readable organization name.  Verified entries from the
19/// DVB Services registry.
20#[must_use]
21pub fn private_data_specifier_name(v: u32) -> Option<&'static str> {
22    match v {
23        0x0000_0028 => Some("EACEM / EICTA"),
24        0x0000_0029 => Some("NorDig"),
25        0x0000_233A => Some("UK DTT (Independent Television Commission / DTG)"),
26        0x0000_0002 => Some("BSkyB"),
27        _ => None,
28    }
29}
30
31/// Private Data Specifier Descriptor (tag 0x5F).
32#[derive(Debug, Clone, PartialEq, Eq)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize))]
34pub struct PrivateDataSpecifierDescriptor {
35    /// 32-bit registered private_data_specifier (ETSI Table 85, PDF p. 98).
36    pub private_data_specifier: u32,
37}
38
39impl<'a> Parse<'a> for PrivateDataSpecifierDescriptor {
40    type Error = crate::error::Error;
41    fn parse(bytes: &'a [u8]) -> Result<Self> {
42        let body = descriptor_body(
43            bytes,
44            TAG,
45            "PrivateDataSpecifierDescriptor",
46            "unexpected tag for private_data_specifier_descriptor",
47        )?;
48        if body.len() != BODY_LEN as usize {
49            return Err(Error::InvalidDescriptor {
50                tag: TAG,
51                reason: "private_data_specifier_descriptor length must equal 4",
52            });
53        }
54        let private_data_specifier = u32::from_be_bytes([body[0], body[1], body[2], body[3]]);
55        Ok(Self {
56            private_data_specifier,
57        })
58    }
59}
60
61impl Serialize for PrivateDataSpecifierDescriptor {
62    type Error = crate::error::Error;
63    fn serialized_len(&self) -> usize {
64        HEADER_LEN + BODY_LEN as usize
65    }
66
67    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
68        let len = self.serialized_len();
69        if buf.len() < len {
70            return Err(Error::OutputBufferTooSmall {
71                need: len,
72                have: buf.len(),
73            });
74        }
75        buf[0] = TAG;
76        buf[1] = BODY_LEN;
77        buf[HEADER_LEN..HEADER_LEN + 4].copy_from_slice(&self.private_data_specifier.to_be_bytes());
78        Ok(len)
79    }
80}
81impl<'a> crate::traits::DescriptorDef<'a> for PrivateDataSpecifierDescriptor {
82    const TAG: u8 = TAG;
83    const NAME: &'static str = "PRIVATE_DATA_SPECIFIER";
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn parse_extracts_specifier() {
92        let bytes = [TAG, 4, 0x00, 0x00, 0x00, 0x28];
93        let d = PrivateDataSpecifierDescriptor::parse(&bytes).unwrap();
94        assert_eq!(d.private_data_specifier, 0x0000_0028);
95    }
96
97    #[test]
98    fn parse_rejects_wrong_tag() {
99        let err = PrivateDataSpecifierDescriptor::parse(&[0x60, 4, 0, 0, 0, 0]).unwrap_err();
100        assert!(matches!(err, Error::InvalidDescriptor { tag: 0x60, .. }));
101    }
102
103    #[test]
104    fn parse_rejects_short_buffer() {
105        let err = PrivateDataSpecifierDescriptor::parse(&[TAG]).unwrap_err();
106        assert!(matches!(err, Error::BufferTooShort { .. }));
107    }
108
109    #[test]
110    fn parse_rejects_truncated_body() {
111        // length=4 but only 2 payload bytes present.
112        let err = PrivateDataSpecifierDescriptor::parse(&[TAG, 4, 0, 0]).unwrap_err();
113        assert!(matches!(err, Error::BufferTooShort { .. }));
114    }
115
116    #[test]
117    fn parse_rejects_wrong_length() {
118        let err = PrivateDataSpecifierDescriptor::parse(&[TAG, 3, 0, 0, 0]).unwrap_err();
119        assert!(matches!(err, Error::InvalidDescriptor { .. }));
120    }
121
122    #[test]
123    fn serialize_round_trip() {
124        let d = PrivateDataSpecifierDescriptor {
125            private_data_specifier: 0xDEAD_BEEF,
126        };
127        let mut buf = vec![0u8; d.serialized_len()];
128        d.serialize_into(&mut buf).unwrap();
129        let re = PrivateDataSpecifierDescriptor::parse(&buf).unwrap();
130        assert_eq!(d, re);
131    }
132
133    #[test]
134    fn serialize_rejects_too_small_buffer() {
135        let d = PrivateDataSpecifierDescriptor {
136            private_data_specifier: 1,
137        };
138        let mut tiny = [0u8; 3];
139        let err = d.serialize_into(&mut tiny).unwrap_err();
140        assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
141    }
142
143    #[test]
144    fn descriptor_length_matches_payload() {
145        let d = PrivateDataSpecifierDescriptor {
146            private_data_specifier: 0,
147        };
148        assert_eq!(d.serialized_len() - 2, 4);
149    }
150
151    #[cfg(feature = "serde")]
152    #[test]
153    fn serde_round_trip() {
154        let d = PrivateDataSpecifierDescriptor {
155            private_data_specifier: 0x0000_233A,
156        };
157        let json = serde_json::to_string(&d).unwrap();
158        // Serialize-only: assert the emitted JSON re-parses (serialize-stable).
159        let _v: serde_json::Value = serde_json::from_str(&json).unwrap();
160    }
161
162    #[test]
163    fn specifier_name_verified() {
164        assert_eq!(
165            private_data_specifier_name(0x0000_0028),
166            Some("EACEM / EICTA")
167        );
168        assert_eq!(private_data_specifier_name(0x0000_0029), Some("NorDig"));
169        assert_eq!(
170            private_data_specifier_name(0x0000_233A),
171            Some("UK DTT (Independent Television Commission / DTG)")
172        );
173        assert_eq!(private_data_specifier_name(0x0000_0002), Some("BSkyB"));
174    }
175
176    #[test]
177    fn specifier_name_removed_entries_return_none() {
178        assert_eq!(private_data_specifier_name(0x0000_001A), None);
179        assert_eq!(private_data_specifier_name(0x0000_002A), None);
180        assert_eq!(private_data_specifier_name(0x0000_0030), None);
181    }
182
183    #[test]
184    fn specifier_name_unknown() {
185        assert_eq!(private_data_specifier_name(0xDEAD_BEEF), None);
186    }
187}