dvb_si/descriptors/
teletext.rs1use crate::error::{Error, Result};
7use crate::traits::Descriptor;
8use dvb_common::{Parse, Serialize};
9
10pub const TAG: u8 = 0x56;
12const HEADER_LEN: usize = 2;
13const ENTRY_LEN: usize = 5;
14const LANG_LEN: usize = 3;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct TeletextEntry {
20 pub language_code: [u8; 3],
22 pub teletext_type: u8,
24 pub magazine_number: u8,
26 pub page_number: u8,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33pub struct TeletextDescriptor {
34 pub entries: Vec<TeletextEntry>,
36}
37
38impl<'a> Parse<'a> for TeletextDescriptor {
39 type Error = crate::error::Error;
40 fn parse(bytes: &'a [u8]) -> Result<Self> {
41 if bytes.len() < HEADER_LEN {
42 return Err(Error::BufferTooShort {
43 need: HEADER_LEN,
44 have: bytes.len(),
45 what: "TeletextDescriptor header",
46 });
47 }
48 if bytes[0] != TAG {
49 return Err(Error::InvalidDescriptor {
50 tag: bytes[0],
51 reason: "unexpected tag for teletext_descriptor",
52 });
53 }
54 let length = bytes[1] as usize;
55 if bytes.len() < HEADER_LEN + length {
56 return Err(Error::BufferTooShort {
57 need: HEADER_LEN + length,
58 have: bytes.len(),
59 what: "TeletextDescriptor body",
60 });
61 }
62 if length % ENTRY_LEN != 0 {
63 return Err(Error::InvalidDescriptor {
64 tag: TAG,
65 reason: "teletext_descriptor length must be a multiple of 5",
66 });
67 }
68 let body = &bytes[HEADER_LEN..HEADER_LEN + length];
69 let mut entries = Vec::with_capacity(length / ENTRY_LEN);
70 for chunk in body.chunks_exact(ENTRY_LEN) {
71 let language_code = [chunk[0], chunk[1], chunk[2]];
72 let type_and_mag = chunk[LANG_LEN];
73 let teletext_type = (type_and_mag >> 3) & 0x1F;
74 let magazine_number = type_and_mag & 0x07;
75 let page_number = chunk[LANG_LEN + 1];
76 entries.push(TeletextEntry {
77 language_code,
78 teletext_type,
79 magazine_number,
80 page_number,
81 });
82 }
83 Ok(Self { entries })
84 }
85}
86
87impl Serialize for TeletextDescriptor {
88 type Error = crate::error::Error;
89 fn serialized_len(&self) -> usize {
90 HEADER_LEN + self.entries.len() * ENTRY_LEN
91 }
92
93 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
94 let len = self.serialized_len();
95 if buf.len() < len {
96 return Err(Error::OutputBufferTooSmall {
97 need: len,
98 have: buf.len(),
99 });
100 }
101 buf[0] = TAG;
102 buf[1] = (self.entries.len() * ENTRY_LEN) as u8;
103 let mut pos = HEADER_LEN;
104 for e in &self.entries {
105 buf[pos..pos + LANG_LEN].copy_from_slice(&e.language_code);
106 buf[pos + LANG_LEN] = ((e.teletext_type & 0x1F) << 3) | (e.magazine_number & 0x07);
107 buf[pos + LANG_LEN + 1] = e.page_number;
108 pos += ENTRY_LEN;
109 }
110 Ok(len)
111 }
112}
113
114impl<'a> Descriptor<'a> for TeletextDescriptor {
115 const TAG: u8 = TAG;
116 fn descriptor_length(&self) -> u8 {
117 (self.entries.len() * ENTRY_LEN) as u8
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn parse_single_entry() {
127 let bytes = [TAG, 5, b'e', b'n', b'g', (1 << 3) | 2, 0x10];
129 let d = TeletextDescriptor::parse(&bytes).unwrap();
130 assert_eq!(d.entries.len(), 1);
131 assert_eq!(&d.entries[0].language_code, b"eng");
132 assert_eq!(d.entries[0].teletext_type, 1);
133 assert_eq!(d.entries[0].magazine_number, 2);
134 assert_eq!(d.entries[0].page_number, 0x10);
135 }
136
137 #[test]
138 fn parse_multiple_entries() {
139 let bytes = [
140 TAG,
141 10,
142 b'e',
143 b'n',
144 b'g',
145 (1 << 3) | 1,
146 0x10,
147 b'f',
148 b'r',
149 b'a',
150 (2 << 3) | 1,
151 0x20,
152 ];
153 let d = TeletextDescriptor::parse(&bytes).unwrap();
154 assert_eq!(d.entries.len(), 2);
155 assert_eq!(d.entries[1].teletext_type, 2);
156 }
157
158 #[test]
159 fn parse_rejects_wrong_tag() {
160 assert!(matches!(
161 TeletextDescriptor::parse(&[0x57, 0]).unwrap_err(),
162 Error::InvalidDescriptor { tag: 0x57, .. }
163 ));
164 }
165
166 #[test]
167 fn parse_rejects_length_not_multiple_of_5() {
168 let bytes = [TAG, 4, 0, 0, 0, 0];
169 assert!(matches!(
170 TeletextDescriptor::parse(&bytes).unwrap_err(),
171 Error::InvalidDescriptor { .. }
172 ));
173 }
174
175 #[test]
176 fn serialize_round_trip() {
177 let d = TeletextDescriptor {
178 entries: vec![TeletextEntry {
179 language_code: *b"fra",
180 teletext_type: 2,
181 magazine_number: 8 & 0x07,
182 page_number: 0x88,
183 }],
184 };
185 let mut buf = vec![0u8; d.serialized_len()];
186 d.serialize_into(&mut buf).unwrap();
187 assert_eq!(TeletextDescriptor::parse(&buf).unwrap(), d);
188 }
189
190 #[test]
191 fn empty_descriptor_valid() {
192 let bytes = [TAG, 0];
193 let d = TeletextDescriptor::parse(&bytes).unwrap();
194 assert_eq!(d.entries.len(), 0);
195 }
196}