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