Skip to main content

dvb_subtitle/segments/
end_of_display_set.rs

1//! End of Display Set Segment — ETSI EN 300 743 §7.2.6, Table 28 (segment_type 0x80).
2
3use crate::error::{Error, Result};
4use broadcast_common::{Parse, Serialize};
5
6/// The end_of_display_set_segment segment_type.
7pub const SEGMENT_TYPE: u8 = 0x80;
8/// Header: sync_byte(1) + segment_type(1) + page_id(2) + segment_length(2) = 6 bytes. segment_length must be 0.
9pub const HEADER_LEN: usize = 6;
10
11/// End of Display Set Segment.
12#[derive(Debug, Clone, PartialEq, Eq)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize))]
14pub struct EndOfDisplaySetSegment {
15    /// The page_id (from generic segment header).
16    pub page_id: u16,
17}
18
19impl<'a> Parse<'a> for EndOfDisplaySetSegment {
20    type Error = Error;
21
22    fn parse(bytes: &'a [u8]) -> Result<Self> {
23        if bytes.len() < HEADER_LEN {
24            return Err(Error::BufferTooShort {
25                need: HEADER_LEN,
26                have: bytes.len(),
27                what: "end_of_display_set_segment",
28            });
29        }
30        if bytes[0] != crate::pes_data_field::SYNC_BYTE {
31            return Err(Error::BadSyncByte(bytes[0]));
32        }
33        if bytes[1] != SEGMENT_TYPE {
34            return Err(Error::UnknownSegmentType(bytes[1]));
35        }
36        let page_id = u16::from_be_bytes([bytes[2], bytes[3]]);
37        let segment_length = u16::from_be_bytes([bytes[4], bytes[5]]);
38        if segment_length != 0 {
39            return Err(Error::SegmentTooLarge);
40        }
41        Ok(EndOfDisplaySetSegment { page_id })
42    }
43}
44
45impl Serialize for EndOfDisplaySetSegment {
46    type Error = Error;
47
48    fn serialized_len(&self) -> usize {
49        HEADER_LEN
50    }
51
52    fn serialize_into(&self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> {
53        let len = self.serialized_len();
54        if buf.len() < len {
55            return Err(Error::BufferTooShort {
56                need: len,
57                have: buf.len(),
58                what: "end_of_display_set_segment serialize",
59            });
60        }
61        buf[0] = 0x0F;
62        buf[1] = SEGMENT_TYPE;
63        buf[2..4].copy_from_slice(&self.page_id.to_be_bytes());
64        buf[4..6].copy_from_slice(&0u16.to_be_bytes()); // segment_length = 0
65        Ok(len)
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use broadcast_common::{Parse, Serialize};
73
74    #[test]
75    fn round_trip() {
76        let bytes = [0x0F, 0x80, 0x00, 0x01, 0x00, 0x00];
77        let seg = EndOfDisplaySetSegment::parse(&bytes).unwrap();
78        assert_eq!(seg.page_id, 1);
79        let out = seg.try_to_bytes().unwrap();
80        assert_eq!(out, bytes);
81
82        // Biting test: mutation changes output
83        let mut seg2 = seg.clone();
84        seg2.page_id = 5;
85        let out2 = seg2.try_to_bytes().unwrap();
86        assert_ne!(out2, bytes);
87        let reparse = EndOfDisplaySetSegment::parse(&out2).unwrap();
88        assert_eq!(reparse.page_id, 5);
89    }
90
91    /// DS-W2 (#1108): sync_byte wasn't checked by any typed segment parser
92    /// (only by `PesDataField`, whose loop only ever calls a typed parser
93    /// with `bytes[0] == 0x0F` anyway), so a direct caller of `Self::parse`
94    /// could parse a non-segment, and re-serializing it would silently
95    /// change byte 0 back to `0x0F`.
96    #[test]
97    fn rejects_bad_sync_byte() {
98        let bytes = [0x00, 0x80, 0x00, 0x01, 0x00, 0x00];
99        assert!(matches!(
100            EndOfDisplaySetSegment::parse(&bytes),
101            Err(Error::BadSyncByte(0x00))
102        ));
103    }
104}