dvb_ci/ci_plus/
descriptors.rs1use crate::error::{Error, Result};
17use dvb_common::{Parse, Serialize};
18
19pub const IV_DESCRIPTOR_TAG: u8 = 0xD0;
21pub const KEY_IDENTIFIER_DESCRIPTOR_TAG: u8 = 0xD1;
23
24const DESC_HEADER: usize = 2;
26
27#[derive(Debug, Clone, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize))]
31pub struct CiplusInitializationVectorDescriptor<'a> {
32 #[cfg_attr(feature = "serde", serde(borrow, with = "crate::objects::bytes_serde"))]
34 pub iv_data: &'a [u8],
35}
36
37impl<'a> Parse<'a> for CiplusInitializationVectorDescriptor<'a> {
38 type Error = Error;
39 fn parse(bytes: &'a [u8]) -> Result<Self> {
40 let body = parse_tlv(
41 bytes,
42 IV_DESCRIPTOR_TAG,
43 "ciplus_initialization_vector_descriptor",
44 )?;
45 Ok(Self { iv_data: body })
46 }
47}
48impl Serialize for CiplusInitializationVectorDescriptor<'_> {
49 type Error = Error;
50 fn serialized_len(&self) -> usize {
51 DESC_HEADER + self.iv_data.len()
52 }
53 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
54 write_tlv(IV_DESCRIPTOR_TAG, self.iv_data, buf)
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Eq)]
61#[cfg_attr(feature = "serde", derive(serde::Serialize))]
62pub struct CiplusKeyIdentifierDescriptor<'a> {
63 #[cfg_attr(feature = "serde", serde(borrow, with = "crate::objects::bytes_serde"))]
65 pub key_id_data: &'a [u8],
66}
67
68impl<'a> Parse<'a> for CiplusKeyIdentifierDescriptor<'a> {
69 type Error = Error;
70 fn parse(bytes: &'a [u8]) -> Result<Self> {
71 let body = parse_tlv(
72 bytes,
73 KEY_IDENTIFIER_DESCRIPTOR_TAG,
74 "ciplus_key_identifier_descriptor",
75 )?;
76 Ok(Self { key_id_data: body })
77 }
78}
79impl Serialize for CiplusKeyIdentifierDescriptor<'_> {
80 type Error = Error;
81 fn serialized_len(&self) -> usize {
82 DESC_HEADER + self.key_id_data.len()
83 }
84 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
85 write_tlv(KEY_IDENTIFIER_DESCRIPTOR_TAG, self.key_id_data, buf)
86 }
87}
88
89fn parse_tlv<'a>(bytes: &'a [u8], expected_tag: u8, what: &'static str) -> Result<&'a [u8]> {
92 if bytes.len() < DESC_HEADER {
93 return Err(Error::BufferTooShort {
94 need: DESC_HEADER,
95 have: bytes.len(),
96 what,
97 });
98 }
99 if bytes[0] != expected_tag {
100 return Err(Error::InvalidObject {
101 what,
102 reason: "descriptor_tag mismatch",
103 });
104 }
105 let len = bytes[1] as usize;
106 let end = DESC_HEADER + len;
107 if bytes.len() < end {
108 return Err(Error::LengthMismatch {
109 what,
110 declared: len,
111 actual: bytes.len().saturating_sub(DESC_HEADER),
112 });
113 }
114 Ok(&bytes[DESC_HEADER..end])
115}
116
117fn write_tlv(tag: u8, body: &[u8], buf: &mut [u8]) -> Result<usize> {
119 if body.len() > u8::MAX as usize {
120 return Err(Error::LengthTooLarge(body.len()));
121 }
122 let total = DESC_HEADER + body.len();
123 if buf.len() < total {
124 return Err(Error::OutputBufferTooSmall {
125 need: total,
126 have: buf.len(),
127 });
128 }
129 buf[0] = tag;
130 buf[1] = body.len() as u8;
131 buf[DESC_HEADER..total].copy_from_slice(body);
132 Ok(total)
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn iv_descriptor_round_trips_and_bites() {
141 let d = CiplusInitializationVectorDescriptor {
142 iv_data: &[0x00, 0x11, 0x22, 0x33],
143 };
144 let bytes = d.to_bytes();
145 assert_eq!(bytes, [0xD0, 0x04, 0x00, 0x11, 0x22, 0x33]);
146 assert_eq!(
147 CiplusInitializationVectorDescriptor::parse(&bytes).unwrap(),
148 d
149 );
150 let other = CiplusInitializationVectorDescriptor {
151 iv_data: &[0x00, 0x11, 0x22, 0x34],
152 };
153 assert_ne!(bytes, other.to_bytes());
154 }
155
156 #[test]
157 fn iv_descriptor_zero_byte_body() {
158 let d = CiplusInitializationVectorDescriptor { iv_data: &[] };
159 let bytes = d.to_bytes();
160 assert_eq!(bytes, [0xD0, 0x00]);
161 let parsed = CiplusInitializationVectorDescriptor::parse(&bytes).unwrap();
162 assert_eq!(parsed, d);
163 assert!(parsed.iv_data.is_empty());
164 }
165
166 #[test]
167 fn key_id_descriptor_round_trips() {
168 let d = CiplusKeyIdentifierDescriptor {
169 key_id_data: &[0xDE, 0xAD],
170 };
171 let bytes = d.to_bytes();
172 assert_eq!(bytes, [0xD1, 0x02, 0xDE, 0xAD]);
173 assert_eq!(CiplusKeyIdentifierDescriptor::parse(&bytes).unwrap(), d);
174 }
175
176 #[test]
177 fn key_id_descriptor_zero_byte_body() {
178 let d = CiplusKeyIdentifierDescriptor { key_id_data: &[] };
179 let bytes = d.to_bytes();
180 assert_eq!(bytes, [0xD1, 0x00]);
181 assert_eq!(CiplusKeyIdentifierDescriptor::parse(&bytes).unwrap(), d);
182 }
183
184 #[test]
185 fn wrong_tag_rejected() {
186 let bytes = [0xD1, 0x00];
187 assert!(matches!(
188 CiplusInitializationVectorDescriptor::parse(&bytes),
189 Err(Error::InvalidObject { .. })
190 ));
191 }
192}