Skip to main content

dvb_si/descriptors/
registration.rs

1//! Registration Descriptor — ISO/IEC 13818-1 §2.6.13 (tag 0x05).
2//!
3//! Identifies the registration of a stream or program via a 4-byte
4//! `format_identifier`. Optionally followed by additional identification
5//! information.
6
7use crate::error::{Error, Result};
8use crate::traits::Descriptor;
9use dvb_common::{Parse, Serialize};
10
11/// Descriptor tag for registration_descriptor.
12pub const TAG: u8 = 0x05;
13const HEADER_LEN: usize = 2;
14const FORMAT_IDENTIFIER_LEN: usize = 4;
15
16/// Registration Descriptor.
17///
18/// The `format_identifier` is a 4-byte code registered with a standards body
19/// (e.g. SMPTE, ATSC) that identifies the coding format of the associated
20/// stream. Any bytes beyond the 4-byte identifier are treated as opaque
21/// additional identification info.
22#[derive(Debug, Clone, PartialEq, Eq)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize))]
24#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
25pub struct RegistrationDescriptor<'a> {
26    /// 4-byte format identifier (e.g. b"AC-3", b"HDMV", b"dtsx").
27    pub format_identifier: [u8; FORMAT_IDENTIFIER_LEN],
28    /// Optional additional identification bytes following the format identifier.
29    pub additional_identification_info: &'a [u8],
30}
31
32impl<'a> Parse<'a> for RegistrationDescriptor<'a> {
33    type Error = crate::error::Error;
34
35    fn parse(bytes: &'a [u8]) -> Result<Self> {
36        if bytes.len() < HEADER_LEN {
37            return Err(Error::BufferTooShort {
38                need: HEADER_LEN,
39                have: bytes.len(),
40                what: "RegistrationDescriptor header",
41            });
42        }
43        if bytes[0] != TAG {
44            return Err(Error::InvalidDescriptor {
45                tag: bytes[0],
46                reason: "unexpected tag for registration_descriptor",
47            });
48        }
49        let length = bytes[1] as usize;
50        if length < FORMAT_IDENTIFIER_LEN {
51            return Err(Error::InvalidDescriptor {
52                tag: TAG,
53                reason: "registration_descriptor length too short for format_identifier",
54            });
55        }
56        let total = HEADER_LEN + length;
57        if bytes.len() < total {
58            return Err(Error::BufferTooShort {
59                need: total,
60                have: bytes.len(),
61                what: "RegistrationDescriptor body",
62            });
63        }
64        let body = &bytes[HEADER_LEN..total];
65        let mut format_identifier = [0u8; FORMAT_IDENTIFIER_LEN];
66        format_identifier.copy_from_slice(&body[..FORMAT_IDENTIFIER_LEN]);
67        let additional_identification_info = &body[FORMAT_IDENTIFIER_LEN..];
68        Ok(Self {
69            format_identifier,
70            additional_identification_info,
71        })
72    }
73}
74
75impl Serialize for RegistrationDescriptor<'_> {
76    type Error = crate::error::Error;
77
78    fn serialized_len(&self) -> usize {
79        HEADER_LEN + FORMAT_IDENTIFIER_LEN + self.additional_identification_info.len()
80    }
81
82    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
83        let len = self.serialized_len();
84        if buf.len() < len {
85            return Err(Error::OutputBufferTooSmall {
86                need: len,
87                have: buf.len(),
88            });
89        }
90        buf[0] = TAG;
91        buf[1] = (len - HEADER_LEN) as u8;
92        buf[HEADER_LEN..HEADER_LEN + FORMAT_IDENTIFIER_LEN]
93            .copy_from_slice(&self.format_identifier);
94        buf[HEADER_LEN + FORMAT_IDENTIFIER_LEN..len]
95            .copy_from_slice(self.additional_identification_info);
96        Ok(len)
97    }
98}
99
100impl<'a> Descriptor<'a> for RegistrationDescriptor<'a> {
101    const TAG: u8 = TAG;
102
103    fn descriptor_length(&self) -> u8 {
104        (self.serialized_len() - HEADER_LEN) as u8
105    }
106}
107
108impl<'a> crate::traits::DescriptorDef<'a> for RegistrationDescriptor<'a> {
109    const TAG: u8 = TAG;
110    const NAME: &'static str = "REGISTRATION";
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn parse_format_identifier_only() {
119        let bytes = [TAG, 4, b'A', b'C', b'-', b'3'];
120        let d = RegistrationDescriptor::parse(&bytes).unwrap();
121        assert_eq!(&d.format_identifier, b"AC-3");
122        assert!(d.additional_identification_info.is_empty());
123    }
124
125    #[test]
126    fn parse_with_additional_info() {
127        let bytes = [TAG, 6, b'H', b'D', b'M', b'V', 0x01, 0x02];
128        let d = RegistrationDescriptor::parse(&bytes).unwrap();
129        assert_eq!(&d.format_identifier, b"HDMV");
130        assert_eq!(d.additional_identification_info, &[0x01, 0x02]);
131    }
132
133    #[test]
134    fn parse_rejects_wrong_tag() {
135        let err = RegistrationDescriptor::parse(&[0x06, 4, 0, 0, 0, 0]).unwrap_err();
136        assert!(matches!(err, Error::InvalidDescriptor { tag: 0x06, .. }));
137    }
138
139    #[test]
140    fn parse_rejects_short_header() {
141        let err = RegistrationDescriptor::parse(&[TAG]).unwrap_err();
142        assert!(matches!(err, Error::BufferTooShort { .. }));
143    }
144
145    #[test]
146    fn parse_rejects_length_too_short_for_format_id() {
147        let bytes = [TAG, 3, 0, 0, 0];
148        let err = RegistrationDescriptor::parse(&bytes).unwrap_err();
149        assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
150    }
151
152    #[test]
153    fn parse_rejects_length_overflow() {
154        let bytes = [TAG, 10, 0, 0, 0, 0];
155        let err = RegistrationDescriptor::parse(&bytes).unwrap_err();
156        assert!(matches!(err, Error::BufferTooShort { .. }));
157    }
158
159    #[test]
160    fn serialize_round_trip() {
161        let d = RegistrationDescriptor {
162            format_identifier: *b"dtsx",
163            additional_identification_info: &[0xAA, 0xBB],
164        };
165        let mut buf = vec![0u8; d.serialized_len()];
166        d.serialize_into(&mut buf).unwrap();
167        let reparsed = RegistrationDescriptor::parse(&buf).unwrap();
168        assert_eq!(d, reparsed);
169    }
170
171    #[test]
172    fn serialize_rejects_small_buffer() {
173        let d = RegistrationDescriptor {
174            format_identifier: *b"AC-3",
175            additional_identification_info: &[],
176        };
177        let mut tiny = vec![0u8; 3];
178        let err = d.serialize_into(&mut tiny).unwrap_err();
179        assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
180    }
181
182    #[test]
183    fn descriptor_length_matches_payload() {
184        let d = RegistrationDescriptor {
185            format_identifier: *b"AC-3",
186            additional_identification_info: &[0x01],
187        };
188        assert_eq!(d.descriptor_length(), 5);
189    }
190}