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