1use crate::error::{Error, Result};
18use crate::traits::Descriptor;
19use dvb_common::{Parse, Serialize};
20
21pub const TAG: u8 = 0x57;
23const HEADER_LEN: usize = 2;
24const FIXED_LEN: usize = 3;
26
27const FOREIGN_AVAIL_MASK: u8 = 0x20; const CONNECTION_TYPE_MASK: u8 = 0x1F; const BYTE0_RESERVED: u8 = 0xC0; const BYTE1_RESERVED: u8 = 0x80; const BYTE2_RESERVED: u8 = 0x80; const MAX_COUNTRY_PREFIX: usize = 0x03; const MAX_INTL_AREA: usize = 0x07; const MAX_OPERATOR: usize = 0x03; const MAX_NATIONAL_AREA: usize = 0x07; const MAX_CORE_NUMBER: usize = 0x0F; #[derive(Debug, Clone, PartialEq, Eq)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize))]
43pub struct TelephoneDescriptor<'a> {
44 pub foreign_availability: bool,
46 pub connection_type: u8,
48 pub country_prefix: &'a [u8],
50 pub international_area_code: &'a [u8],
52 pub operator_code: &'a [u8],
54 pub national_area_code: &'a [u8],
56 pub core_number: &'a [u8],
58}
59
60impl<'a> Parse<'a> for TelephoneDescriptor<'a> {
61 type Error = crate::error::Error;
62 fn parse(bytes: &'a [u8]) -> Result<Self> {
63 if bytes.len() < HEADER_LEN {
64 return Err(Error::BufferTooShort {
65 need: HEADER_LEN,
66 have: bytes.len(),
67 what: "TelephoneDescriptor header",
68 });
69 }
70 if bytes[0] != TAG {
71 return Err(Error::InvalidDescriptor {
72 tag: bytes[0],
73 reason: "unexpected tag for telephone_descriptor",
74 });
75 }
76 let length = bytes[1] as usize;
77 if length < FIXED_LEN {
78 return Err(Error::InvalidDescriptor {
79 tag: TAG,
80 reason: "telephone_descriptor length too short for fixed fields",
81 });
82 }
83 let end = HEADER_LEN + length;
84 if bytes.len() < end {
85 return Err(Error::BufferTooShort {
86 need: end,
87 have: bytes.len(),
88 what: "TelephoneDescriptor body",
89 });
90 }
91 let body = &bytes[HEADER_LEN..end];
92 let foreign_availability = body[0] & FOREIGN_AVAIL_MASK != 0;
94 let connection_type = body[0] & CONNECTION_TYPE_MASK;
95 let country_prefix_length = ((body[1] >> 5) & 0x03) as usize;
96 let international_area_code_length = ((body[1] >> 2) & 0x07) as usize;
97 let operator_code_length = (body[1] & 0x03) as usize;
98 let national_area_code_length = ((body[2] >> 4) & 0x07) as usize;
99 let core_number_length = (body[2] & 0x0F) as usize;
100 let total_chars = country_prefix_length
101 + international_area_code_length
102 + operator_code_length
103 + national_area_code_length
104 + core_number_length;
105 if FIXED_LEN + total_chars > body.len() {
106 return Err(Error::InvalidDescriptor {
107 tag: TAG,
108 reason: "sum of telephone char-field lengths exceeds descriptor body",
109 });
110 }
111 let mut pos = FIXED_LEN;
112 let mut take = |n: usize| {
113 let s = &body[pos..pos + n];
114 pos += n;
115 s
116 };
117 let country_prefix = take(country_prefix_length);
118 let international_area_code = take(international_area_code_length);
119 let operator_code = take(operator_code_length);
120 let national_area_code = take(national_area_code_length);
121 let core_number = take(core_number_length);
122 Ok(Self {
123 foreign_availability,
124 connection_type,
125 country_prefix,
126 international_area_code,
127 operator_code,
128 national_area_code,
129 core_number,
130 })
131 }
132}
133
134impl Serialize for TelephoneDescriptor<'_> {
135 type Error = crate::error::Error;
136 fn serialized_len(&self) -> usize {
137 HEADER_LEN
138 + FIXED_LEN
139 + self.country_prefix.len()
140 + self.international_area_code.len()
141 + self.operator_code.len()
142 + self.national_area_code.len()
143 + self.core_number.len()
144 }
145
146 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
147 let len = self.serialized_len();
148 if buf.len() < len {
149 return Err(Error::OutputBufferTooSmall {
150 need: len,
151 have: buf.len(),
152 });
153 }
154 if self.country_prefix.len() > MAX_COUNTRY_PREFIX
156 || self.international_area_code.len() > MAX_INTL_AREA
157 || self.operator_code.len() > MAX_OPERATOR
158 || self.national_area_code.len() > MAX_NATIONAL_AREA
159 || self.core_number.len() > MAX_CORE_NUMBER
160 {
161 return Err(Error::InvalidDescriptor {
162 tag: TAG,
163 reason: "telephone char-field exceeds its length-field capacity",
164 });
165 }
166 buf[0] = TAG;
167 buf[1] = (len - HEADER_LEN) as u8;
168 buf[2] = BYTE0_RESERVED
170 | if self.foreign_availability {
171 FOREIGN_AVAIL_MASK
172 } else {
173 0
174 }
175 | (self.connection_type & CONNECTION_TYPE_MASK);
176 buf[3] = BYTE1_RESERVED
178 | ((self.country_prefix.len() as u8 & 0x03) << 5)
179 | ((self.international_area_code.len() as u8 & 0x07) << 2)
180 | (self.operator_code.len() as u8 & 0x03);
181 buf[4] = BYTE2_RESERVED
183 | ((self.national_area_code.len() as u8 & 0x07) << 4)
184 | (self.core_number.len() as u8 & 0x0F);
185 let mut pos = HEADER_LEN + FIXED_LEN;
186 for field in [
187 self.country_prefix,
188 self.international_area_code,
189 self.operator_code,
190 self.national_area_code,
191 self.core_number,
192 ] {
193 buf[pos..pos + field.len()].copy_from_slice(field);
194 pos += field.len();
195 }
196 Ok(len)
197 }
198}
199
200impl<'a> Descriptor<'a> for TelephoneDescriptor<'a> {
201 const TAG: u8 = TAG;
202 fn descriptor_length(&self) -> u8 {
203 (self.serialized_len() - HEADER_LEN) as u8
204 }
205}
206
207impl<'a> crate::traits::DescriptorDef<'a> for TelephoneDescriptor<'a> {
208 const TAG: u8 = TAG;
209 const NAME: &'static str = "TELEPHONE";
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 fn sample() -> TelephoneDescriptor<'static> {
217 TelephoneDescriptor {
218 foreign_availability: true,
219 connection_type: 0x05,
220 country_prefix: b"44",
221 international_area_code: b"171",
222 operator_code: b"01",
223 national_area_code: b"207",
224 core_number: b"123456",
225 }
226 }
227
228 #[test]
229 fn parse_extracts_all_fields() {
230 let d = sample();
231 let mut buf = vec![0u8; d.serialized_len()];
232 d.serialize_into(&mut buf).unwrap();
233 let p = TelephoneDescriptor::parse(&buf).unwrap();
234 assert!(p.foreign_availability);
235 assert_eq!(p.connection_type, 0x05);
236 assert_eq!(p.country_prefix, b"44");
237 assert_eq!(p.international_area_code, b"171");
238 assert_eq!(p.operator_code, b"01");
239 assert_eq!(p.national_area_code, b"207");
240 assert_eq!(p.core_number, b"123456");
241 }
242
243 #[test]
244 fn parse_minimal_no_chars() {
245 let bytes = [TAG, 3, 0x20, 0x00, 0x00];
247 let d = TelephoneDescriptor::parse(&bytes).unwrap();
248 assert!(d.foreign_availability);
249 assert!(d.country_prefix.is_empty());
250 assert!(d.core_number.is_empty());
251 }
252
253 #[test]
254 fn parse_rejects_wrong_tag() {
255 assert!(matches!(
256 TelephoneDescriptor::parse(&[0x58, 3, 0, 0, 0]).unwrap_err(),
257 Error::InvalidDescriptor { tag: 0x58, .. }
258 ));
259 }
260
261 #[test]
262 fn parse_rejects_short_buffer() {
263 let bytes = [TAG, 3, 0x20, 0x00];
265 assert!(matches!(
266 TelephoneDescriptor::parse(&bytes).unwrap_err(),
267 Error::BufferTooShort { .. }
268 ));
269 }
270
271 #[test]
272 fn parse_rejects_length_below_fixed() {
273 let bytes = [TAG, 2, 0x20, 0x00];
274 assert!(matches!(
275 TelephoneDescriptor::parse(&bytes).unwrap_err(),
276 Error::InvalidDescriptor { tag: TAG, .. }
277 ));
278 }
279
280 #[test]
281 fn parse_rejects_char_lengths_overrun() {
282 let bytes = [TAG, 3, 0x20, 0x60, 0x00];
285 assert!(matches!(
286 TelephoneDescriptor::parse(&bytes).unwrap_err(),
287 Error::InvalidDescriptor { tag: TAG, .. }
288 ));
289 }
290
291 #[test]
292 fn serialize_round_trip() {
293 let d = sample();
294 let mut buf = vec![0u8; d.serialized_len()];
295 d.serialize_into(&mut buf).unwrap();
296 assert_eq!(TelephoneDescriptor::parse(&buf).unwrap(), d);
297 }
298
299 #[test]
300 fn serialize_emits_reserved_ones() {
301 let d = TelephoneDescriptor {
302 foreign_availability: false,
303 connection_type: 0,
304 country_prefix: b"",
305 international_area_code: b"",
306 operator_code: b"",
307 national_area_code: b"",
308 core_number: b"",
309 };
310 let mut buf = vec![0u8; d.serialized_len()];
311 d.serialize_into(&mut buf).unwrap();
312 assert_eq!(buf[2] & BYTE0_RESERVED, BYTE0_RESERVED);
314 assert_eq!(buf[3] & BYTE1_RESERVED, BYTE1_RESERVED);
315 assert_eq!(buf[4] & BYTE2_RESERVED, BYTE2_RESERVED);
316 }
317
318 #[test]
319 fn serialize_rejects_over_range_field() {
320 let d = TelephoneDescriptor {
322 foreign_availability: false,
323 connection_type: 0,
324 country_prefix: b"",
325 international_area_code: b"",
326 operator_code: b"1234",
327 national_area_code: b"",
328 core_number: b"",
329 };
330 let mut buf = vec![0u8; d.serialized_len()];
331 assert!(matches!(
332 d.serialize_into(&mut buf).unwrap_err(),
333 Error::InvalidDescriptor { tag: TAG, .. }
334 ));
335 }
336
337 #[cfg(feature = "serde")]
338 #[test]
339 fn serde_serialize_stable() {
340 let d = sample();
345 let json = serde_json::to_string(&d).unwrap();
346 assert!(json.contains("connection_type"));
347 assert!(json.contains("foreign_availability"));
348 assert_eq!(json, serde_json::to_string(&sample()).unwrap());
349 }
350}