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