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