dvb_si/descriptors/
multilingual_network_name.rs1use super::descriptor_body;
7use crate::error::{Error, Result};
8use crate::text::{DvbText, LangCode};
9use alloc::vec::Vec;
10use dvb_common::{Parse, Serialize};
11
12pub const TAG: u8 = 0x5B;
14const HEADER_LEN: usize = 2;
15const LANG_LEN: usize = 3;
16const NAME_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 NetworkNameEntry<'a> {
23 pub language_code: LangCode,
25 pub network_name: DvbText<'a>,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize))]
32#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
33pub struct MultilingualNetworkNameDescriptor<'a> {
34 pub entries: Vec<NetworkNameEntry<'a>>,
36}
37
38impl<'a> Parse<'a> for MultilingualNetworkNameDescriptor<'a> {
39 type Error = crate::error::Error;
40 fn parse(bytes: &'a [u8]) -> Result<Self> {
41 let body = descriptor_body(
42 bytes,
43 TAG,
44 "MultilingualNetworkNameDescriptor",
45 "unexpected tag for multilingual_network_name_descriptor",
46 )?;
47 let mut entries = Vec::new();
48 let mut pos = 0;
49 while pos < body.len() {
50 if pos + LANG_LEN + NAME_LEN_FIELD > body.len() {
51 return Err(Error::InvalidDescriptor {
52 tag: TAG,
53 reason: "entry header runs past descriptor end",
54 });
55 }
56 let language_code = LangCode([body[pos], body[pos + 1], body[pos + 2]]);
57 let name_len = body[pos + LANG_LEN] as usize;
58 let name_start = pos + LANG_LEN + NAME_LEN_FIELD;
59 let name_end = name_start + name_len;
60 if name_end > body.len() {
61 return Err(Error::InvalidDescriptor {
62 tag: TAG,
63 reason: "name_length runs past descriptor end",
64 });
65 }
66 entries.push(NetworkNameEntry {
67 language_code,
68 network_name: DvbText::new(&body[name_start..name_end]),
69 });
70 pos = name_end;
71 }
72 Ok(Self { entries })
73 }
74}
75
76impl Serialize for MultilingualNetworkNameDescriptor<'_> {
77 type Error = crate::error::Error;
78 fn serialized_len(&self) -> usize {
79 HEADER_LEN
80 + self
81 .entries
82 .iter()
83 .map(|e| LANG_LEN + NAME_LEN_FIELD + e.network_name.len())
84 .sum::<usize>()
85 }
86
87 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
88 for e in &self.entries {
89 if e.network_name.len() > u8::MAX as usize {
90 return Err(Error::InvalidDescriptor {
91 tag: TAG,
92 reason: "network_name exceeds 255 bytes (name_length is 8-bit)",
93 });
94 }
95 }
96 let len = self.serialized_len();
97 let body = len - HEADER_LEN;
98 if body > u8::MAX as usize {
99 return Err(Error::InvalidDescriptor {
100 tag: TAG,
101 reason: "multilingual_network_name_descriptor body exceeds 255 bytes",
102 });
103 }
104 if buf.len() < len {
105 return Err(Error::OutputBufferTooSmall {
106 need: len,
107 have: buf.len(),
108 });
109 }
110 buf[0] = TAG;
111 buf[1] = body as u8;
112 let mut pos = HEADER_LEN;
113 for e in &self.entries {
114 buf[pos..pos + LANG_LEN].copy_from_slice(&e.language_code.0);
115 buf[pos + LANG_LEN] = e.network_name.len() as u8;
116 let name_start = pos + LANG_LEN + NAME_LEN_FIELD;
117 buf[name_start..name_start + e.network_name.len()]
118 .copy_from_slice(e.network_name.raw());
119 pos = name_start + e.network_name.len();
120 }
121 Ok(len)
122 }
123}
124impl<'a> crate::traits::DescriptorDef<'a> for MultilingualNetworkNameDescriptor<'a> {
125 const TAG: u8 = TAG;
126 const NAME: &'static str = "MULTILINGUAL_NETWORK_NAME";
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 fn build(entries: &[([u8; 3], &[u8])]) -> Vec<u8> {
134 let body: usize = entries.iter().map(|(_, n)| LANG_LEN + 1 + n.len()).sum();
135 let mut v = Vec::with_capacity(HEADER_LEN + body);
136 v.push(TAG);
137 v.push(body as u8);
138 for (lang, name) in entries {
139 v.extend_from_slice(lang);
140 v.push(name.len() as u8);
141 v.extend_from_slice(name);
142 }
143 v
144 }
145
146 #[test]
147 fn parse_single_entry() {
148 let bytes = build(&[(*b"eng", b"BBC")]);
149 let d = MultilingualNetworkNameDescriptor::parse(&bytes).unwrap();
150 assert_eq!(d.entries.len(), 1);
151 assert_eq!(d.entries[0].language_code, LangCode(*b"eng"));
152 assert_eq!(d.entries[0].network_name.raw(), b"BBC");
153 }
154
155 #[test]
156 fn parse_multiple_entries() {
157 let bytes = build(&[(*b"eng", b"Net"), (*b"fra", b"Reseau")]);
158 let d = MultilingualNetworkNameDescriptor::parse(&bytes).unwrap();
159 assert_eq!(d.entries.len(), 2);
160 assert_eq!(d.entries[1].network_name.raw(), b"Reseau");
161 }
162
163 #[test]
164 fn parse_rejects_wrong_tag() {
165 let err = MultilingualNetworkNameDescriptor::parse(&[0x5C, 0]).unwrap_err();
166 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x5C, .. }));
167 }
168
169 #[test]
170 fn parse_rejects_short_buffer() {
171 let err = MultilingualNetworkNameDescriptor::parse(&[TAG]).unwrap_err();
172 assert!(matches!(err, Error::BufferTooShort { .. }));
173 }
174
175 #[test]
176 fn parse_rejects_name_length_overrun() {
177 let bytes = [TAG, 5, b'e', b'n', b'g', 100, 0];
179 let err = MultilingualNetworkNameDescriptor::parse(&bytes).unwrap_err();
180 assert!(matches!(err, Error::InvalidDescriptor { .. }));
181 }
182
183 #[test]
184 fn parse_rejects_truncated_entry_header() {
185 let bytes = [TAG, 2, b'e', b'n'];
187 let err = MultilingualNetworkNameDescriptor::parse(&bytes).unwrap_err();
188 assert!(matches!(err, Error::InvalidDescriptor { .. }));
189 }
190
191 #[test]
192 fn empty_descriptor_valid() {
193 let d = MultilingualNetworkNameDescriptor::parse(&[TAG, 0]).unwrap();
194 assert_eq!(d.entries.len(), 0);
195 }
196
197 #[test]
198 fn serialize_round_trip() {
199 let bytes = build(&[(*b"eng", b"Network"), (*b"deu", b"Netz")]);
200 let parsed = MultilingualNetworkNameDescriptor::parse(&bytes).unwrap();
201 let mut buf = vec![0u8; parsed.serialized_len()];
202 parsed.serialize_into(&mut buf).unwrap();
203 assert_eq!(buf, bytes);
204 let re = MultilingualNetworkNameDescriptor::parse(&buf).unwrap();
205 assert_eq!(parsed, re);
206 }
207
208 #[test]
209 fn serialize_rejects_too_small_buffer() {
210 let d = MultilingualNetworkNameDescriptor {
211 entries: vec![NetworkNameEntry {
212 language_code: LangCode(*b"eng"),
213 network_name: DvbText::new(b"X"),
214 }],
215 };
216 let mut tiny = [0u8; 3];
217 let err = d.serialize_into(&mut tiny).unwrap_err();
218 assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
219 }
220
221 #[test]
222 fn serialize_rejects_over_range_name() {
223 let name = vec![0u8; 256];
224 let d = MultilingualNetworkNameDescriptor {
225 entries: vec![NetworkNameEntry {
226 language_code: LangCode(*b"eng"),
227 network_name: DvbText::new(&name),
228 }],
229 };
230 let mut buf = vec![0u8; d.serialized_len()];
231 let err = d.serialize_into(&mut buf).unwrap_err();
232 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
233 }
234
235 #[cfg(feature = "serde")]
236 #[test]
237 fn serde_serialize_is_stable() {
238 let d = MultilingualNetworkNameDescriptor {
239 entries: vec![NetworkNameEntry {
240 language_code: LangCode(*b"eng"),
241 network_name: DvbText::new(b"BBC"),
242 }],
243 };
244 let json = serde_json::to_string(&d).unwrap();
245 assert!(json.contains("\"language_code\""));
246 assert!(json.contains("\"eng\""));
247 assert!(json.contains("\"BBC\""));
248 }
249}