1use crate::error::{Error, Result};
8use crate::text::{DvbText, LangCode};
9use crate::traits::Descriptor;
10use dvb_common::{Parse, Serialize};
11
12pub const TAG: u8 = 0x5D;
14const HEADER_LEN: usize = 2;
15const LANG_LEN: usize = 3;
16const LEN_FIELD: usize = 1;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct ServiceNameEntry<'a> {
22 pub language_code: LangCode,
24 pub service_provider_name: DvbText<'a>,
26 pub service_name: DvbText<'a>,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct MultilingualServiceNameDescriptor<'a> {
34 pub entries: Vec<ServiceNameEntry<'a>>,
36}
37
38impl<'a> Parse<'a> for MultilingualServiceNameDescriptor<'a> {
39 type Error = crate::error::Error;
40 fn parse(bytes: &'a [u8]) -> Result<Self> {
41 if bytes.len() < HEADER_LEN {
42 return Err(Error::BufferTooShort {
43 need: HEADER_LEN,
44 have: bytes.len(),
45 what: "MultilingualServiceNameDescriptor header",
46 });
47 }
48 if bytes[0] != TAG {
49 return Err(Error::InvalidDescriptor {
50 tag: bytes[0],
51 reason: "unexpected tag for multilingual_service_name_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: "MultilingualServiceNameDescriptor body",
61 });
62 }
63 let mut entries = Vec::new();
64 let mut pos = HEADER_LEN;
65 while pos < end {
66 if pos + LANG_LEN + LEN_FIELD > end {
68 return Err(Error::InvalidDescriptor {
69 tag: TAG,
70 reason: "entry header runs past descriptor end",
71 });
72 }
73 let language_code = LangCode([bytes[pos], bytes[pos + 1], bytes[pos + 2]]);
74 let provider_len_pos = pos + LANG_LEN;
75 let provider_len = bytes[provider_len_pos] as usize;
76 let provider_start = provider_len_pos + LEN_FIELD;
77 let provider_end = provider_start + provider_len;
78 if provider_end + LEN_FIELD > end {
80 return Err(Error::InvalidDescriptor {
81 tag: TAG,
82 reason: "service_provider_name_length runs past descriptor end",
83 });
84 }
85 let service_provider_name = DvbText::new(&bytes[provider_start..provider_end]);
86 let service_len = bytes[provider_end] as usize;
87 let service_start = provider_end + LEN_FIELD;
88 let service_end = service_start + service_len;
89 if service_end > end {
90 return Err(Error::InvalidDescriptor {
91 tag: TAG,
92 reason: "service_name_length runs past descriptor end",
93 });
94 }
95 let service_name = DvbText::new(&bytes[service_start..service_end]);
96 entries.push(ServiceNameEntry {
97 language_code,
98 service_provider_name,
99 service_name,
100 });
101 pos = service_end;
102 }
103 Ok(Self { entries })
104 }
105}
106
107impl Serialize for MultilingualServiceNameDescriptor<'_> {
108 type Error = crate::error::Error;
109 fn serialized_len(&self) -> usize {
110 HEADER_LEN
111 + self
112 .entries
113 .iter()
114 .map(|e| {
115 LANG_LEN
116 + LEN_FIELD
117 + e.service_provider_name.len()
118 + LEN_FIELD
119 + e.service_name.len()
120 })
121 .sum::<usize>()
122 }
123
124 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
125 for e in &self.entries {
126 if e.service_provider_name.len() > u8::MAX as usize {
127 return Err(Error::InvalidDescriptor {
128 tag: TAG,
129 reason: "service_provider_name exceeds 255 bytes (length is 8-bit)",
130 });
131 }
132 if e.service_name.len() > u8::MAX as usize {
133 return Err(Error::InvalidDescriptor {
134 tag: TAG,
135 reason: "service_name exceeds 255 bytes (length is 8-bit)",
136 });
137 }
138 }
139 let len = self.serialized_len();
140 let body = len - HEADER_LEN;
141 if body > u8::MAX as usize {
142 return Err(Error::InvalidDescriptor {
143 tag: TAG,
144 reason: "multilingual_service_name_descriptor body exceeds 255 bytes",
145 });
146 }
147 if buf.len() < len {
148 return Err(Error::OutputBufferTooSmall {
149 need: len,
150 have: buf.len(),
151 });
152 }
153 buf[0] = TAG;
154 buf[1] = body as u8;
155 let mut pos = HEADER_LEN;
156 for e in &self.entries {
157 buf[pos..pos + LANG_LEN].copy_from_slice(&e.language_code.0);
158 pos += LANG_LEN;
159 buf[pos] = e.service_provider_name.len() as u8;
160 pos += LEN_FIELD;
161 buf[pos..pos + e.service_provider_name.len()]
162 .copy_from_slice(e.service_provider_name.raw());
163 pos += e.service_provider_name.len();
164 buf[pos] = e.service_name.len() as u8;
165 pos += LEN_FIELD;
166 buf[pos..pos + e.service_name.len()].copy_from_slice(e.service_name.raw());
167 pos += e.service_name.len();
168 }
169 Ok(len)
170 }
171}
172
173impl<'a> Descriptor<'a> for MultilingualServiceNameDescriptor<'a> {
174 const TAG: u8 = TAG;
175 fn descriptor_length(&self) -> u8 {
176 (self.serialized_len() - HEADER_LEN) as u8
177 }
178}
179
180impl<'a> crate::traits::DescriptorDef<'a> for MultilingualServiceNameDescriptor<'a> {
181 const TAG: u8 = TAG;
182 const NAME: &'static str = "MULTILINGUAL_SERVICE_NAME";
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 fn build(entries: &[([u8; 3], &[u8], &[u8])]) -> Vec<u8> {
190 let body: usize = entries
191 .iter()
192 .map(|(_, p, s)| LANG_LEN + 1 + p.len() + 1 + s.len())
193 .sum();
194 let mut v = Vec::with_capacity(HEADER_LEN + body);
195 v.push(TAG);
196 v.push(body as u8);
197 for (lang, provider, service) in entries {
198 v.extend_from_slice(lang);
199 v.push(provider.len() as u8);
200 v.extend_from_slice(provider);
201 v.push(service.len() as u8);
202 v.extend_from_slice(service);
203 }
204 v
205 }
206
207 #[test]
208 fn parse_single_entry() {
209 let bytes = build(&[(*b"eng", b"BBC", b"One")]);
210 let d = MultilingualServiceNameDescriptor::parse(&bytes).unwrap();
211 assert_eq!(d.entries.len(), 1);
212 assert_eq!(d.entries[0].language_code, LangCode(*b"eng"));
213 assert_eq!(d.entries[0].service_provider_name.raw(), b"BBC");
214 assert_eq!(d.entries[0].service_name.raw(), b"One");
215 }
216
217 #[test]
218 fn parse_multiple_entries() {
219 let bytes = build(&[(*b"eng", b"Prov", b"Svc"), (*b"fra", b"Fourn", b"Chaine")]);
220 let d = MultilingualServiceNameDescriptor::parse(&bytes).unwrap();
221 assert_eq!(d.entries.len(), 2);
222 assert_eq!(d.entries[1].service_name.raw(), b"Chaine");
223 }
224
225 #[test]
226 fn parse_empty_names_valid() {
227 let bytes = build(&[(*b"deu", b"", b"")]);
228 let d = MultilingualServiceNameDescriptor::parse(&bytes).unwrap();
229 assert!(d.entries[0].service_provider_name.raw().is_empty());
230 assert!(d.entries[0].service_name.raw().is_empty());
231 }
232
233 #[test]
234 fn parse_rejects_wrong_tag() {
235 let err = MultilingualServiceNameDescriptor::parse(&[0x5E, 0]).unwrap_err();
236 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x5E, .. }));
237 }
238
239 #[test]
240 fn parse_rejects_short_buffer() {
241 let err = MultilingualServiceNameDescriptor::parse(&[TAG]).unwrap_err();
242 assert!(matches!(err, Error::BufferTooShort { .. }));
243 }
244
245 #[test]
246 fn parse_rejects_provider_length_overrun() {
247 let bytes = [TAG, 5, b'e', b'n', b'g', 100, 0];
249 let err = MultilingualServiceNameDescriptor::parse(&bytes).unwrap_err();
250 assert!(matches!(err, Error::InvalidDescriptor { .. }));
251 }
252
253 #[test]
254 fn parse_rejects_service_length_overrun() {
255 let bytes = [TAG, 5, b'e', b'n', b'g', 0, 100];
257 let err = MultilingualServiceNameDescriptor::parse(&bytes).unwrap_err();
258 assert!(matches!(err, Error::InvalidDescriptor { .. }));
259 }
260
261 #[test]
262 fn empty_descriptor_valid() {
263 let d = MultilingualServiceNameDescriptor::parse(&[TAG, 0]).unwrap();
264 assert_eq!(d.entries.len(), 0);
265 }
266
267 #[test]
268 fn serialize_round_trip() {
269 let bytes = build(&[
270 (*b"eng", b"Provider", b"Channel"),
271 (*b"deu", b"Anbieter", b"Sender"),
272 ]);
273 let parsed = MultilingualServiceNameDescriptor::parse(&bytes).unwrap();
274 let mut buf = vec![0u8; parsed.serialized_len()];
275 parsed.serialize_into(&mut buf).unwrap();
276 assert_eq!(buf, bytes);
277 let re = MultilingualServiceNameDescriptor::parse(&buf).unwrap();
278 assert_eq!(parsed, re);
279 }
280
281 #[test]
282 fn serialize_rejects_too_small_buffer() {
283 let d = MultilingualServiceNameDescriptor {
284 entries: vec![ServiceNameEntry {
285 language_code: LangCode(*b"eng"),
286 service_provider_name: DvbText::new(b"P"),
287 service_name: DvbText::new(b"S"),
288 }],
289 };
290 let mut tiny = [0u8; 3];
291 let err = d.serialize_into(&mut tiny).unwrap_err();
292 assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
293 }
294
295 #[test]
296 fn serialize_rejects_over_range_provider_name() {
297 let provider = vec![0u8; 256];
298 let d = MultilingualServiceNameDescriptor {
299 entries: vec![ServiceNameEntry {
300 language_code: LangCode(*b"eng"),
301 service_provider_name: DvbText::new(&provider),
302 service_name: DvbText::new(b"S"),
303 }],
304 };
305 let mut buf = vec![0u8; d.serialized_len()];
306 let err = d.serialize_into(&mut buf).unwrap_err();
307 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
308 }
309
310 #[cfg(feature = "serde")]
311 #[test]
312 fn serde_serialize_is_stable() {
313 let d = MultilingualServiceNameDescriptor {
317 entries: vec![ServiceNameEntry {
318 language_code: LangCode(*b"eng"),
319 service_provider_name: DvbText::new(b"BBC"),
320 service_name: DvbText::new(b"One"),
321 }],
322 };
323 let json = serde_json::to_string(&d).unwrap();
324 assert_eq!(json, serde_json::to_string(&d.clone()).unwrap());
325 }
326}