1use super::{
13 ior::{Ior, NameComponent},
14 BIOP_MAGIC, BIOP_VERSION_MAJOR, BIOP_VERSION_MINOR, BYTE_ORDER_BIG_ENDIAN,
15 COMPRESSED_MODULE_DESCRIPTOR_TAG,
16};
17use crate::error::{Error, Result};
18use dvb_common::{Parse, Serialize};
19
20const BIOP_HEADER_LEN: usize = 12;
24const OBJECT_KEY_LEN_FIELD: usize = 1;
26const OBJECT_KIND_LEN_FIELD: usize = 4;
28const OBJECT_KIND_DATA_LEN: usize = 4;
30const OBJECT_INFO_LEN_FIELD: usize = 2;
32const SERVICE_CONTEXT_COUNT_FIELD: usize = 1;
34const SERVICE_CONTEXT_FIXED: usize = 6;
36const MESSAGE_BODY_LEN_FIELD: usize = 4;
38const BINDINGS_COUNT_FIELD: usize = 2;
40const BINDING_NAME_COUNT_FIELD: usize = 1;
42const BINDING_TYPE_FIELD: usize = 1;
44const BINDING_OBJ_INFO_LEN_FIELD: usize = 2;
46const FILE_CONTENT_LEN_FIELD: usize = 4;
48const FILE_CONTENT_SIZE_LEN: usize = 8;
50const MODULE_INFO_FIXED: usize = 12;
52const MODULE_TAPS_COUNT_FIELD: usize = 1;
54const MODULE_USER_INFO_LEN_FIELD: usize = 1;
56const SGI_DOWNLOAD_TAPS_COUNT_FIELD: usize = 1;
58const SGI_USER_INFO_LEN_FIELD: usize = 2;
60
61#[derive(Debug, Clone, PartialEq, Eq)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize))]
67pub struct Binding<'a> {
68 #[cfg_attr(feature = "serde", serde(borrow))]
70 pub name: Vec<NameComponent<'a>>,
71 pub binding_type: u8,
73 pub ior: Ior<'a>,
75 #[cfg_attr(feature = "serde", serde(borrow))]
77 pub object_info: &'a [u8],
78}
79
80impl<'a> Binding<'a> {
81 fn parse_from(bytes: &'a [u8], pos: usize, end: usize) -> Result<(Self, usize)> {
82 if pos + BINDING_NAME_COUNT_FIELD > end {
84 return Err(Error::BufferTooShort {
85 need: pos + BINDING_NAME_COUNT_FIELD,
86 have: end,
87 what: "Binding nameComponents_count",
88 });
89 }
90 let name_count = bytes[pos] as usize;
91 let mut cur = pos + BINDING_NAME_COUNT_FIELD;
92 let mut name = Vec::with_capacity(name_count.min(4));
93 for _ in 0..name_count {
94 let (nc, next) = NameComponent::parse_8bit(bytes, cur, end)?;
95 name.push(nc);
96 cur = next;
97 }
98
99 if cur + BINDING_TYPE_FIELD > end {
101 return Err(Error::BufferTooShort {
102 need: cur + BINDING_TYPE_FIELD,
103 have: end,
104 what: "Binding bindingType",
105 });
106 }
107 let binding_type = bytes[cur];
108 cur += BINDING_TYPE_FIELD;
109
110 let ior_slice = &bytes[cur..end];
113 let ior = Ior::parse(ior_slice)?;
114 let ior_len = ior.serialized_len();
115 cur += ior_len;
116
117 if cur + BINDING_OBJ_INFO_LEN_FIELD > end {
119 return Err(Error::BufferTooShort {
120 need: cur + BINDING_OBJ_INFO_LEN_FIELD,
121 have: end,
122 what: "Binding objectInfo_length",
123 });
124 }
125 let obj_info_len = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
126 cur += BINDING_OBJ_INFO_LEN_FIELD;
127 if cur + obj_info_len > end {
128 return Err(Error::SectionLengthOverflow {
129 declared: obj_info_len,
130 available: end - cur,
131 });
132 }
133 let object_info = &bytes[cur..cur + obj_info_len];
134 cur += obj_info_len;
135
136 Ok((
137 Binding {
138 name,
139 binding_type,
140 ior,
141 object_info,
142 },
143 cur,
144 ))
145 }
146
147 fn serialized_len(&self) -> usize {
148 let name_len: usize = self.name.iter().map(|n| n.serialized_len_8bit()).sum();
149 BINDING_NAME_COUNT_FIELD
150 + name_len
151 + BINDING_TYPE_FIELD
152 + self.ior.serialized_len()
153 + BINDING_OBJ_INFO_LEN_FIELD
154 + self.object_info.len()
155 }
156
157 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
158 let len = self.serialized_len();
159 if buf.len() < len {
160 return Err(Error::OutputBufferTooSmall {
161 need: len,
162 have: buf.len(),
163 });
164 }
165 if self.name.len() > u8::MAX as usize {
166 return Err(Error::SectionLengthOverflow {
167 declared: self.name.len(),
168 available: u8::MAX as usize,
169 });
170 }
171 buf[0] = self.name.len() as u8;
172 let mut pos = BINDING_NAME_COUNT_FIELD;
173 for nc in &self.name {
174 let written = nc.serialize_8bit(&mut buf[pos..])?;
175 pos += written;
176 }
177 buf[pos] = self.binding_type;
178 pos += BINDING_TYPE_FIELD;
179 let written = self.ior.serialize_into(&mut buf[pos..])?;
180 pos += written;
181 if self.object_info.len() > u16::MAX as usize {
182 return Err(Error::SectionLengthOverflow {
183 declared: self.object_info.len(),
184 available: u16::MAX as usize,
185 });
186 }
187 buf[pos..pos + 2].copy_from_slice(&(self.object_info.len() as u16).to_be_bytes());
188 pos += BINDING_OBJ_INFO_LEN_FIELD;
189 buf[pos..pos + self.object_info.len()].copy_from_slice(self.object_info);
190 pos += self.object_info.len();
191 Ok(pos)
192 }
193}
194
195fn parse_biop_header(bytes: &[u8]) -> Result<(&[u8], [u8; 4], usize, usize)> {
201 let total = bytes.len();
202 if total < BIOP_HEADER_LEN {
203 return Err(Error::BufferTooShort {
204 need: BIOP_HEADER_LEN,
205 have: total,
206 what: "BIOP message header",
207 });
208 }
209 let magic = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
210 if magic != BIOP_MAGIC {
211 return Err(Error::ReservedBitsViolation {
212 field: "BIOP magic",
213 reason: "must be 0x42494F50 (\"BIOP\")",
214 });
215 }
216 if bytes[4] != BIOP_VERSION_MAJOR || bytes[5] != BIOP_VERSION_MINOR {
217 return Err(Error::ReservedBitsViolation {
218 field: "biop_version",
219 reason: "must be 1.0",
220 });
221 }
222 if bytes[6] != BYTE_ORDER_BIG_ENDIAN {
223 return Err(Error::ReservedBitsViolation {
224 field: "byte_order",
225 reason: "must be 0x00 (big-endian) per DVB mandatory constraint",
226 });
227 }
228 let message_size = u32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]) as usize;
230 let end = BIOP_HEADER_LEN + message_size;
231 if total < end {
232 return Err(Error::SectionLengthOverflow {
233 declared: message_size,
234 available: total - BIOP_HEADER_LEN,
235 });
236 }
237 let mut pos = BIOP_HEADER_LEN;
238
239 if pos + OBJECT_KEY_LEN_FIELD > end {
241 return Err(Error::BufferTooShort {
242 need: pos + OBJECT_KEY_LEN_FIELD,
243 have: end,
244 what: "BIOP objectKey_length",
245 });
246 }
247 let obj_key_len = bytes[pos] as usize;
248 pos += OBJECT_KEY_LEN_FIELD;
249 if pos + obj_key_len > end {
250 return Err(Error::SectionLengthOverflow {
251 declared: obj_key_len,
252 available: end - pos,
253 });
254 }
255 let object_key = &bytes[pos..pos + obj_key_len];
256 pos += obj_key_len;
257
258 if pos + OBJECT_KIND_LEN_FIELD > end {
260 return Err(Error::BufferTooShort {
261 need: pos + OBJECT_KIND_LEN_FIELD,
262 have: end,
263 what: "BIOP objectKind_length",
264 });
265 }
266 let kind_len =
267 u32::from_be_bytes([bytes[pos], bytes[pos + 1], bytes[pos + 2], bytes[pos + 3]]) as usize;
268 pos += OBJECT_KIND_LEN_FIELD;
269 if kind_len != OBJECT_KIND_DATA_LEN {
270 return Err(Error::ValueOutOfRange {
271 field: "objectKind_length",
272 reason: "DVB BIOP objectKind must be exactly 4 bytes",
273 });
274 }
275 if pos + OBJECT_KIND_DATA_LEN > end {
276 return Err(Error::SectionLengthOverflow {
277 declared: OBJECT_KIND_DATA_LEN,
278 available: end - pos,
279 });
280 }
281 let mut kind_bytes = [0u8; 4];
282 kind_bytes.copy_from_slice(&bytes[pos..pos + 4]);
283 pos += OBJECT_KIND_DATA_LEN;
284
285 Ok((object_key, kind_bytes, message_size, pos))
286}
287
288fn parse_service_context_list(bytes: &[u8], pos: usize, end: usize) -> Result<(&[u8], usize)> {
291 if pos + SERVICE_CONTEXT_COUNT_FIELD > end {
292 return Err(Error::BufferTooShort {
293 need: pos + SERVICE_CONTEXT_COUNT_FIELD,
294 have: end,
295 what: "serviceContextList_count",
296 });
297 }
298 let count = bytes[pos] as usize;
299 let list_start = pos;
300 let mut cur = pos + SERVICE_CONTEXT_COUNT_FIELD;
301 for _ in 0..count {
302 if cur + SERVICE_CONTEXT_FIXED > end {
303 return Err(Error::BufferTooShort {
304 need: cur + SERVICE_CONTEXT_FIXED,
305 have: end,
306 what: "serviceContext entry",
307 });
308 }
309 let ctx_data_len = u16::from_be_bytes([bytes[cur + 4], bytes[cur + 5]]) as usize;
310 cur += SERVICE_CONTEXT_FIXED;
311 if cur + ctx_data_len > end {
312 return Err(Error::SectionLengthOverflow {
313 declared: ctx_data_len,
314 available: end - cur,
315 });
316 }
317 cur += ctx_data_len;
318 }
319 Ok((&bytes[list_start..cur], cur))
320}
321
322fn write_biop_header(buf: &mut [u8], message_size: u32) {
324 buf[0..4].copy_from_slice(&BIOP_MAGIC.to_be_bytes());
325 buf[4] = BIOP_VERSION_MAJOR;
326 buf[5] = BIOP_VERSION_MINOR;
327 buf[6] = BYTE_ORDER_BIG_ENDIAN;
328 buf[7] = 0x00; buf[8..12].copy_from_slice(&message_size.to_be_bytes());
330}
331
332#[derive(Debug, Clone, PartialEq, Eq)]
337#[cfg_attr(feature = "serde", derive(serde::Serialize))]
338pub struct DirectoryMessage<'a> {
339 pub object_kind: [u8; 4],
341 #[cfg_attr(feature = "serde", serde(borrow))]
343 pub object_key: &'a [u8],
344 #[cfg_attr(feature = "serde", serde(borrow))]
346 pub object_info: &'a [u8],
347 #[cfg_attr(feature = "serde", serde(borrow))]
349 pub service_context: &'a [u8],
350 pub bindings: Vec<Binding<'a>>,
352}
353
354impl<'a> DirectoryMessage<'a> {
355 pub fn is_service_gateway(&self) -> bool {
357 &self.object_kind == b"srg\0"
358 }
359
360 fn parse_from(
361 bytes: &'a [u8],
362 object_key: &'a [u8],
363 object_kind: [u8; 4],
364 pos: usize,
365 end: usize,
366 ) -> Result<Self> {
367 let mut cur = pos;
368
369 if cur + OBJECT_INFO_LEN_FIELD > end {
371 return Err(Error::BufferTooShort {
372 need: cur + OBJECT_INFO_LEN_FIELD,
373 have: end,
374 what: "DirectoryMessage objectInfo_length",
375 });
376 }
377 let obj_info_len = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
378 cur += OBJECT_INFO_LEN_FIELD;
379 if cur + obj_info_len > end {
380 return Err(Error::SectionLengthOverflow {
381 declared: obj_info_len,
382 available: end - cur,
383 });
384 }
385 let object_info = &bytes[cur..cur + obj_info_len];
386 cur += obj_info_len;
387
388 let (service_context, next) = parse_service_context_list(bytes, cur, end)?;
390 cur = next;
391
392 if cur + MESSAGE_BODY_LEN_FIELD > end {
394 return Err(Error::BufferTooShort {
395 need: cur + MESSAGE_BODY_LEN_FIELD,
396 have: end,
397 what: "DirectoryMessage messageBody_length",
398 });
399 }
400 let body_len =
401 u32::from_be_bytes([bytes[cur], bytes[cur + 1], bytes[cur + 2], bytes[cur + 3]])
402 as usize;
403 cur += MESSAGE_BODY_LEN_FIELD;
404 let body_end = cur + body_len;
405 if body_end > end {
406 return Err(Error::SectionLengthOverflow {
407 declared: body_len,
408 available: end - cur,
409 });
410 }
411
412 if cur + BINDINGS_COUNT_FIELD > body_end {
414 return Err(Error::BufferTooShort {
415 need: cur + BINDINGS_COUNT_FIELD,
416 have: body_end,
417 what: "DirectoryMessage bindings_count",
418 });
419 }
420 let bindings_count = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
421 cur += BINDINGS_COUNT_FIELD;
422
423 let mut bindings = Vec::with_capacity(bindings_count.min(256));
424 for _ in 0..bindings_count {
425 let (binding, next) = Binding::parse_from(bytes, cur, body_end)?;
426 bindings.push(binding);
427 cur = next;
428 }
429
430 Ok(DirectoryMessage {
431 object_kind,
432 object_key,
433 object_info,
434 service_context,
435 bindings,
436 })
437 }
438
439 fn body_len(&self) -> usize {
440 let bindings_len: usize = self.bindings.iter().map(|b| b.serialized_len()).sum();
441 BINDINGS_COUNT_FIELD + bindings_len
442 }
443
444 fn serialized_len_inner(&self) -> usize {
445 let key_part = OBJECT_KEY_LEN_FIELD
447 + self.object_key.len()
448 + OBJECT_KIND_LEN_FIELD
449 + OBJECT_KIND_DATA_LEN;
450 let info_part = OBJECT_INFO_LEN_FIELD + self.object_info.len();
451 let svc_ctx_part = self.service_context.len();
452 let body_part = MESSAGE_BODY_LEN_FIELD + self.body_len();
453 key_part + info_part + svc_ctx_part + body_part
454 }
455
456 pub fn serialized_len_total(&self) -> usize {
458 BIOP_HEADER_LEN + self.serialized_len_inner()
459 }
460
461 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
462 let inner_len = self.serialized_len_inner();
463 let total = BIOP_HEADER_LEN + inner_len;
464 if buf.len() < total {
465 return Err(Error::OutputBufferTooSmall {
466 need: total,
467 have: buf.len(),
468 });
469 }
470 if inner_len > u32::MAX as usize {
471 return Err(Error::SectionLengthOverflow {
472 declared: inner_len,
473 available: u32::MAX as usize,
474 });
475 }
476 write_biop_header(buf, inner_len as u32);
477 let mut pos = BIOP_HEADER_LEN;
478
479 if self.object_key.len() > u8::MAX as usize {
481 return Err(Error::SectionLengthOverflow {
482 declared: self.object_key.len(),
483 available: u8::MAX as usize,
484 });
485 }
486 buf[pos] = self.object_key.len() as u8;
487 pos += OBJECT_KEY_LEN_FIELD;
488 buf[pos..pos + self.object_key.len()].copy_from_slice(self.object_key);
489 pos += self.object_key.len();
490
491 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
493 pos += OBJECT_KIND_LEN_FIELD;
494 buf[pos..pos + 4].copy_from_slice(&self.object_kind);
495 pos += OBJECT_KIND_DATA_LEN;
496
497 if self.object_info.len() > u16::MAX as usize {
499 return Err(Error::SectionLengthOverflow {
500 declared: self.object_info.len(),
501 available: u16::MAX as usize,
502 });
503 }
504 buf[pos..pos + 2].copy_from_slice(&(self.object_info.len() as u16).to_be_bytes());
505 pos += OBJECT_INFO_LEN_FIELD;
506 buf[pos..pos + self.object_info.len()].copy_from_slice(self.object_info);
507 pos += self.object_info.len();
508
509 buf[pos..pos + self.service_context.len()].copy_from_slice(self.service_context);
511 pos += self.service_context.len();
512
513 let body_len = self.body_len();
515 if body_len > u32::MAX as usize {
516 return Err(Error::SectionLengthOverflow {
517 declared: body_len,
518 available: u32::MAX as usize,
519 });
520 }
521 buf[pos..pos + 4].copy_from_slice(&(body_len as u32).to_be_bytes());
522 pos += MESSAGE_BODY_LEN_FIELD;
523
524 if self.bindings.len() > u16::MAX as usize {
526 return Err(Error::SectionLengthOverflow {
527 declared: self.bindings.len(),
528 available: u16::MAX as usize,
529 });
530 }
531 buf[pos..pos + 2].copy_from_slice(&(self.bindings.len() as u16).to_be_bytes());
532 pos += BINDINGS_COUNT_FIELD;
533
534 for binding in &self.bindings {
535 let written = binding.serialize_into_buf(&mut buf[pos..])?;
536 pos += written;
537 }
538
539 Ok(total)
540 }
541}
542
543#[derive(Debug, Clone, PartialEq, Eq)]
550#[cfg_attr(feature = "serde", derive(serde::Serialize))]
551pub struct FileMessage<'a> {
552 #[cfg_attr(feature = "serde", serde(borrow))]
554 pub object_key: &'a [u8],
555 pub content_size: u64,
557 #[cfg_attr(feature = "serde", serde(borrow))]
559 pub object_info_extra: &'a [u8],
560 #[cfg_attr(feature = "serde", serde(borrow))]
562 pub service_context: &'a [u8],
563 #[cfg_attr(feature = "serde", serde(borrow))]
565 pub content: &'a [u8],
566}
567
568impl<'a> FileMessage<'a> {
569 fn parse_from(bytes: &'a [u8], object_key: &'a [u8], pos: usize, end: usize) -> Result<Self> {
570 let mut cur = pos;
571
572 if cur + OBJECT_INFO_LEN_FIELD > end {
574 return Err(Error::BufferTooShort {
575 need: cur + OBJECT_INFO_LEN_FIELD,
576 have: end,
577 what: "FileMessage objectInfo_length",
578 });
579 }
580 let obj_info_len = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
581 cur += OBJECT_INFO_LEN_FIELD;
582 if obj_info_len < FILE_CONTENT_SIZE_LEN {
583 return Err(Error::ValueOutOfRange {
584 field: "FileMessage.objectInfo_length",
585 reason: "FileMessage objectInfo must be at least 8 bytes (ContentSize)",
586 });
587 }
588 if cur + obj_info_len > end {
589 return Err(Error::SectionLengthOverflow {
590 declared: obj_info_len,
591 available: end - cur,
592 });
593 }
594 let content_size = u64::from_be_bytes([
595 bytes[cur],
596 bytes[cur + 1],
597 bytes[cur + 2],
598 bytes[cur + 3],
599 bytes[cur + 4],
600 bytes[cur + 5],
601 bytes[cur + 6],
602 bytes[cur + 7],
603 ]);
604 let object_info_extra = &bytes[cur + FILE_CONTENT_SIZE_LEN..cur + obj_info_len];
605 cur += obj_info_len;
606
607 let (service_context, next) = parse_service_context_list(bytes, cur, end)?;
609 cur = next;
610
611 if cur + MESSAGE_BODY_LEN_FIELD > end {
613 return Err(Error::BufferTooShort {
614 need: cur + MESSAGE_BODY_LEN_FIELD,
615 have: end,
616 what: "FileMessage messageBody_length",
617 });
618 }
619 let body_len =
620 u32::from_be_bytes([bytes[cur], bytes[cur + 1], bytes[cur + 2], bytes[cur + 3]])
621 as usize;
622 cur += MESSAGE_BODY_LEN_FIELD;
623 let body_end = cur + body_len;
624 if body_end > end {
625 return Err(Error::SectionLengthOverflow {
626 declared: body_len,
627 available: end - cur,
628 });
629 }
630
631 if cur + FILE_CONTENT_LEN_FIELD > body_end {
633 return Err(Error::BufferTooShort {
634 need: cur + FILE_CONTENT_LEN_FIELD,
635 have: body_end,
636 what: "FileMessage content_length",
637 });
638 }
639 let content_len =
640 u32::from_be_bytes([bytes[cur], bytes[cur + 1], bytes[cur + 2], bytes[cur + 3]])
641 as usize;
642 cur += FILE_CONTENT_LEN_FIELD;
643 if cur + content_len > body_end {
644 return Err(Error::SectionLengthOverflow {
645 declared: content_len,
646 available: body_end - cur,
647 });
648 }
649 let content = &bytes[cur..cur + content_len];
650
651 Ok(FileMessage {
652 object_key,
653 content_size,
654 object_info_extra,
655 service_context,
656 content,
657 })
658 }
659
660 fn serialized_len_inner(&self) -> usize {
661 let obj_info_total = FILE_CONTENT_SIZE_LEN + self.object_info_extra.len();
662 OBJECT_KEY_LEN_FIELD
663 + self.object_key.len()
664 + OBJECT_KIND_LEN_FIELD
665 + OBJECT_KIND_DATA_LEN
666 + OBJECT_INFO_LEN_FIELD
667 + obj_info_total
668 + self.service_context.len()
669 + MESSAGE_BODY_LEN_FIELD
670 + FILE_CONTENT_LEN_FIELD
671 + self.content.len()
672 }
673
674 pub fn serialized_len_total(&self) -> usize {
676 BIOP_HEADER_LEN + self.serialized_len_inner()
677 }
678
679 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
680 let inner_len = self.serialized_len_inner();
681 let total = BIOP_HEADER_LEN + inner_len;
682 if buf.len() < total {
683 return Err(Error::OutputBufferTooSmall {
684 need: total,
685 have: buf.len(),
686 });
687 }
688 write_biop_header(buf, inner_len as u32);
689 let mut pos = BIOP_HEADER_LEN;
690
691 if self.object_key.len() > u8::MAX as usize {
692 return Err(Error::SectionLengthOverflow {
693 declared: self.object_key.len(),
694 available: u8::MAX as usize,
695 });
696 }
697 buf[pos] = self.object_key.len() as u8;
698 pos += OBJECT_KEY_LEN_FIELD;
699 buf[pos..pos + self.object_key.len()].copy_from_slice(self.object_key);
700 pos += self.object_key.len();
701
702 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
704 pos += OBJECT_KIND_LEN_FIELD;
705 buf[pos..pos + 4].copy_from_slice(b"fil\0");
706 pos += OBJECT_KIND_DATA_LEN;
707
708 let obj_info_total = FILE_CONTENT_SIZE_LEN + self.object_info_extra.len();
710 if obj_info_total > u16::MAX as usize {
711 return Err(Error::SectionLengthOverflow {
712 declared: obj_info_total,
713 available: u16::MAX as usize,
714 });
715 }
716 buf[pos..pos + 2].copy_from_slice(&(obj_info_total as u16).to_be_bytes());
717 pos += OBJECT_INFO_LEN_FIELD;
718 buf[pos..pos + 8].copy_from_slice(&self.content_size.to_be_bytes());
719 pos += FILE_CONTENT_SIZE_LEN;
720 buf[pos..pos + self.object_info_extra.len()].copy_from_slice(self.object_info_extra);
721 pos += self.object_info_extra.len();
722
723 buf[pos..pos + self.service_context.len()].copy_from_slice(self.service_context);
725 pos += self.service_context.len();
726
727 let body_len = FILE_CONTENT_LEN_FIELD + self.content.len();
729 buf[pos..pos + 4].copy_from_slice(&(body_len as u32).to_be_bytes());
730 pos += MESSAGE_BODY_LEN_FIELD;
731 buf[pos..pos + 4].copy_from_slice(&(self.content.len() as u32).to_be_bytes());
732 pos += FILE_CONTENT_LEN_FIELD;
733 buf[pos..pos + self.content.len()].copy_from_slice(self.content);
734
735 Ok(total)
736 }
737}
738
739#[derive(Debug, Clone, PartialEq, Eq)]
744#[cfg_attr(feature = "serde", derive(serde::Serialize))]
745#[non_exhaustive]
746pub enum BiopMessage<'a> {
747 Directory(DirectoryMessage<'a>),
749 File(FileMessage<'a>),
751 ServiceGateway(DirectoryMessage<'a>),
753 #[cfg_attr(feature = "serde", serde(borrow))]
755 Stream(&'a [u8]),
756 #[cfg_attr(feature = "serde", serde(borrow))]
758 StreamEvent(&'a [u8]),
759}
760
761impl<'a> BiopMessage<'a> {
762 pub fn parse_at(bytes: &'a [u8]) -> Result<(Self, usize)> {
767 let (object_key, kind_bytes, message_size, pos) = parse_biop_header(bytes)?;
768 let consumed = BIOP_HEADER_LEN + message_size;
769 let end = consumed;
770
771 let msg = match &kind_bytes {
772 b"dir\0" => {
773 let dm = DirectoryMessage::parse_from(bytes, object_key, kind_bytes, pos, end)?;
774 BiopMessage::Directory(dm)
775 }
776 b"srg\0" => {
777 let dm = DirectoryMessage::parse_from(bytes, object_key, kind_bytes, pos, end)?;
778 BiopMessage::ServiceGateway(dm)
779 }
780 b"fil\0" => {
781 let fm = FileMessage::parse_from(bytes, object_key, pos, end)?;
782 BiopMessage::File(fm)
783 }
784 b"str\0" => BiopMessage::Stream(&bytes[pos..end]),
785 b"ste\0" => BiopMessage::StreamEvent(&bytes[pos..end]),
786 _ => {
787 BiopMessage::Stream(&bytes[pos..end])
789 }
790 };
791
792 Ok((msg, consumed))
793 }
794
795 fn serialized_len_total(&self) -> usize {
796 match self {
797 Self::Directory(d) | Self::ServiceGateway(d) => d.serialized_len_total(),
798 Self::File(f) => f.serialized_len_total(),
799 Self::Stream(raw) | Self::StreamEvent(raw) => BIOP_HEADER_LEN + raw.len(),
800 }
801 }
802
803 fn kind_bytes(&self) -> [u8; 4] {
804 match self {
805 Self::Directory(_) => *b"dir\0",
806 Self::File(_) => *b"fil\0",
807 Self::ServiceGateway(_) => *b"srg\0",
808 Self::Stream(_) => *b"str\0",
809 Self::StreamEvent(_) => *b"ste\0",
810 }
811 }
812}
813
814impl Serialize for BiopMessage<'_> {
815 type Error = crate::error::Error;
816
817 fn serialized_len(&self) -> usize {
818 self.serialized_len_total()
819 }
820
821 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
822 let len = self.serialized_len_total();
823 if buf.len() < len {
824 return Err(Error::OutputBufferTooSmall {
825 need: len,
826 have: buf.len(),
827 });
828 }
829 match self {
830 Self::Directory(d) | Self::ServiceGateway(d) => {
831 d.serialize_into_buf(buf)?;
832 }
833 Self::File(f) => {
834 f.serialize_into_buf(buf)?;
835 }
836 Self::Stream(raw) | Self::StreamEvent(raw) => {
837 let kind = self.kind_bytes();
839 let inner_len = OBJECT_KEY_LEN_FIELD + OBJECT_KIND_LEN_FIELD + OBJECT_KIND_DATA_LEN
841 + raw.len();
842 write_biop_header(buf, inner_len as u32);
843 let mut pos = BIOP_HEADER_LEN;
844 buf[pos] = 0; pos += OBJECT_KEY_LEN_FIELD;
846 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
847 pos += OBJECT_KIND_LEN_FIELD;
848 buf[pos..pos + 4].copy_from_slice(&kind);
849 pos += OBJECT_KIND_DATA_LEN;
850 buf[pos..pos + raw.len()].copy_from_slice(raw);
851 }
852 }
853 Ok(len)
854 }
855}
856
857#[derive(Debug, Clone, PartialEq, Eq)]
862#[cfg_attr(feature = "serde", derive(serde::Serialize))]
863pub struct ModuleInfo<'a> {
864 pub module_timeout: u32,
866 pub block_timeout: u32,
868 pub min_block_time: u32,
870 #[cfg_attr(feature = "serde", serde(borrow))]
872 pub taps: Vec<super::ior::Tap<'a>>,
873 #[cfg_attr(feature = "serde", serde(borrow))]
875 pub user_info: &'a [u8],
876}
877
878impl<'a> ModuleInfo<'a> {
879 pub fn descriptors(&self) -> impl Iterator<Item = (u8, &[u8])> {
883 DescriptorIter {
884 data: self.user_info,
885 pos: 0,
886 }
887 }
888
889 pub fn compressed_module_descriptor(&self) -> Option<CompressedModuleDescriptor<'_>> {
892 for (tag, data) in self.descriptors() {
893 if tag == COMPRESSED_MODULE_DESCRIPTOR_TAG {
894 return Some(CompressedModuleDescriptor { body: data });
895 }
896 }
897 None
898 }
899}
900
901struct DescriptorIter<'a> {
902 data: &'a [u8],
903 pos: usize,
904}
905
906impl<'a> Iterator for DescriptorIter<'a> {
907 type Item = (u8, &'a [u8]);
908 fn next(&mut self) -> Option<Self::Item> {
909 let end = self.data.len();
910 if self.pos + 2 > end {
911 return None;
912 }
913 let tag = self.data[self.pos];
914 let len = self.data[self.pos + 1] as usize;
915 self.pos += 2;
916 if self.pos + len > end {
917 return None;
918 }
919 let d = &self.data[self.pos..self.pos + len];
920 self.pos += len;
921 Some((tag, d))
922 }
923}
924
925impl<'a> Parse<'a> for ModuleInfo<'a> {
926 type Error = crate::error::Error;
927
928 fn parse(bytes: &'a [u8]) -> Result<Self> {
929 let end = bytes.len();
930 if end < MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD {
931 return Err(Error::BufferTooShort {
932 need: MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD,
933 have: end,
934 what: "ModuleInfo fixed fields",
935 });
936 }
937 let module_timeout = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
938 let block_timeout = u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
939 let min_block_time = u32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]);
940 let taps_count = bytes[12] as usize;
941 let mut pos = MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD;
942
943 let mut taps = Vec::with_capacity(taps_count.min(8));
944 for _ in 0..taps_count {
945 let (tap, next) = super::ior::Tap::parse_from(bytes, pos, end)?;
946 taps.push(tap);
947 pos = next;
948 }
949
950 if pos + MODULE_USER_INFO_LEN_FIELD > end {
951 return Err(Error::BufferTooShort {
952 need: pos + MODULE_USER_INFO_LEN_FIELD,
953 have: end,
954 what: "ModuleInfo UserInfoLength",
955 });
956 }
957 let user_info_len = bytes[pos] as usize;
958 pos += MODULE_USER_INFO_LEN_FIELD;
959 if pos + user_info_len > end {
960 return Err(Error::SectionLengthOverflow {
961 declared: user_info_len,
962 available: end - pos,
963 });
964 }
965 let user_info = &bytes[pos..pos + user_info_len];
966
967 Ok(ModuleInfo {
968 module_timeout,
969 block_timeout,
970 min_block_time,
971 taps,
972 user_info,
973 })
974 }
975}
976
977impl Serialize for ModuleInfo<'_> {
978 type Error = crate::error::Error;
979
980 fn serialized_len(&self) -> usize {
981 let taps_len: usize = self.taps.iter().map(|t| t.serialized_len()).sum();
982 MODULE_INFO_FIXED
983 + MODULE_TAPS_COUNT_FIELD
984 + taps_len
985 + MODULE_USER_INFO_LEN_FIELD
986 + self.user_info.len()
987 }
988
989 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
990 let len = self.serialized_len();
991 if buf.len() < len {
992 return Err(Error::OutputBufferTooSmall {
993 need: len,
994 have: buf.len(),
995 });
996 }
997 buf[0..4].copy_from_slice(&self.module_timeout.to_be_bytes());
998 buf[4..8].copy_from_slice(&self.block_timeout.to_be_bytes());
999 buf[8..12].copy_from_slice(&self.min_block_time.to_be_bytes());
1000 if self.taps.len() > u8::MAX as usize {
1001 return Err(Error::SectionLengthOverflow {
1002 declared: self.taps.len(),
1003 available: u8::MAX as usize,
1004 });
1005 }
1006 buf[12] = self.taps.len() as u8;
1007 let mut pos = MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD;
1008 for tap in &self.taps {
1009 let written = tap.serialize_into_buf(&mut buf[pos..])?;
1010 pos += written;
1011 }
1012 if self.user_info.len() > u8::MAX as usize {
1013 return Err(Error::SectionLengthOverflow {
1014 declared: self.user_info.len(),
1015 available: u8::MAX as usize,
1016 });
1017 }
1018 buf[pos] = self.user_info.len() as u8;
1019 pos += MODULE_USER_INFO_LEN_FIELD;
1020 buf[pos..pos + self.user_info.len()].copy_from_slice(self.user_info);
1021 pos += self.user_info.len();
1022 Ok(pos)
1023 }
1024}
1025
1026#[derive(Debug, Clone, PartialEq, Eq)]
1034#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1035pub struct CompressedModuleDescriptor<'a> {
1036 #[cfg_attr(feature = "serde", serde(borrow))]
1038 pub body: &'a [u8],
1039}
1040
1041#[cfg(feature = "flate2")]
1046pub fn decompress_zlib(data: &[u8]) -> Result<Vec<u8>> {
1047 use std::io::Read;
1048 let mut decoder = flate2::read::ZlibDecoder::new(data);
1049 let mut out = Vec::new();
1050 decoder
1051 .read_to_end(&mut out)
1052 .map_err(|e| Error::ReservedBitsViolation {
1053 field: "compressed_module_descriptor body",
1054 reason: if e.kind() == std::io::ErrorKind::InvalidData {
1055 "zlib decompression failed: invalid data"
1056 } else {
1057 "zlib decompression failed"
1058 },
1059 })?;
1060 Ok(out)
1061}
1062
1063#[derive(Debug, Clone, PartialEq, Eq)]
1071#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1072pub struct ServiceGatewayInfo<'a> {
1073 pub ior: Ior<'a>,
1075 #[cfg_attr(feature = "serde", serde(borrow))]
1078 pub download_taps: &'a [u8],
1079 #[cfg_attr(feature = "serde", serde(borrow))]
1081 pub service_context: &'a [u8],
1082 #[cfg_attr(feature = "serde", serde(borrow))]
1084 pub user_info: &'a [u8],
1085}
1086
1087impl<'a> ServiceGatewayInfo<'a> {
1088 pub fn parse(bytes: &'a [u8]) -> Result<Self> {
1090 let end = bytes.len();
1091 let ior = Ior::parse(bytes)?;
1092 let mut pos = ior.serialized_len();
1093
1094 if pos + SGI_DOWNLOAD_TAPS_COUNT_FIELD > end {
1097 return Err(Error::BufferTooShort {
1098 need: pos + SGI_DOWNLOAD_TAPS_COUNT_FIELD,
1099 have: end,
1100 what: "ServiceGatewayInfo downloadTaps_count",
1101 });
1102 }
1103 let tap_count = bytes[pos] as usize;
1104 let dl_taps_start = pos;
1105 pos += SGI_DOWNLOAD_TAPS_COUNT_FIELD;
1106 for _ in 0..tap_count {
1107 let (_, next) = super::ior::Tap::parse_from(bytes, pos, end)?;
1108 pos = next;
1109 }
1110 let download_taps = &bytes[dl_taps_start..pos];
1111
1112 let (service_context, next) = parse_service_context_list(bytes, pos, end)?;
1114 pos = next;
1115
1116 if pos + SGI_USER_INFO_LEN_FIELD > end {
1118 return Err(Error::BufferTooShort {
1119 need: pos + SGI_USER_INFO_LEN_FIELD,
1120 have: end,
1121 what: "ServiceGatewayInfo userInfoLength",
1122 });
1123 }
1124 let ui_len = u16::from_be_bytes([bytes[pos], bytes[pos + 1]]) as usize;
1125 pos += SGI_USER_INFO_LEN_FIELD;
1126 if pos + ui_len > end {
1127 return Err(Error::SectionLengthOverflow {
1128 declared: ui_len,
1129 available: end - pos,
1130 });
1131 }
1132 let user_info = &bytes[pos..pos + ui_len];
1133
1134 Ok(ServiceGatewayInfo {
1135 ior,
1136 download_taps,
1137 service_context,
1138 user_info,
1139 })
1140 }
1141
1142 pub fn to_bytes(&self) -> Vec<u8> {
1145 let len = self.ior.serialized_len()
1146 + self.download_taps.len()
1147 + self.service_context.len()
1148 + SGI_USER_INFO_LEN_FIELD
1149 + self.user_info.len();
1150 let mut buf = vec![0u8; len];
1151 let mut pos = 0;
1152 let written = self
1153 .ior
1154 .serialize_into(&mut buf[pos..])
1155 .expect("IOR serialize");
1156 pos += written;
1157 buf[pos..pos + self.download_taps.len()].copy_from_slice(self.download_taps);
1158 pos += self.download_taps.len();
1159 buf[pos..pos + self.service_context.len()].copy_from_slice(self.service_context);
1160 pos += self.service_context.len();
1161 buf[pos..pos + 2].copy_from_slice(&(self.user_info.len() as u16).to_be_bytes());
1162 pos += SGI_USER_INFO_LEN_FIELD;
1163 buf[pos..pos + self.user_info.len()].copy_from_slice(self.user_info);
1164 buf
1165 }
1166}
1167
1168#[cfg(test)]
1171mod tests {
1172 use super::*;
1173 use crate::carousel::biop::BINDING_NOBJECT;
1174 use dvb_common::Parse;
1175
1176 fn sample_file_message(key: &'static [u8], content: &'static [u8]) -> BiopMessage<'static> {
1178 BiopMessage::File(FileMessage {
1179 object_key: key,
1180 content_size: content.len() as u64,
1181 object_info_extra: &[],
1182 service_context: &[0x00], content,
1184 })
1185 }
1186
1187 fn sample_dir_message() -> BiopMessage<'static> {
1189 use crate::carousel::biop::ior::{
1190 BiopProfileBody, ConnBinder, ObjectLocation, TaggedProfile,
1191 };
1192 let ior = crate::carousel::biop::ior::Ior {
1193 type_id: b"fil\0",
1194 profiles: vec![TaggedProfile::Biop(BiopProfileBody {
1195 object_location: ObjectLocation {
1196 carousel_id: 0xAB,
1197 module_id: 2,
1198 version_major: 1,
1199 version_minor: 0,
1200 object_key: &[0x02],
1201 },
1202 conn_binder: ConnBinder { taps: vec![] },
1203 extra: vec![],
1204 })],
1205 };
1206 BiopMessage::Directory(DirectoryMessage {
1207 object_kind: *b"dir\0",
1208 object_key: &[0x01],
1209 object_info: &[],
1210 service_context: &[0x00], bindings: vec![Binding {
1212 name: vec![NameComponent {
1213 id: b"index.html",
1214 kind: b"fil\0",
1215 }],
1216 binding_type: BINDING_NOBJECT,
1217 ior,
1218 object_info: &[],
1219 }],
1220 })
1221 }
1222
1223 #[test]
1224 fn file_message_round_trip() {
1225 let content: &[u8] = b"Hello, BIOP!";
1226 let msg = sample_file_message(&[0x01], content);
1227 let mut buf = vec![0u8; msg.serialized_len()];
1228 msg.serialize_into(&mut buf).unwrap();
1229 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
1230 assert_eq!(consumed, buf.len());
1231 assert_eq!(parsed, msg);
1232 let mut buf2 = vec![0u8; parsed.serialized_len()];
1234 parsed.serialize_into(&mut buf2).unwrap();
1235 assert_eq!(buf, buf2);
1236 }
1237
1238 #[test]
1239 fn directory_message_round_trip() {
1240 let msg = sample_dir_message();
1241 let mut buf = vec![0u8; msg.serialized_len()];
1242 msg.serialize_into(&mut buf).unwrap();
1243 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
1244 assert_eq!(consumed, buf.len());
1245 assert_eq!(parsed, msg);
1246 let mut buf2 = vec![0u8; parsed.serialized_len()];
1247 parsed.serialize_into(&mut buf2).unwrap();
1248 assert_eq!(buf, buf2, "Directory message byte-exact re-serialize");
1249 }
1250
1251 #[test]
1252 fn module_info_round_trip() {
1253 use crate::carousel::biop::ior::Tap;
1254 let info = ModuleInfo {
1255 module_timeout: 0x00FFFFFF,
1256 block_timeout: 0x00FFFFFF,
1257 min_block_time: 0x00000064,
1258 taps: vec![Tap {
1259 id: 0,
1260 use_: 0x0017,
1261 association_tag: 0x0042,
1262 selector: &[],
1263 }],
1264 user_info: &[],
1265 };
1266 let mut buf = vec![0u8; info.serialized_len()];
1267 info.serialize_into(&mut buf).unwrap();
1268 let parsed = ModuleInfo::parse(&buf).unwrap();
1269 assert_eq!(parsed, info);
1270 let mut buf2 = vec![0u8; parsed.serialized_len()];
1271 parsed.serialize_into(&mut buf2).unwrap();
1272 assert_eq!(buf, buf2, "ModuleInfo byte-exact re-serialize");
1273 }
1274
1275 #[test]
1276 fn module_info_byte_anchor() {
1277 use crate::carousel::biop::ior::Tap;
1278 #[rustfmt::skip]
1283 let expected: &[u8] = &[
1284 0x00, 0x0F, 0x42, 0x40, 0x00, 0x0F, 0x42, 0x40, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x47, 0x00, 0x00, ];
1294 let info = ModuleInfo {
1295 module_timeout: 0x000F4240,
1296 block_timeout: 0x000F4240,
1297 min_block_time: 0x00000064,
1298 taps: vec![Tap {
1299 id: 0,
1300 use_: 0x0017,
1301 association_tag: 0x0047,
1302 selector: &[],
1303 }],
1304 user_info: &[],
1305 };
1306 let mut buf = vec![0u8; info.serialized_len()];
1307 info.serialize_into(&mut buf).unwrap();
1308 assert_eq!(buf.as_slice(), expected);
1309 let parsed = ModuleInfo::parse(expected).unwrap();
1310 assert_eq!(parsed, info);
1311 }
1312
1313 #[test]
1314 fn sgi_byte_anchor_m6() {
1315 #[rustfmt::skip]
1318 let raw: &[u8] = &[
1319 0x00, 0x00, 0x00, 0x04, 0x73, 0x72, 0x67, 0x00, 0x00, 0x00, 0x00, 0x01, 0x49, 0x53, 0x4F, 0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x02, 0x49, 0x53, 0x4F, 0x50, 0x0A, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x49, 0x53, 0x4F, 0x40, 0x12, 0x01, 0x00, 0x00, 0x00, 0x16, 0x00, 0x47, 0x0A, 0x00, 0x01, 0x80, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF,
1337 0x00, 0x00, 0x00, 0x00, ];
1341 assert_eq!(raw.len(), 64);
1342
1343 let sgi = ServiceGatewayInfo::parse(raw).unwrap();
1344
1345 assert_eq!(sgi.ior.type_id, b"srg\0");
1347 assert_eq!(sgi.ior.profiles.len(), 1);
1348 let bp = sgi.ior.biop_profile().unwrap();
1349 assert_eq!(bp.object_location.carousel_id, 0xAB);
1350 assert_eq!(bp.object_location.module_id, 1);
1351 assert_eq!(bp.object_location.version_major, 1);
1352 assert_eq!(bp.object_location.version_minor, 0);
1353 assert_eq!(bp.object_location.object_key, &[0x01]);
1354 assert_eq!(bp.conn_binder.taps.len(), 1);
1355 let tap = &bp.conn_binder.taps[0];
1356 assert_eq!(tap.use_, 0x0016);
1357 assert_eq!(tap.association_tag, 0x47);
1358 assert_eq!(tap.transaction_id(), Some(0x80000002));
1359 assert_eq!(tap.timeout(), Some(0xFFFFFFFF));
1360
1361 let out = sgi.to_bytes();
1363 assert_eq!(out.len(), 64, "SGI serialized length");
1364 assert_eq!(out.as_slice(), raw, "SGI byte-exact round-trip");
1365 }
1366
1367 #[cfg(feature = "serde")]
1368 #[test]
1369 fn biop_serde_round_trip() {
1370 let content: &[u8] = b"test content";
1371 let msg = sample_file_message(&[0x01], content);
1372 let json = serde_json::to_string(&msg).unwrap();
1373 assert!(json.contains("content_size"));
1374 }
1375
1376 #[cfg(feature = "flate2")]
1377 #[test]
1378 fn zlib_round_trip() {
1379 use flate2::{write::ZlibEncoder, Compression};
1380 use std::io::Write;
1381
1382 let original = b"Hello, compressed BIOP world! ".repeat(10);
1383 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
1384 encoder.write_all(&original).unwrap();
1385 let compressed = encoder.finish().unwrap();
1386
1387 let decompressed = decompress_zlib(&compressed).unwrap();
1388 assert_eq!(decompressed.as_slice(), original.as_slice());
1389 }
1390}