dvb_si/descriptors/
ca_identifier.rs1use crate::error::{Error, Result};
8use crate::traits::Descriptor;
9use dvb_common::{Parse, Serialize};
10
11pub const TAG: u8 = 0x53;
13const HEADER_LEN: usize = 2;
14const ENTRY_LEN: usize = 2;
15const MAX_BODY_LEN: usize = u8::MAX as usize;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub struct CaIdentifierDescriptor {
22 pub ca_system_ids: Vec<u16>,
24}
25
26impl<'a> Parse<'a> for CaIdentifierDescriptor {
27 type Error = crate::error::Error;
28 fn parse(bytes: &'a [u8]) -> Result<Self> {
29 if bytes.len() < HEADER_LEN {
30 return Err(Error::BufferTooShort {
31 need: HEADER_LEN,
32 have: bytes.len(),
33 what: "CaIdentifierDescriptor header",
34 });
35 }
36 if bytes[0] != TAG {
37 return Err(Error::InvalidDescriptor {
38 tag: bytes[0],
39 reason: "unexpected tag for CA_identifier_descriptor",
40 });
41 }
42 let length = bytes[1] as usize;
43 if length % ENTRY_LEN != 0 {
44 return Err(Error::InvalidDescriptor {
45 tag: TAG,
46 reason: "descriptor_length must be a multiple of 2",
47 });
48 }
49 let end = HEADER_LEN + length;
50 if bytes.len() < end {
51 return Err(Error::BufferTooShort {
52 need: end,
53 have: bytes.len(),
54 what: "CaIdentifierDescriptor body",
55 });
56 }
57 let body = &bytes[HEADER_LEN..end];
58 let mut ca_system_ids = Vec::with_capacity(length / ENTRY_LEN);
59 for chunk in body.chunks_exact(ENTRY_LEN) {
60 ca_system_ids.push(u16::from_be_bytes([chunk[0], chunk[1]]));
61 }
62 Ok(Self { ca_system_ids })
63 }
64}
65
66impl Serialize for CaIdentifierDescriptor {
67 type Error = crate::error::Error;
68 fn serialized_len(&self) -> usize {
69 HEADER_LEN + ENTRY_LEN * self.ca_system_ids.len()
70 }
71
72 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
73 let len = self.serialized_len();
74 if buf.len() < len {
75 return Err(Error::OutputBufferTooSmall {
76 need: len,
77 have: buf.len(),
78 });
79 }
80 let body_len = ENTRY_LEN * self.ca_system_ids.len();
81 if body_len > MAX_BODY_LEN {
83 return Err(Error::SectionLengthOverflow {
84 declared: body_len,
85 available: MAX_BODY_LEN,
86 });
87 }
88 buf[0] = TAG;
89 buf[1] = body_len as u8;
90 let mut pos = HEADER_LEN;
91 for caid in &self.ca_system_ids {
92 buf[pos..pos + ENTRY_LEN].copy_from_slice(&caid.to_be_bytes());
93 pos += ENTRY_LEN;
94 }
95 Ok(len)
96 }
97}
98
99impl<'a> Descriptor<'a> for CaIdentifierDescriptor {
100 const TAG: u8 = TAG;
101 fn descriptor_length(&self) -> u8 {
102 (ENTRY_LEN * self.ca_system_ids.len()) as u8
103 }
104}
105
106impl<'a> crate::traits::DescriptorDef<'a> for CaIdentifierDescriptor {
107 const TAG: u8 = TAG;
108 const NAME: &'static str = "CA_IDENTIFIER";
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn parse_single_caid() {
117 let bytes = [TAG, 2, 0x06, 0x50];
118 let d = CaIdentifierDescriptor::parse(&bytes).unwrap();
119 assert_eq!(d.ca_system_ids, vec![0x0650]);
120 }
121
122 #[test]
123 fn parse_multiple_caids_preserves_order() {
124 let bytes = [TAG, 6, 0x05, 0x00, 0x06, 0x50, 0x0B, 0x00];
125 let d = CaIdentifierDescriptor::parse(&bytes).unwrap();
126 assert_eq!(d.ca_system_ids, vec![0x0500, 0x0650, 0x0B00]);
127 }
128
129 #[test]
130 fn parse_rejects_wrong_tag() {
131 assert!(matches!(
132 CaIdentifierDescriptor::parse(&[0x54, 2, 0x06, 0x50]).unwrap_err(),
133 Error::InvalidDescriptor { tag: 0x54, .. }
134 ));
135 }
136
137 #[test]
138 fn parse_rejects_short_buffer() {
139 let bytes = [TAG, 4, 0x06, 0x50];
141 assert!(matches!(
142 CaIdentifierDescriptor::parse(&bytes).unwrap_err(),
143 Error::BufferTooShort { .. }
144 ));
145 }
146
147 #[test]
148 fn parse_rejects_odd_length() {
149 let bytes = [TAG, 3, 0x06, 0x50, 0x00];
150 assert!(matches!(
151 CaIdentifierDescriptor::parse(&bytes).unwrap_err(),
152 Error::InvalidDescriptor { tag: TAG, .. }
153 ));
154 }
155
156 #[test]
157 fn empty_descriptor_valid() {
158 let d = CaIdentifierDescriptor::parse(&[TAG, 0]).unwrap();
159 assert!(d.ca_system_ids.is_empty());
160 }
161
162 #[test]
163 fn serialize_round_trip() {
164 let d = CaIdentifierDescriptor {
165 ca_system_ids: vec![0x0100, 0x1800, 0x2600],
166 };
167 let mut buf = vec![0u8; d.serialized_len()];
168 d.serialize_into(&mut buf).unwrap();
169 assert_eq!(CaIdentifierDescriptor::parse(&buf).unwrap(), d);
170 }
171
172 #[test]
173 fn serialize_rejects_over_range_body() {
174 let d = CaIdentifierDescriptor {
176 ca_system_ids: vec![0x0500; 128],
177 };
178 let mut buf = vec![0u8; d.serialized_len()];
179 assert!(matches!(
180 d.serialize_into(&mut buf).unwrap_err(),
181 Error::SectionLengthOverflow { .. }
182 ));
183 }
184
185 #[cfg(feature = "serde")]
186 #[test]
187 fn serde_round_trip() {
188 let d = CaIdentifierDescriptor {
189 ca_system_ids: vec![0x0500, 0x0650],
190 };
191 let json = serde_json::to_string(&d).unwrap();
192 let back: CaIdentifierDescriptor = serde_json::from_str(&json).unwrap();
193 assert_eq!(d, back);
194 }
195}