1use super::descriptor_body;
8use crate::error::{Error, Result};
9use dvb_common::{Parse, Serialize};
10
11pub const TAG: u8 = 0x66;
13const HEADER_LEN: usize = 2;
14const ID_LEN: usize = 2;
16
17#[must_use]
22pub fn data_broadcast_id_name(id: u16) -> Option<&'static str> {
23 match id {
24 0x0005 => Some("Multiprotocol Encapsulation (MPE)"),
25 0x0006 => Some("Data Carousel"),
26 0x0007 => Some("Object Carousel"),
27 0x000A => Some("System Software Update (SSU)"),
28 0x000B => Some("IP/MAC Notification (INT)"),
29 0x00F0 => Some("MHP Object Carousel"),
30 0x0123 => Some("HbbTV"),
31 _ => None,
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize))]
38#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
39pub struct DataBroadcastIdDescriptor<'a> {
40 pub data_broadcast_id: u16,
42 pub id_selector: &'a [u8],
45}
46
47impl<'a> Parse<'a> for DataBroadcastIdDescriptor<'a> {
48 type Error = crate::error::Error;
49 fn parse(bytes: &'a [u8]) -> Result<Self> {
50 let body = descriptor_body(
51 bytes,
52 TAG,
53 "DataBroadcastIdDescriptor",
54 "unexpected tag for data_broadcast_id_descriptor",
55 )?;
56 if body.len() < ID_LEN {
57 return Err(Error::InvalidDescriptor {
58 tag: TAG,
59 reason: "data_broadcast_id_descriptor body shorter than 2 bytes",
60 });
61 }
62 let data_broadcast_id = u16::from_be_bytes([body[0], body[1]]);
63 let id_selector = &body[ID_LEN..];
64 Ok(Self {
65 data_broadcast_id,
66 id_selector,
67 })
68 }
69}
70
71impl Serialize for DataBroadcastIdDescriptor<'_> {
72 type Error = crate::error::Error;
73 fn serialized_len(&self) -> usize {
74 HEADER_LEN + ID_LEN + self.id_selector.len()
75 }
76
77 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
78 let len = self.serialized_len();
79 let body = ID_LEN + self.id_selector.len();
80 if body > u8::MAX as usize {
81 return Err(Error::InvalidDescriptor {
82 tag: TAG,
83 reason: "data_broadcast_id_descriptor body exceeds 255 bytes",
84 });
85 }
86 if buf.len() < len {
87 return Err(Error::OutputBufferTooSmall {
88 need: len,
89 have: buf.len(),
90 });
91 }
92 buf[0] = TAG;
93 buf[1] = body as u8;
94 buf[HEADER_LEN..HEADER_LEN + ID_LEN].copy_from_slice(&self.data_broadcast_id.to_be_bytes());
95 let sel_start = HEADER_LEN + ID_LEN;
96 buf[sel_start..sel_start + self.id_selector.len()].copy_from_slice(self.id_selector);
97 Ok(len)
98 }
99}
100impl<'a> crate::traits::DescriptorDef<'a> for DataBroadcastIdDescriptor<'a> {
101 const TAG: u8 = TAG;
102 const NAME: &'static str = "DATA_BROADCAST_ID";
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn parse_extracts_id_and_selector() {
111 let bytes = [TAG, 0x05, 0x00, 0x0B, 0xAA, 0xBB, 0xCC];
112 let d = DataBroadcastIdDescriptor::parse(&bytes).unwrap();
113 assert_eq!(d.data_broadcast_id, 0x000B);
114 assert_eq!(d.id_selector, &[0xAA, 0xBB, 0xCC]);
115 }
116
117 #[test]
118 fn parse_accepts_empty_selector() {
119 let bytes = [TAG, 0x02, 0x00, 0x0A];
120 let d = DataBroadcastIdDescriptor::parse(&bytes).unwrap();
121 assert_eq!(d.data_broadcast_id, 0x000A);
122 assert!(d.id_selector.is_empty());
123 }
124
125 #[test]
126 fn data_broadcast_id_name_verified() {
127 assert_eq!(
128 data_broadcast_id_name(0x0005),
129 Some("Multiprotocol Encapsulation (MPE)")
130 );
131 assert_eq!(data_broadcast_id_name(0x0006), Some("Data Carousel"));
132 assert_eq!(data_broadcast_id_name(0x0007), Some("Object Carousel"));
133 assert_eq!(
134 data_broadcast_id_name(0x000A),
135 Some("System Software Update (SSU)")
136 );
137 assert_eq!(
138 data_broadcast_id_name(0x000B),
139 Some("IP/MAC Notification (INT)")
140 );
141 assert_eq!(data_broadcast_id_name(0x00F0), Some("MHP Object Carousel"));
142 assert_eq!(data_broadcast_id_name(0x0123), Some("HbbTV"));
143 }
144
145 #[test]
146 fn data_broadcast_id_name_removed_entries_return_none() {
147 assert_eq!(data_broadcast_id_name(0x00F1), None);
148 assert_eq!(data_broadcast_id_name(0x00F2), None);
149 assert_eq!(data_broadcast_id_name(0x00F3), None);
150 assert_eq!(data_broadcast_id_name(0x00F4), None);
151 }
152
153 #[test]
154 fn data_broadcast_id_name_unknown() {
155 assert_eq!(data_broadcast_id_name(0x0000), None);
156 assert_eq!(data_broadcast_id_name(0xFFFF), None);
157 }
158
159 #[test]
160 fn parse_rejects_wrong_tag() {
161 let err = DataBroadcastIdDescriptor::parse(&[0x65, 0x02, 0x00, 0x0A]).unwrap_err();
162 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x65, .. }));
163 }
164
165 #[test]
166 fn parse_rejects_short_buffer() {
167 let err = DataBroadcastIdDescriptor::parse(&[TAG]).unwrap_err();
168 assert!(matches!(err, Error::BufferTooShort { .. }));
169 }
170
171 #[test]
172 fn parse_rejects_body_too_short() {
173 let err = DataBroadcastIdDescriptor::parse(&[TAG, 0x01, 0x00]).unwrap_err();
175 assert!(matches!(err, Error::InvalidDescriptor { .. }));
176 }
177
178 #[test]
179 fn parse_rejects_length_overrun() {
180 let err = DataBroadcastIdDescriptor::parse(&[TAG, 0x05, 0x00, 0x0B, 0xAA]).unwrap_err();
182 assert!(matches!(err, Error::BufferTooShort { .. }));
183 }
184
185 #[test]
186 fn serialize_round_trip() {
187 let d = DataBroadcastIdDescriptor {
188 data_broadcast_id: 0x0123,
189 id_selector: &[0xDE, 0xAD, 0xBE, 0xEF],
190 };
191 let mut buf = vec![0u8; d.serialized_len()];
192 d.serialize_into(&mut buf).unwrap();
193 let re = DataBroadcastIdDescriptor::parse(&buf).unwrap();
194 assert_eq!(d, re);
195 }
196
197 #[test]
198 fn serialize_rejects_too_small_buffer() {
199 let d = DataBroadcastIdDescriptor {
200 data_broadcast_id: 0x0001,
201 id_selector: &[0x01],
202 };
203 let mut tiny = [0u8; 2];
204 let err = d.serialize_into(&mut tiny).unwrap_err();
205 assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
206 }
207
208 #[test]
209 fn serialize_rejects_over_range_body() {
210 let sel = vec![0u8; 254];
212 let d = DataBroadcastIdDescriptor {
213 data_broadcast_id: 0x0001,
214 id_selector: &sel,
215 };
216 let mut buf = vec![0u8; d.serialized_len()];
217 let err = d.serialize_into(&mut buf).unwrap_err();
218 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
219 }
220
221 #[cfg(feature = "serde")]
222 #[test]
223 fn serde_serialize_is_stable() {
224 let d = DataBroadcastIdDescriptor {
225 data_broadcast_id: 0x000B,
226 id_selector: &[0x01, 0x02],
227 };
228 let json = serde_json::to_string(&d).unwrap();
229 assert!(json.contains("\"data_broadcast_id\""));
230 assert!(json.contains("\"id_selector\""));
231 assert!(json.contains("11"));
232 }
233}