1use crate::ParserError;
8use crate::WriterError;
9
10#[derive(Debug, PartialEq, Eq, Default, Clone)]
12pub struct ServiceInfo {
13 start: bool,
14 change: bool,
15 complete: bool,
16 services: Vec<ServiceEntry>,
17}
18
19impl ServiceInfo {
20 pub fn parse(data: &[u8]) -> Result<Self, ParserError> {
22 if data.len() < 2 {
23 return Err(ParserError::LengthMismatch {
24 expected: 2,
25 actual: data.len(),
26 });
27 }
28 if data[0] != 0x73 {
29 return Err(ParserError::WrongMagic);
30 }
31 if data[1] & 0x80 != 0x80 {
32 return Err(ParserError::InvalidFixedBits);
33 }
34 let svc_count = (data[1] & 0xf) as usize;
35 let expected = svc_count * 7 + 2;
36 if data.len() != expected {
37 return Err(ParserError::LengthMismatch {
38 expected,
39 actual: data.len(),
40 });
41 }
42 let start = data[1] & 0x40 > 0;
43 let change = data[1] & 0x20 > 0;
44 let complete = data[1] & 0x10 > 0;
45 let mut ret = Self {
46 start,
47 change,
48 complete,
49 services: vec![],
50 };
51 let mut data = &data[2..];
52 for _ in 0..svc_count {
53 trace!("parsing entry {:x?}", &data[..7]);
54 if data[0] & 0x80 != 0x80 {
55 return Err(ParserError::InvalidFixedBits);
56 }
57 let service_large = data[0] & 0x40 > 0;
58 let service_no = if service_large {
59 if data[0] & 0x20 != 0x20 {
60 return Err(ParserError::InvalidFixedBits);
61 }
62 data[0] & 0x1f
63 } else {
64 data[0] & 0x3f
65 };
66 let service =
67 ServiceEntry::parse([data[1], data[2], data[3], data[4], data[5], data[6]])?;
68 match &service.service {
69 FieldOrService::Service(digital) => {
70 if digital.service != service_no {
71 return Err(ParserError::ServiceNumberMismatch);
72 }
73 }
74 FieldOrService::Field(_field1) => {
75 if service_no != 0 {
76 return Err(ParserError::ServiceNumberMismatch);
77 }
78 }
79 }
80 data = &data[7..];
81 ret.services.push(service);
82 }
83 Ok(ret)
84 }
85
86 pub fn is_start(&self) -> bool {
88 self.start
89 }
90
91 pub fn set_start(&mut self, start: bool) {
93 self.start = start;
94 }
95
96 pub fn is_change(&self) -> bool {
99 self.change
100 }
101
102 pub fn set_change(&mut self, change: bool) {
105 self.change = change;
106 if change {
107 self.start = true;
108 }
109 }
110
111 pub fn is_complete(&self) -> bool {
113 self.complete
114 }
115
116 pub fn set_complete(&mut self, complete: bool) {
118 self.complete = complete;
119 }
120
121 pub fn services(&self) -> &[ServiceEntry] {
123 &self.services
124 }
125
126 pub fn clear_services(&mut self) {
128 self.services.clear();
129 }
130
131 pub fn add_service(&mut self, service: ServiceEntry) -> Result<(), WriterError> {
133 if self.services.len() >= 15 {
134 return Err(WriterError::WouldOverflow(1));
135 }
136 self.services.push(service);
137 Ok(())
138 }
139
140 pub fn byte_len(&self) -> usize {
142 self.services.len() * 7 + 2
143 }
144
145 pub fn write<W: std::io::Write>(&mut self, w: &mut W) -> Result<(), std::io::Error> {
147 let mut header = [0; 2];
148 self.write_header_unchecked(&mut header);
149 w.write_all(&header)?;
150 for svc in self.services.iter() {
151 let mut data = [0; 7];
152 self.write_svc_header_unchecked(svc, &mut data[..1]);
153 svc.write_into_unchecked(&mut data[1..7]);
154 w.write_all(&data)?;
155 }
156 Ok(())
157 }
158
159 fn write_header_unchecked(&self, data: &mut [u8]) {
160 data[0] = 0x73;
161 let mut byte = 0x80;
162 if self.start {
163 byte |= 0x40;
164 }
165 if self.change {
166 byte |= 0x20;
167 }
168 if self.complete {
169 byte |= 0x10;
170 }
171 let byte_len = self.services.len() & 0xf;
172 byte |= byte_len as u8;
173 data[1] = byte;
174 }
175
176 fn write_svc_header_unchecked(&self, svc: &ServiceEntry, data: &mut [u8]) {
177 match &svc.service {
178 FieldOrService::Field(field) => {
179 let mut byte = 0x80;
180 if !*field {
181 byte |= 0x01
182 }
183 data[0] = byte;
184 }
185 FieldOrService::Service(digital) => {
186 data[0] = 0x80 | digital.service;
187 }
188 }
189 }
190
191 pub fn write_into_unchecked(&self, data: &mut [u8]) -> usize {
194 self.write_header_unchecked(data);
195 let mut idx = 2;
196 for svc in self.services.iter() {
197 self.write_svc_header_unchecked(svc, &mut data[idx..idx + 1]);
198 svc.write_into_unchecked(&mut data[idx + 1..idx + 7]);
199 idx += 7;
200 }
201 idx
202 }
203}
204
205#[derive(Debug, PartialEq, Eq, Clone, Copy)]
208pub struct ServiceEntry {
209 language: [u8; 3],
210 service: FieldOrService,
211}
212
213impl ServiceEntry {
214 pub fn new(language: [u8; 3], service: FieldOrService) -> Self {
216 Self { language, service }
217 }
218
219 pub fn parse(data: [u8; 6]) -> Result<Self, ParserError> {
221 let digital_cc = data[3] & 0x80 > 0;
222 if data[3] & 0x40 != 0x40 {
223 return Err(ParserError::InvalidFixedBits);
224 }
225 let atsc_service_no = data[3] & 0x3f;
226 let easy_reader = data[4] & 0x80 > 0;
227 let wide_aspect_ratio = data[4] & 0x40 > 0;
228 let service = if digital_cc {
229 if atsc_service_no == 0 {
230 return Err(ParserError::InvalidServiceNumber);
231 }
232 FieldOrService::Service(DigitalServiceEntry {
233 service: atsc_service_no,
234 easy_reader,
235 wide_aspect_ratio,
236 })
237 } else {
238 if data[3] & 0x3e != 0x3e {
239 return Err(ParserError::InvalidFixedBits);
240 }
241 FieldOrService::Field(atsc_service_no & 0x01 == 0)
242 };
243 if data[4] & 0x3f != 0x3f {
244 return Err(ParserError::InvalidFixedBits);
245 }
246 if data[5] != 0xff {
247 return Err(ParserError::InvalidFixedBits);
248 }
249 Ok(Self {
250 language: [data[0], data[1], data[2]],
251 service,
252 })
253 }
254
255 pub fn language(&self) -> [u8; 3] {
257 self.language
258 }
259
260 pub fn service(&self) -> &FieldOrService {
262 &self.service
263 }
264
265 pub fn write<W: std::io::Write>(&mut self, w: &mut W) -> Result<(), std::io::Error> {
267 let mut data = [0; 6];
268 self.write_into_unchecked(&mut data);
269 w.write_all(&data)
270 }
271
272 pub fn write_into_unchecked(&self, data: &mut [u8]) {
275 data[0] = self.language[0];
276 data[1] = self.language[1];
277 data[2] = self.language[2];
278 match &self.service {
279 FieldOrService::Field(field) => {
280 let mut byte = 0x7e;
281 if !*field {
282 byte |= 0x01;
283 }
284 data[3] = byte;
285 data[4] = 0x3f;
286 }
287 FieldOrService::Service(digital) => {
288 data[3] = 0xc0 | digital.service;
289 let mut byte = 0x3f;
290 if digital.easy_reader {
291 byte |= 0x80;
292 }
293 if digital.wide_aspect_ratio {
294 byte |= 0x40;
295 }
296 data[4] = byte;
297 }
298 }
299 data[5] = 0xff;
300 }
301}
302
303#[derive(Debug, PartialEq, Eq, Copy, Clone)]
305pub enum FieldOrService {
306 Field(bool),
308 Service(DigitalServiceEntry),
310}
311
312#[derive(Debug, PartialEq, Eq, Copy, Clone)]
314pub struct DigitalServiceEntry {
315 service: u8,
316 easy_reader: bool,
317 wide_aspect_ratio: bool,
318}
319
320impl DigitalServiceEntry {
321 pub fn new(service: u8, easy_reader: bool, wide_aspect_ratio: bool) -> Self {
323 Self {
324 service,
325 easy_reader,
326 wide_aspect_ratio,
327 }
328 }
329
330 pub fn service_no(&self) -> u8 {
332 self.service
333 }
334
335 pub fn easy_reader(&self) -> bool {
337 self.easy_reader
338 }
339
340 pub fn wide_aspect_ratio(&self) -> bool {
342 self.wide_aspect_ratio
343 }
344}
345
346#[cfg(test)]
347mod test {
348 use std::sync::LazyLock;
349
350 use super::*;
351 use crate::tests::test_init_log;
352
353 static LANG_TAG: [u8; 3] = [b'e', b'n', b'g'];
354
355 #[derive(Debug)]
356 struct TestSVCData {
357 data: Vec<u8>,
358 service_info: ServiceInfo,
359 }
360
361 static PARSE_SERVICE: LazyLock<[TestSVCData; 1]> = LazyLock::new(|| {
362 [TestSVCData {
363 data: vec![
364 0x73, 0xd2, 0x80, LANG_TAG[0],
368 LANG_TAG[1],
369 LANG_TAG[2],
370 0x7e, 0x3f, 0xff, 0xe1,
374 LANG_TAG[0],
375 LANG_TAG[1],
376 LANG_TAG[2],
377 0xc1,
378 0xff,
379 0xff,
380 ],
381 service_info: ServiceInfo {
382 start: true,
383 change: false,
384 complete: true,
385 services: vec![
386 ServiceEntry {
387 language: LANG_TAG,
388 service: FieldOrService::Field(true),
389 },
390 ServiceEntry {
391 language: LANG_TAG,
392 service: FieldOrService::Service(DigitalServiceEntry {
393 service: 1,
394 easy_reader: true,
395 wide_aspect_ratio: true,
396 }),
397 },
398 ],
399 },
400 }]
401 });
402
403 #[test]
404 fn parse_service_descriptor() {
405 test_init_log();
406
407 for service in PARSE_SERVICE.iter() {
408 debug!("parsing service info data: {:x?}", service.data);
409 let parsed = ServiceInfo::parse(&service.data).unwrap();
410 assert_eq!(parsed, service.service_info);
411 }
412 }
413
414 #[test]
415 fn roundtrip_service_descriptor() {
416 test_init_log();
417
418 for svc in PARSE_SERVICE.iter() {
419 debug!("writing service {:?}", svc.service_info);
420 debug!("existing data {:x?}", svc.data);
421 let byte_len = svc.service_info.byte_len();
422 let mut data = vec![0; byte_len];
423 svc.service_info.write_into_unchecked(&mut data);
424 debug!("wrote service data {data:x?}");
425 let service = ServiceInfo::parse(&data).unwrap();
426 debug!("parsed service {service:?}");
427 assert_eq!(service, svc.service_info);
428 }
429 }
430
431 #[test]
432 fn add_service_overflow() {
433 test_init_log();
434
435 let mut info = ServiceInfo::default();
436 let lang_tag = [b'e', b'n', b'g'];
437 for i in 0..15 {
438 let entry = ServiceEntry::new(
439 lang_tag,
440 FieldOrService::Service(DigitalServiceEntry::new(i, false, false)),
441 );
442 info.add_service(entry).unwrap();
443 }
444 let entry = ServiceEntry::new(
445 lang_tag,
446 FieldOrService::Service(DigitalServiceEntry::new(1, false, false)),
447 );
448 assert_eq!(info.add_service(entry), Err(WriterError::WouldOverflow(1)));
449 }
450}