1use crate::error::{Error, Result};
8use crate::text::{DvbText, LangCode};
9use crate::traits::Descriptor;
10use dvb_common::{Parse, Serialize};
11
12pub const TAG: u8 = 0x64;
14const HEADER_LEN: usize = 2;
15const ID_LEN: usize = 2;
16const COMPONENT_TAG_LEN: usize = 1;
17const SELECTOR_LEN_FIELD: usize = 1;
18const LANG_LEN: usize = 3;
19const TEXT_LEN_FIELD: usize = 1;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize))] #[cfg_attr(feature = "serde", serde(bound = ""))]
25pub struct DataBroadcastDescriptor<'a> {
26 pub data_broadcast_id: u16,
28 pub component_tag: u8,
30 #[cfg_attr(feature = "serde", serde(borrow))]
32 pub selector: &'a [u8],
33 pub language_code: LangCode,
35 pub text: DvbText<'a>,
37}
38
39impl<'a> Parse<'a> for DataBroadcastDescriptor<'a> {
40 type Error = crate::error::Error;
41 fn parse(bytes: &'a [u8]) -> Result<Self> {
42 let min_body = ID_LEN + COMPONENT_TAG_LEN + SELECTOR_LEN_FIELD + LANG_LEN + TEXT_LEN_FIELD;
43 if bytes.len() < HEADER_LEN {
44 return Err(Error::BufferTooShort {
45 need: HEADER_LEN,
46 have: bytes.len(),
47 what: "DataBroadcastDescriptor header",
48 });
49 }
50 if bytes[0] != TAG {
51 return Err(Error::InvalidDescriptor {
52 tag: bytes[0],
53 reason: "unexpected tag for data_broadcast_descriptor",
54 });
55 }
56 let length = bytes[1] as usize;
57 let end = HEADER_LEN + length;
58 if bytes.len() < end {
59 return Err(Error::BufferTooShort {
60 need: end,
61 have: bytes.len(),
62 what: "DataBroadcastDescriptor body",
63 });
64 }
65 if length < min_body {
66 return Err(Error::InvalidDescriptor {
67 tag: TAG,
68 reason: "data_broadcast_descriptor body shorter than minimum 8 bytes",
69 });
70 }
71 let mut pos = HEADER_LEN;
72 let data_broadcast_id = u16::from_be_bytes([bytes[pos], bytes[pos + 1]]);
73 pos += ID_LEN;
74 let component_tag = bytes[pos];
75 pos += COMPONENT_TAG_LEN;
76
77 let selector_length = bytes[pos] as usize;
78 pos += SELECTOR_LEN_FIELD;
79 let selector_end = pos + selector_length;
80 if selector_end + LANG_LEN + TEXT_LEN_FIELD > end {
82 return Err(Error::InvalidDescriptor {
83 tag: TAG,
84 reason: "selector_length runs past descriptor end",
85 });
86 }
87 let selector = &bytes[pos..selector_end];
88 pos = selector_end;
89
90 let language_code = LangCode([bytes[pos], bytes[pos + 1], bytes[pos + 2]]);
91 pos += LANG_LEN;
92
93 let text_length = bytes[pos] as usize;
94 pos += TEXT_LEN_FIELD;
95 let text_end = pos + text_length;
96 if text_end > end {
97 return Err(Error::InvalidDescriptor {
98 tag: TAG,
99 reason: "text_length runs past descriptor end",
100 });
101 }
102 let text = DvbText::new(&bytes[pos..text_end]);
103
104 Ok(Self {
105 data_broadcast_id,
106 component_tag,
107 selector,
108 language_code,
109 text,
110 })
111 }
112}
113
114impl Serialize for DataBroadcastDescriptor<'_> {
115 type Error = crate::error::Error;
116 fn serialized_len(&self) -> usize {
117 HEADER_LEN
118 + ID_LEN
119 + COMPONENT_TAG_LEN
120 + SELECTOR_LEN_FIELD
121 + self.selector.len()
122 + LANG_LEN
123 + TEXT_LEN_FIELD
124 + self.text.len()
125 }
126
127 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
128 if self.selector.len() > u8::MAX as usize {
129 return Err(Error::InvalidDescriptor {
130 tag: TAG,
131 reason: "selector exceeds 255 bytes (selector_length is 8-bit)",
132 });
133 }
134 if self.text.len() > u8::MAX as usize {
135 return Err(Error::InvalidDescriptor {
136 tag: TAG,
137 reason: "text exceeds 255 bytes (text_length is 8-bit)",
138 });
139 }
140 let len = self.serialized_len();
141 let body = len - HEADER_LEN;
142 if body > u8::MAX as usize {
143 return Err(Error::InvalidDescriptor {
144 tag: TAG,
145 reason: "data_broadcast_descriptor body exceeds 255 bytes",
146 });
147 }
148 if buf.len() < len {
149 return Err(Error::OutputBufferTooSmall {
150 need: len,
151 have: buf.len(),
152 });
153 }
154 buf[0] = TAG;
155 buf[1] = body as u8;
156 let mut pos = HEADER_LEN;
157 buf[pos..pos + ID_LEN].copy_from_slice(&self.data_broadcast_id.to_be_bytes());
158 pos += ID_LEN;
159 buf[pos] = self.component_tag;
160 pos += COMPONENT_TAG_LEN;
161 buf[pos] = self.selector.len() as u8;
162 pos += SELECTOR_LEN_FIELD;
163 buf[pos..pos + self.selector.len()].copy_from_slice(self.selector);
164 pos += self.selector.len();
165 buf[pos..pos + LANG_LEN].copy_from_slice(&self.language_code.0);
166 pos += LANG_LEN;
167 buf[pos] = self.text.len() as u8;
168 pos += TEXT_LEN_FIELD;
169 buf[pos..pos + self.text.len()].copy_from_slice(self.text.raw());
170 Ok(len)
171 }
172}
173
174impl<'a> Descriptor<'a> for DataBroadcastDescriptor<'a> {
175 const TAG: u8 = TAG;
176 fn descriptor_length(&self) -> u8 {
177 (self.serialized_len() - HEADER_LEN) as u8
178 }
179}
180
181impl<'a> crate::traits::DescriptorDef<'a> for DataBroadcastDescriptor<'a> {
182 const TAG: u8 = TAG;
183 const NAME: &'static str = "DATA_BROADCAST";
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 fn build(id: u16, ctag: u8, selector: &[u8], lang: [u8; 3], text: &[u8]) -> Vec<u8> {
191 let body = ID_LEN
192 + COMPONENT_TAG_LEN
193 + SELECTOR_LEN_FIELD
194 + selector.len()
195 + LANG_LEN
196 + TEXT_LEN_FIELD
197 + text.len();
198 let mut v = Vec::with_capacity(HEADER_LEN + body);
199 v.push(TAG);
200 v.push(body as u8);
201 v.extend_from_slice(&id.to_be_bytes());
202 v.push(ctag);
203 v.push(selector.len() as u8);
204 v.extend_from_slice(selector);
205 v.extend_from_slice(&lang);
206 v.push(text.len() as u8);
207 v.extend_from_slice(text);
208 v
209 }
210
211 #[test]
212 fn parse_extracts_all_fields() {
213 let bytes = build(0x000B, 0x12, &[0xAA, 0xBB], *b"eng", b"Hello");
214 let d = DataBroadcastDescriptor::parse(&bytes).unwrap();
215 assert_eq!(d.data_broadcast_id, 0x000B);
216 assert_eq!(d.component_tag, 0x12);
217 assert_eq!(d.selector, &[0xAA, 0xBB]);
218 assert_eq!(d.language_code, LangCode(*b"eng"));
219 assert_eq!(d.text.raw(), b"Hello");
220 }
221
222 #[test]
223 fn parse_accepts_empty_selector_and_text() {
224 let bytes = build(0x0001, 0x00, &[], *b"fra", b"");
225 let d = DataBroadcastDescriptor::parse(&bytes).unwrap();
226 assert!(d.selector.is_empty());
227 assert!(d.text.raw().is_empty());
228 assert_eq!(d.language_code, LangCode(*b"fra"));
229 }
230
231 #[test]
232 fn parse_rejects_wrong_tag() {
233 let mut bytes = build(0x0001, 0x00, &[], *b"eng", b"");
234 bytes[0] = 0x65;
235 let err = DataBroadcastDescriptor::parse(&bytes).unwrap_err();
236 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x65, .. }));
237 }
238
239 #[test]
240 fn parse_rejects_short_buffer() {
241 let err = DataBroadcastDescriptor::parse(&[TAG]).unwrap_err();
242 assert!(matches!(err, Error::BufferTooShort { .. }));
243 }
244
245 #[test]
246 fn parse_rejects_body_too_short() {
247 let err = DataBroadcastDescriptor::parse(&[TAG, 4, 0, 0, 0, 0]).unwrap_err();
249 assert!(matches!(err, Error::InvalidDescriptor { .. }));
250 }
251
252 #[test]
253 fn parse_rejects_selector_length_overrun() {
254 let bytes = [TAG, 8, 0x00, 0x0B, 0x12, 200, b'e', b'n', b'g', 0];
256 let err = DataBroadcastDescriptor::parse(&bytes).unwrap_err();
257 assert!(matches!(err, Error::InvalidDescriptor { .. }));
258 }
259
260 #[test]
261 fn parse_rejects_text_length_overrun() {
262 let bytes = [TAG, 8, 0x00, 0x0B, 0x12, 0, b'e', b'n', b'g', 5];
264 let err = DataBroadcastDescriptor::parse(&bytes).unwrap_err();
265 assert!(matches!(err, Error::InvalidDescriptor { .. }));
266 }
267
268 #[test]
269 fn serialize_round_trip() {
270 let bytes = build(0x0123, 0x45, &[0xDE, 0xAD], *b"deu", b"Daten");
271 let parsed = DataBroadcastDescriptor::parse(&bytes).unwrap();
272 let mut buf = vec![0u8; parsed.serialized_len()];
273 parsed.serialize_into(&mut buf).unwrap();
274 assert_eq!(buf, bytes);
275 let re = DataBroadcastDescriptor::parse(&buf).unwrap();
276 assert_eq!(parsed, re);
277 }
278
279 #[test]
280 fn serialize_rejects_too_small_buffer() {
281 let d = DataBroadcastDescriptor {
282 data_broadcast_id: 0x0001,
283 component_tag: 0x00,
284 selector: &[],
285 language_code: LangCode(*b"eng"),
286 text: DvbText::new(&[]),
287 };
288 let mut tiny = [0u8; 4];
289 let err = d.serialize_into(&mut tiny).unwrap_err();
290 assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
291 }
292
293 #[test]
294 fn serialize_rejects_over_range_selector() {
295 let sel = vec![0u8; 256];
296 let d = DataBroadcastDescriptor {
297 data_broadcast_id: 0x0001,
298 component_tag: 0x00,
299 selector: &sel,
300 language_code: LangCode(*b"eng"),
301 text: DvbText::new(&[]),
302 };
303 let mut buf = vec![0u8; d.serialized_len()];
304 let err = d.serialize_into(&mut buf).unwrap_err();
305 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
306 }
307
308 #[test]
309 fn serialize_rejects_over_range_body() {
310 let sel = vec![0u8; 250];
312 let txt = vec![0u8; 10];
313 let d = DataBroadcastDescriptor {
314 data_broadcast_id: 0x0001,
315 component_tag: 0x00,
316 selector: &sel,
317 language_code: LangCode(*b"eng"),
318 text: DvbText::new(&txt),
319 };
320 let mut buf = vec![0u8; d.serialized_len()];
321 let err = d.serialize_into(&mut buf).unwrap_err();
322 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
323 }
324
325 #[cfg(feature = "serde")]
326 #[test]
327 fn serde_serialize_is_stable() {
328 let d = DataBroadcastDescriptor {
333 data_broadcast_id: 0x000B,
334 component_tag: 0x09,
335 selector: &[0x01, 0x02],
336 language_code: LangCode(*b"eng"),
337 text: DvbText::new(b"Text"),
338 };
339 let json = serde_json::to_string(&d).unwrap();
340 assert_eq!(json, serde_json::to_string(&d.clone()).unwrap());
341 }
342}