1use super::descriptor_body;
10use crate::error::{Error, Result};
11use dvb_common::{Parse, Serialize};
12
13pub const TAG: u8 = 0x7A;
15const HEADER_LEN: usize = 2;
16
17const FLAG_COMPONENT_TYPE: u8 = 0x80;
18const FLAG_BSID: u8 = 0x40;
19const FLAG_MAINID: u8 = 0x20;
20const FLAG_ASVC: u8 = 0x10;
21const FLAG_MIXINFO_EXISTS: u8 = 0x08;
22const FLAG_SUBSTREAM1: u8 = 0x04;
23const FLAG_SUBSTREAM2: u8 = 0x02;
24const FLAG_SUBSTREAM3: u8 = 0x01;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize))]
29#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
30pub struct EnhancedAc3Descriptor<'a> {
31 pub component_type: Option<u8>,
33 pub bsid: Option<u8>,
35 pub mainid: Option<u8>,
37 pub asvc: Option<u8>,
39 pub mixinfoexists: bool,
42 pub substream1: Option<u8>,
44 pub substream2: Option<u8>,
46 pub substream3: Option<u8>,
48 pub additional_info: &'a [u8],
50}
51
52impl<'a> Parse<'a> for EnhancedAc3Descriptor<'a> {
53 type Error = crate::error::Error;
54 fn parse(bytes: &'a [u8]) -> Result<Self> {
55 let body = descriptor_body(
56 bytes,
57 TAG,
58 "EnhancedAc3Descriptor",
59 "unexpected tag for EAC-3 descriptor",
60 )?;
61 if body.is_empty() {
62 return Err(Error::InvalidDescriptor {
63 tag: TAG,
64 reason: "descriptor body is empty (length=0)",
65 });
66 }
67 let flags = body[0];
68 let mixinfoexists = (flags & FLAG_MIXINFO_EXISTS) != 0;
69 let mut pos = 1;
70 let mut read_one = |set: bool| -> Result<Option<u8>> {
71 if !set {
72 return Ok(None);
73 }
74 if pos >= body.len() {
75 return Err(Error::InvalidDescriptor {
76 tag: TAG,
77 reason: "enhanced AC-3 descriptor flags claim more bytes than length permits",
78 });
79 }
80 let b = body[pos];
81 pos += 1;
82 Ok(Some(b))
83 };
84
85 let component_type = read_one(flags & FLAG_COMPONENT_TYPE != 0)?;
86 let bsid = read_one(flags & FLAG_BSID != 0)?;
87 let mainid = read_one(flags & FLAG_MAINID != 0)?;
88 let asvc = read_one(flags & FLAG_ASVC != 0)?;
89 let substream1 = read_one(flags & FLAG_SUBSTREAM1 != 0)?;
90 let substream2 = read_one(flags & FLAG_SUBSTREAM2 != 0)?;
91 let substream3 = read_one(flags & FLAG_SUBSTREAM3 != 0)?;
92 let additional_info = &body[pos..];
93 Ok(Self {
94 component_type,
95 bsid,
96 mainid,
97 asvc,
98 mixinfoexists,
99 substream1,
100 substream2,
101 substream3,
102 additional_info,
103 })
104 }
105}
106
107impl Serialize for EnhancedAc3Descriptor<'_> {
108 type Error = crate::error::Error;
109 fn serialized_len(&self) -> usize {
110 HEADER_LEN
111 + 1
112 + usize::from(self.component_type.is_some())
113 + usize::from(self.bsid.is_some())
114 + usize::from(self.mainid.is_some())
115 + usize::from(self.asvc.is_some())
116 + usize::from(self.substream1.is_some())
117 + usize::from(self.substream2.is_some())
118 + usize::from(self.substream3.is_some())
119 + self.additional_info.len()
120 }
121
122 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
123 let len = self.serialized_len();
124 if buf.len() < len {
125 return Err(Error::OutputBufferTooSmall {
126 need: len,
127 have: buf.len(),
128 });
129 }
130 buf[0] = TAG;
131 buf[1] = (len - HEADER_LEN) as u8;
132 let mut flags: u8 = 0;
133 if self.component_type.is_some() {
134 flags |= FLAG_COMPONENT_TYPE;
135 }
136 if self.bsid.is_some() {
137 flags |= FLAG_BSID;
138 }
139 if self.mainid.is_some() {
140 flags |= FLAG_MAINID;
141 }
142 if self.asvc.is_some() {
143 flags |= FLAG_ASVC;
144 }
145 if self.mixinfoexists {
146 flags |= FLAG_MIXINFO_EXISTS;
147 }
148 if self.substream1.is_some() {
149 flags |= FLAG_SUBSTREAM1;
150 }
151 if self.substream2.is_some() {
152 flags |= FLAG_SUBSTREAM2;
153 }
154 if self.substream3.is_some() {
155 flags |= FLAG_SUBSTREAM3;
156 }
157 buf[2] = flags;
158 let mut pos = 3;
159 for b in [
160 self.component_type,
161 self.bsid,
162 self.mainid,
163 self.asvc,
164 self.substream1,
165 self.substream2,
166 self.substream3,
167 ]
168 .into_iter()
169 .flatten()
170 {
171 buf[pos] = b;
172 pos += 1;
173 }
174 buf[pos..pos + self.additional_info.len()].copy_from_slice(self.additional_info);
175 Ok(len)
176 }
177}
178impl<'a> crate::traits::DescriptorDef<'a> for EnhancedAc3Descriptor<'a> {
179 const TAG: u8 = TAG;
180 const NAME: &'static str = "ENHANCED_AC3";
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[test]
188 fn parse_with_all_fields() {
189 let bytes = [
190 TAG,
191 8,
192 FLAG_COMPONENT_TYPE
193 | FLAG_BSID
194 | FLAG_MAINID
195 | FLAG_ASVC
196 | FLAG_MIXINFO_EXISTS
197 | FLAG_SUBSTREAM1
198 | FLAG_SUBSTREAM2
199 | FLAG_SUBSTREAM3,
200 0x11,
201 0x22,
202 0x33,
203 0x44,
204 0x55,
205 0x66,
206 0x77,
207 ];
208 let d = EnhancedAc3Descriptor::parse(&bytes).unwrap();
209 assert_eq!(d.component_type, Some(0x11));
210 assert_eq!(d.bsid, Some(0x22));
211 assert_eq!(d.mainid, Some(0x33));
212 assert_eq!(d.asvc, Some(0x44));
213 assert!(d.mixinfoexists);
214 assert_eq!(d.substream1, Some(0x55));
215 assert_eq!(d.substream2, Some(0x66));
216 assert_eq!(d.substream3, Some(0x77));
217 assert_eq!(d.additional_info, &[] as &[u8]);
218 }
219
220 #[test]
221 fn parse_with_only_component_type_and_mixinfoexists() {
222 let bytes = [TAG, 2, FLAG_COMPONENT_TYPE | FLAG_MIXINFO_EXISTS, 0x07];
223 let d = EnhancedAc3Descriptor::parse(&bytes).unwrap();
224 assert_eq!(d.component_type, Some(0x07));
225 assert!(d.mixinfoexists);
226 assert_eq!(d.bsid, None);
227 assert_eq!(d.substream1, None);
228 }
229
230 #[test]
231 fn parse_with_additional_info_only() {
232 let bytes = [TAG, 3, 0x00, 0xAA, 0xBB];
233 let d = EnhancedAc3Descriptor::parse(&bytes).unwrap();
234 assert_eq!(d.component_type, None);
235 assert!(!d.mixinfoexists);
236 assert_eq!(d.additional_info, &[0xAA, 0xBB]);
237 }
238
239 #[test]
240 fn parse_rejects_wrong_tag() {
241 assert!(matches!(
242 EnhancedAc3Descriptor::parse(&[0x6A, 1, 0]).unwrap_err(),
243 Error::InvalidDescriptor { tag: 0x6A, .. }
244 ));
245 }
246
247 #[test]
248 fn parse_rejects_flags_past_length() {
249 let bytes = [TAG, 1, FLAG_COMPONENT_TYPE];
250 assert!(matches!(
251 EnhancedAc3Descriptor::parse(&bytes).unwrap_err(),
252 Error::InvalidDescriptor { .. }
253 ));
254 }
255
256 #[test]
257 fn parse_rejects_short_buffer() {
258 assert!(matches!(
259 EnhancedAc3Descriptor::parse(&[TAG]).unwrap_err(),
260 Error::BufferTooShort { .. }
261 ));
262 }
263
264 #[test]
265 fn serialize_round_trip() {
266 let d = EnhancedAc3Descriptor {
267 component_type: Some(0x40),
268 bsid: Some(8),
269 mainid: None,
270 asvc: None,
271 mixinfoexists: true,
272 substream1: Some(0xAA),
273 substream2: None,
274 substream3: None,
275 additional_info: &[0xFE, 0xED],
276 };
277 let mut buf = vec![0u8; d.serialized_len()];
278 d.serialize_into(&mut buf).unwrap();
279 assert_eq!(EnhancedAc3Descriptor::parse(&buf).unwrap(), d);
280 }
281
282 #[test]
283 fn serialize_round_trip_no_flags() {
284 let d = EnhancedAc3Descriptor {
285 component_type: None,
286 bsid: None,
287 mainid: None,
288 asvc: None,
289 mixinfoexists: false,
290 substream1: None,
291 substream2: None,
292 substream3: None,
293 additional_info: &[],
294 };
295 let mut buf = vec![0u8; d.serialized_len()];
296 d.serialize_into(&mut buf).unwrap();
297 assert_eq!(EnhancedAc3Descriptor::parse(&buf).unwrap(), d);
298 assert_eq!(buf, [TAG, 1, 0x00]);
299 }
300
301 #[test]
302 fn parse_rejects_empty_body() {
303 let bytes = [TAG, 0];
304 assert!(matches!(
305 EnhancedAc3Descriptor::parse(&bytes).unwrap_err(),
306 Error::InvalidDescriptor { .. }
307 ));
308 }
309}