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