1use crate::descriptors::descriptor_body;
13use crate::error::{Error, Result};
14use alloc::vec::Vec;
15use dvb_common::{Parse, Serialize};
16
17pub const TAG: u8 = 0x02;
19const HEADER_LEN: usize = 2;
20const PROTOCOL_ID_LEN: usize = 2;
21const LABEL_LEN: usize = 1;
22
23pub const PROTOCOL_ID_OBJECT_CAROUSEL: u16 = 0x0001;
25pub const PROTOCOL_ID_HTTP: u16 = 0x0003;
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize))]
31pub struct OcSelector {
32 pub remote_connection: bool,
34 pub remote_connection_info: Option<OcRemoteConnection>,
36 pub component_tag: u8,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize))]
43pub struct OcRemoteConnection {
44 pub original_network_id: u16,
46 pub transport_stream_id: u16,
48 pub service_id: u16,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
54#[cfg_attr(feature = "serde", derive(serde::Serialize))]
55pub struct HttpUrlEntry<'a> {
56 pub url_base: &'a [u8],
58 pub url_extensions: Vec<&'a [u8]>,
60}
61
62#[derive(Debug, Clone, PartialEq, Eq)]
64#[cfg_attr(feature = "serde", derive(serde::Serialize))]
65pub struct HttpSelector<'a> {
66 pub urls: Vec<HttpUrlEntry<'a>>,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
72#[cfg_attr(feature = "serde", derive(serde::Serialize))]
73#[non_exhaustive]
74pub enum SelectorKind<'a> {
75 ObjectCarousel(OcSelector),
77 Http(HttpSelector<'a>),
79 Unknown(&'a [u8]),
81}
82
83impl SelectorKind<'_> {
84 #[must_use]
86 pub fn name(&self) -> &'static str {
87 match self {
88 Self::ObjectCarousel(_) => "OBJECT_CAROUSEL",
89 Self::Http(_) => "HTTP",
90 Self::Unknown(_) => "UNKNOWN",
91 }
92 }
93}
94dvb_common::impl_spec_display!(SelectorKind<'_>);
95
96#[derive(Debug, Clone, PartialEq, Eq)]
98#[cfg_attr(feature = "serde", derive(serde::Serialize))]
99pub struct TransportProtocolDescriptor<'a> {
100 pub protocol_id: u16,
102 pub transport_protocol_label: u8,
104 #[cfg_attr(feature = "serde", serde(borrow))]
107 pub selector_bytes: &'a [u8],
108}
109
110impl<'a> TransportProtocolDescriptor<'a> {
111 #[must_use]
113 pub fn selector(&self) -> SelectorKind<'a> {
114 match self.protocol_id {
115 PROTOCOL_ID_OBJECT_CAROUSEL => self.decode_oc_selector(),
116 PROTOCOL_ID_HTTP => self.decode_http_selector(),
117 _ => SelectorKind::Unknown(self.selector_bytes),
118 }
119 }
120
121 fn decode_oc_selector(&self) -> SelectorKind<'a> {
122 let b = self.selector_bytes;
123 if b.len() < 2 {
124 return SelectorKind::Unknown(b);
125 }
126 let remote_connection = (b[0] & 0x80) != 0;
127 let mut pos = 1;
128 let remote_connection_info = if remote_connection {
129 if pos + 6 > b.len() {
130 return SelectorKind::Unknown(b);
131 }
132 let info = OcRemoteConnection {
133 original_network_id: u16::from_be_bytes([b[pos], b[pos + 1]]),
134 transport_stream_id: u16::from_be_bytes([b[pos + 2], b[pos + 3]]),
135 service_id: u16::from_be_bytes([b[pos + 4], b[pos + 5]]),
136 };
137 pos += 6;
138 Some(info)
139 } else {
140 None
141 };
142 if pos >= b.len() {
146 return SelectorKind::Unknown(b);
147 }
148 let component_tag = b[pos];
149 SelectorKind::ObjectCarousel(OcSelector {
150 remote_connection,
151 remote_connection_info,
152 component_tag,
153 })
154 }
155
156 fn decode_http_selector(&self) -> SelectorKind<'a> {
157 let b = self.selector_bytes;
158 let mut urls = Vec::new();
159 let mut pos = 0;
160 while pos < b.len() {
161 let url_base_length = b[pos] as usize;
162 pos += 1;
163 if pos + url_base_length > b.len() {
164 break;
165 }
166 let base_end = pos + url_base_length;
167 let url_base = &b[pos..base_end];
168 pos = base_end;
169 if pos >= b.len() {
170 urls.push(HttpUrlEntry {
171 url_base,
172 url_extensions: Vec::new(),
173 });
174 break;
175 }
176 let url_extension_count = b[pos] as usize;
177 pos += 1;
178 let mut url_extensions = Vec::with_capacity(url_extension_count);
179 for _ in 0..url_extension_count {
180 if pos >= b.len() {
181 break;
182 }
183 let ext_len = b[pos] as usize;
184 pos += 1;
185 let ext_end = pos + ext_len;
186 if ext_end > b.len() {
187 break;
188 }
189 url_extensions.push(&b[pos..ext_end]);
190 pos = ext_end;
191 }
192 urls.push(HttpUrlEntry {
193 url_base,
194 url_extensions,
195 });
196 }
197 SelectorKind::Http(HttpSelector { urls })
198 }
199}
200
201impl<'a> Parse<'a> for TransportProtocolDescriptor<'a> {
202 type Error = crate::error::Error;
203 fn parse(bytes: &'a [u8]) -> Result<Self> {
204 let body = descriptor_body(
205 bytes,
206 TAG,
207 "TransportProtocolDescriptor",
208 "unexpected tag for transport_protocol_descriptor",
209 )?;
210 if body.len() < PROTOCOL_ID_LEN + LABEL_LEN {
211 return Err(Error::InvalidDescriptor {
212 tag: TAG,
213 reason: "transport_protocol_descriptor body shorter than minimum 3 bytes",
214 });
215 }
216 let protocol_id = u16::from_be_bytes([body[0], body[1]]);
217 let transport_protocol_label = body[2];
218 let selector_bytes = &body[PROTOCOL_ID_LEN + LABEL_LEN..];
219 Ok(Self {
220 protocol_id,
221 transport_protocol_label,
222 selector_bytes,
223 })
224 }
225}
226
227impl Serialize for TransportProtocolDescriptor<'_> {
228 type Error = crate::error::Error;
229 fn serialized_len(&self) -> usize {
230 HEADER_LEN + PROTOCOL_ID_LEN + LABEL_LEN + self.selector_bytes.len()
231 }
232
233 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
234 let len = self.serialized_len();
235 let body_len = len - HEADER_LEN;
236 if body_len > u8::MAX as usize {
237 return Err(Error::InvalidDescriptor {
238 tag: TAG,
239 reason: "transport_protocol_descriptor body exceeds 255 bytes",
240 });
241 }
242 if buf.len() < len {
243 return Err(Error::OutputBufferTooSmall {
244 need: len,
245 have: buf.len(),
246 });
247 }
248 buf[0] = TAG;
249 buf[1] = body_len as u8;
250 buf[2..4].copy_from_slice(&self.protocol_id.to_be_bytes());
251 buf[4] = self.transport_protocol_label;
252 buf[5..5 + self.selector_bytes.len()].copy_from_slice(self.selector_bytes);
253 Ok(len)
254 }
255}
256
257impl<'a> crate::traits::DescriptorDef<'a> for TransportProtocolDescriptor<'a> {
258 const TAG: u8 = TAG;
259 const NAME: &'static str = "TRANSPORT_PROTOCOL";
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265
266 fn build_oc_local() -> [u8; 7] {
268 [TAG, 5, 0x00, 0x01, 0x01, 0x00, 0xB4]
269 }
270
271 fn build_oc_remote() -> [u8; 13] {
273 [
274 TAG, 11, 0x00, 0x01, 0x01, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x04, ]
277 }
278
279 fn build_http() -> [u8; 16] {
281 [
282 TAG, 14, 0x00, 0x03, 0x01, 4, b'h', b't', b't', b'p', 1, 4, b'/', b'a', b'p', b'p',
284 ]
285 }
286
287 #[test]
288 fn parse_oc_local_selector() {
289 let bytes = build_oc_local();
290 let d = TransportProtocolDescriptor::parse(&bytes).unwrap();
291 assert_eq!(d.protocol_id, PROTOCOL_ID_OBJECT_CAROUSEL);
292 assert_eq!(d.transport_protocol_label, 0x01);
293 assert_eq!(d.selector_bytes, &[0x00, 0xB4]);
294 match d.selector() {
295 SelectorKind::ObjectCarousel(oc) => {
296 assert!(!oc.remote_connection);
297 assert!(oc.remote_connection_info.is_none());
298 assert_eq!(oc.component_tag, 0xB4);
299 }
300 other => panic!("expected ObjectCarousel, got {other:?}"),
301 }
302 }
303
304 #[test]
305 fn parse_oc_remote_selector() {
306 let bytes = build_oc_remote();
307 let d = TransportProtocolDescriptor::parse(&bytes).unwrap();
308 match d.selector() {
309 SelectorKind::ObjectCarousel(oc) => {
310 assert!(oc.remote_connection);
311 let rc = oc.remote_connection_info.unwrap();
312 assert_eq!(rc.original_network_id, 1);
313 assert_eq!(rc.transport_stream_id, 2);
314 assert_eq!(rc.service_id, 3);
315 assert_eq!(oc.component_tag, 0x04);
316 }
317 other => panic!("expected ObjectCarousel, got {other:?}"),
318 }
319 }
320
321 #[test]
322 fn parse_http_selector() {
323 let bytes = build_http();
324 let d = TransportProtocolDescriptor::parse(&bytes).unwrap();
325 assert_eq!(d.protocol_id, PROTOCOL_ID_HTTP);
326 match d.selector() {
327 SelectorKind::Http(http) => {
328 assert_eq!(http.urls.len(), 1);
329 assert_eq!(http.urls[0].url_base, b"http");
330 assert_eq!(http.urls[0].url_extensions.len(), 1);
331 assert_eq!(http.urls[0].url_extensions[0], b"/app");
332 }
333 other => panic!("expected Http, got {other:?}"),
334 }
335 }
336
337 #[test]
338 fn oc_remote_selector_missing_component_tag_is_unknown_not_panic() {
339 let bytes = [
343 TAG, 10, 0x00, 0x01, 0x01, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, ];
349 let d = TransportProtocolDescriptor::parse(&bytes).unwrap();
350 assert_eq!(d.selector_bytes.len(), 7); assert!(d.selector_bytes[0] & 0x80 != 0); assert!(matches!(d.selector(), SelectorKind::Unknown(_)));
353 }
354
355 #[test]
356 fn parse_unknown_protocol() {
357 let bytes = [TAG, 5, 0x01, 0x00, 0x02, 0xCA, 0xFE];
358 let d = TransportProtocolDescriptor::parse(&bytes).unwrap();
359 assert_eq!(d.protocol_id, 0x0100);
360 assert!(matches!(d.selector(), SelectorKind::Unknown(_)));
361 }
362
363 #[test]
364 fn serialize_round_trip_oc() {
365 let bytes = build_oc_local();
366 let d = TransportProtocolDescriptor::parse(&bytes).unwrap();
367 let mut buf = vec![0u8; d.serialized_len()];
368 d.serialize_into(&mut buf).unwrap();
369 assert_eq!(buf.as_slice(), &bytes[..]);
370 let re = TransportProtocolDescriptor::parse(&buf).unwrap();
371 assert_eq!(d, re);
372 }
373
374 #[test]
375 fn serialize_round_trip_http() {
376 let bytes = build_http();
377 let d = TransportProtocolDescriptor::parse(&bytes).unwrap();
378 let mut buf = vec![0u8; d.serialized_len()];
379 d.serialize_into(&mut buf).unwrap();
380 assert_eq!(buf.as_slice(), &bytes[..]);
381 let re = TransportProtocolDescriptor::parse(&buf).unwrap();
382 assert_eq!(d, re);
383 }
384
385 #[test]
386 fn serialize_round_trip_oc_remote() {
387 let bytes = build_oc_remote();
388 let d = TransportProtocolDescriptor::parse(&bytes).unwrap();
389 let mut buf = vec![0u8; d.serialized_len()];
390 d.serialize_into(&mut buf).unwrap();
391 assert_eq!(buf.as_slice(), &bytes[..]);
392 }
393}