1use alloc::vec;
13use alloc::vec::Vec;
14
15use super::{
16 ior::{Ior, NameComponent},
17 BINDING_NCONTEXT, BINDING_NOBJECT, BIOP_MAGIC, BIOP_VERSION_MAJOR, BIOP_VERSION_MINOR,
18 BYTE_ORDER_BIG_ENDIAN, COMPRESSED_MODULE_DESCRIPTOR_TAG,
19};
20use crate::error::{Error, Result};
21use dvb_common::{Parse, Serialize};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize))]
30#[non_exhaustive]
31pub enum BindingType {
32 NObject,
34 NContext,
36 Reserved(u8),
38}
39
40impl BindingType {
41 #[must_use]
42 pub fn from_u8(v: u8) -> Self {
45 match v {
46 BINDING_NOBJECT => Self::NObject,
47 BINDING_NCONTEXT => Self::NContext,
48 v => Self::Reserved(v),
49 }
50 }
51
52 #[must_use]
53 pub fn to_u8(self) -> u8 {
55 match self {
56 Self::NObject => BINDING_NOBJECT,
57 Self::NContext => BINDING_NCONTEXT,
58 Self::Reserved(v) => v,
59 }
60 }
61
62 #[must_use]
63 pub fn name(self) -> &'static str {
65 match self {
66 Self::NObject => "nobject",
67 Self::NContext => "ncontext",
68 Self::Reserved(_) => "reserved",
69 }
70 }
71}
72dvb_common::impl_spec_display!(BindingType, Reserved);
73
74const BIOP_HEADER_LEN: usize = 12;
78const OBJECT_KEY_LEN_FIELD: usize = 1;
80const OBJECT_KIND_LEN_FIELD: usize = 4;
82const OBJECT_KIND_DATA_LEN: usize = 4;
84const OBJECT_INFO_LEN_FIELD: usize = 2;
86const SERVICE_CONTEXT_COUNT_FIELD: usize = 1;
88const SERVICE_CONTEXT_FIXED: usize = 6;
90const MESSAGE_BODY_LEN_FIELD: usize = 4;
92const BINDINGS_COUNT_FIELD: usize = 2;
94const BINDING_NAME_COUNT_FIELD: usize = 1;
96const BINDING_TYPE_FIELD: usize = 1;
98const BINDING_OBJ_INFO_LEN_FIELD: usize = 2;
100const FILE_CONTENT_LEN_FIELD: usize = 4;
102const FILE_CONTENT_SIZE_LEN: usize = 8;
104const STREAM_ADESC_LEN_FIELD: usize = 1;
106const STREAM_INFO_FIXED: usize = 9;
108const STREAM_TAPS_COUNT_FIELD: usize = 1;
110const STREAM_EVENT_NAMES_COUNT_FIELD: usize = 2;
112const STREAM_EVENT_NAME_LEN_FIELD: usize = 1;
114const STREAM_EVENT_IDS_COUNT_FIELD: usize = 1;
116const STREAM_EVENT_ID_LEN: usize = 2;
118const MODULE_INFO_FIXED: usize = 12;
120const MODULE_TAPS_COUNT_FIELD: usize = 1;
122const MODULE_USER_INFO_LEN_FIELD: usize = 1;
124const SGI_DOWNLOAD_TAPS_COUNT_FIELD: usize = 1;
126const SGI_USER_INFO_LEN_FIELD: usize = 2;
128
129#[derive(Debug, Clone, PartialEq, Eq)]
134#[cfg_attr(feature = "serde", derive(serde::Serialize))]
135pub struct Binding<'a> {
136 #[cfg_attr(feature = "serde", serde(borrow))]
138 pub name: Vec<NameComponent<'a>>,
139 pub binding_type: BindingType,
141 pub ior: Ior<'a>,
143 #[cfg_attr(feature = "serde", serde(borrow))]
145 pub object_info: &'a [u8],
146}
147
148impl<'a> Binding<'a> {
149 fn parse_from(bytes: &'a [u8], pos: usize, end: usize) -> Result<(Self, usize)> {
150 if pos + BINDING_NAME_COUNT_FIELD > end {
152 return Err(Error::BufferTooShort {
153 need: pos + BINDING_NAME_COUNT_FIELD,
154 have: end,
155 what: "Binding nameComponents_count",
156 });
157 }
158 let name_count = bytes[pos] as usize;
159 let mut cur = pos + BINDING_NAME_COUNT_FIELD;
160 let mut name = Vec::with_capacity(name_count.min(4));
161 for _ in 0..name_count {
162 let (nc, next) = NameComponent::parse_8bit(bytes, cur, end)?;
163 name.push(nc);
164 cur = next;
165 }
166
167 if cur + BINDING_TYPE_FIELD > end {
169 return Err(Error::BufferTooShort {
170 need: cur + BINDING_TYPE_FIELD,
171 have: end,
172 what: "Binding bindingType",
173 });
174 }
175 let binding_type = BindingType::from_u8(bytes[cur]);
176 cur += BINDING_TYPE_FIELD;
177
178 let ior_slice = &bytes[cur..end];
181 let ior = Ior::parse(ior_slice)?;
182 let ior_len = ior.serialized_len();
183 cur += ior_len;
184
185 if cur + BINDING_OBJ_INFO_LEN_FIELD > end {
187 return Err(Error::BufferTooShort {
188 need: cur + BINDING_OBJ_INFO_LEN_FIELD,
189 have: end,
190 what: "Binding objectInfo_length",
191 });
192 }
193 let obj_info_len = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
194 cur += BINDING_OBJ_INFO_LEN_FIELD;
195 if cur + obj_info_len > end {
196 return Err(Error::SectionLengthOverflow {
197 declared: obj_info_len,
198 available: end - cur,
199 });
200 }
201 let object_info = &bytes[cur..cur + obj_info_len];
202 cur += obj_info_len;
203
204 Ok((
205 Binding {
206 name,
207 binding_type,
208 ior,
209 object_info,
210 },
211 cur,
212 ))
213 }
214
215 fn serialized_len(&self) -> usize {
216 let name_len: usize = self.name.iter().map(|n| n.serialized_len_8bit()).sum();
217 BINDING_NAME_COUNT_FIELD
218 + name_len
219 + BINDING_TYPE_FIELD
220 + self.ior.serialized_len()
221 + BINDING_OBJ_INFO_LEN_FIELD
222 + self.object_info.len()
223 }
224
225 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
226 let len = self.serialized_len();
227 if buf.len() < len {
228 return Err(Error::OutputBufferTooSmall {
229 need: len,
230 have: buf.len(),
231 });
232 }
233 if self.name.len() > u8::MAX as usize {
234 return Err(Error::SectionLengthOverflow {
235 declared: self.name.len(),
236 available: u8::MAX as usize,
237 });
238 }
239 buf[0] = self.name.len() as u8;
240 let mut pos = BINDING_NAME_COUNT_FIELD;
241 for nc in &self.name {
242 let written = nc.serialize_8bit(&mut buf[pos..])?;
243 pos += written;
244 }
245 buf[pos] = self.binding_type.to_u8();
246 pos += BINDING_TYPE_FIELD;
247 let written = self.ior.serialize_into(&mut buf[pos..])?;
248 pos += written;
249 if self.object_info.len() > u16::MAX as usize {
250 return Err(Error::SectionLengthOverflow {
251 declared: self.object_info.len(),
252 available: u16::MAX as usize,
253 });
254 }
255 buf[pos..pos + 2].copy_from_slice(&(self.object_info.len() as u16).to_be_bytes());
256 pos += BINDING_OBJ_INFO_LEN_FIELD;
257 buf[pos..pos + self.object_info.len()].copy_from_slice(self.object_info);
258 pos += self.object_info.len();
259 Ok(pos)
260 }
261}
262
263#[derive(Debug, Clone, PartialEq, Eq)]
268#[cfg_attr(feature = "serde", derive(serde::Serialize))]
269pub struct ServiceContext<'a> {
270 pub context_id: u32,
272 #[cfg_attr(feature = "serde", serde(borrow))]
274 pub data: &'a [u8],
275}
276
277fn parse_biop_header(bytes: &[u8]) -> Result<(&[u8], [u8; 4], usize, usize)> {
283 let total = bytes.len();
284 if total < BIOP_HEADER_LEN {
285 return Err(Error::BufferTooShort {
286 need: BIOP_HEADER_LEN,
287 have: total,
288 what: "BIOP message header",
289 });
290 }
291 let magic = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
292 if magic != BIOP_MAGIC {
293 return Err(Error::ReservedBitsViolation {
294 field: "BIOP magic",
295 reason: "must be 0x42494F50 (\"BIOP\")",
296 });
297 }
298 if bytes[4] != BIOP_VERSION_MAJOR || bytes[5] != BIOP_VERSION_MINOR {
299 return Err(Error::ReservedBitsViolation {
300 field: "biop_version",
301 reason: "must be 1.0",
302 });
303 }
304 if bytes[6] != BYTE_ORDER_BIG_ENDIAN {
305 return Err(Error::ReservedBitsViolation {
306 field: "byte_order",
307 reason: "must be 0x00 (big-endian) per DVB mandatory constraint",
308 });
309 }
310 let message_size = u32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]) as usize;
312 let end = BIOP_HEADER_LEN + message_size;
313 if total < end {
314 return Err(Error::SectionLengthOverflow {
315 declared: message_size,
316 available: total - BIOP_HEADER_LEN,
317 });
318 }
319 let mut pos = BIOP_HEADER_LEN;
320
321 if pos + OBJECT_KEY_LEN_FIELD > end {
323 return Err(Error::BufferTooShort {
324 need: pos + OBJECT_KEY_LEN_FIELD,
325 have: end,
326 what: "BIOP objectKey_length",
327 });
328 }
329 let obj_key_len = bytes[pos] as usize;
330 pos += OBJECT_KEY_LEN_FIELD;
331 if pos + obj_key_len > end {
332 return Err(Error::SectionLengthOverflow {
333 declared: obj_key_len,
334 available: end - pos,
335 });
336 }
337 let object_key = &bytes[pos..pos + obj_key_len];
338 pos += obj_key_len;
339
340 if pos + OBJECT_KIND_LEN_FIELD > end {
342 return Err(Error::BufferTooShort {
343 need: pos + OBJECT_KIND_LEN_FIELD,
344 have: end,
345 what: "BIOP objectKind_length",
346 });
347 }
348 let kind_len =
349 u32::from_be_bytes([bytes[pos], bytes[pos + 1], bytes[pos + 2], bytes[pos + 3]]) as usize;
350 pos += OBJECT_KIND_LEN_FIELD;
351 if kind_len != OBJECT_KIND_DATA_LEN {
352 return Err(Error::ValueOutOfRange {
353 field: "objectKind_length",
354 reason: "DVB BIOP objectKind must be exactly 4 bytes",
355 });
356 }
357 if pos + OBJECT_KIND_DATA_LEN > end {
358 return Err(Error::SectionLengthOverflow {
359 declared: OBJECT_KIND_DATA_LEN,
360 available: end - pos,
361 });
362 }
363 let mut kind_bytes = [0u8; 4];
364 kind_bytes.copy_from_slice(&bytes[pos..pos + 4]);
365 pos += OBJECT_KIND_DATA_LEN;
366
367 Ok((object_key, kind_bytes, message_size, pos))
368}
369
370fn parse_service_context_list<'a>(
373 bytes: &'a [u8],
374 pos: usize,
375 end: usize,
376) -> Result<(Vec<ServiceContext<'a>>, usize)> {
377 if pos + SERVICE_CONTEXT_COUNT_FIELD > end {
378 return Err(Error::BufferTooShort {
379 need: pos + SERVICE_CONTEXT_COUNT_FIELD,
380 have: end,
381 what: "serviceContextList_count",
382 });
383 }
384 let count = bytes[pos] as usize;
385 let mut cur = pos + SERVICE_CONTEXT_COUNT_FIELD;
386 let mut list = Vec::with_capacity(count.min(16));
387 for _ in 0..count {
388 if cur + SERVICE_CONTEXT_FIXED > end {
389 return Err(Error::BufferTooShort {
390 need: cur + SERVICE_CONTEXT_FIXED,
391 have: end,
392 what: "serviceContext entry",
393 });
394 }
395 let context_id =
396 u32::from_be_bytes([bytes[cur], bytes[cur + 1], bytes[cur + 2], bytes[cur + 3]]);
397 let ctx_data_len = u16::from_be_bytes([bytes[cur + 4], bytes[cur + 5]]) as usize;
398 cur += SERVICE_CONTEXT_FIXED;
399 if cur + ctx_data_len > end {
400 return Err(Error::SectionLengthOverflow {
401 declared: ctx_data_len,
402 available: end - cur,
403 });
404 }
405 let data = &bytes[cur..cur + ctx_data_len];
406 cur += ctx_data_len;
407 list.push(ServiceContext { context_id, data });
408 }
409 Ok((list, cur))
410}
411
412fn service_context_list_len(list: &[ServiceContext]) -> usize {
414 SERVICE_CONTEXT_COUNT_FIELD
415 + list
416 .iter()
417 .map(|e| SERVICE_CONTEXT_FIXED + e.data.len())
418 .sum::<usize>()
419}
420
421fn write_service_context_list(buf: &mut [u8], list: &[ServiceContext]) -> Result<usize> {
423 if list.len() > u8::MAX as usize {
424 return Err(Error::SectionLengthOverflow {
425 declared: list.len(),
426 available: u8::MAX as usize,
427 });
428 }
429 buf[0] = list.len() as u8;
430 let mut pos = SERVICE_CONTEXT_COUNT_FIELD;
431 for entry in list {
432 if entry.data.len() > u16::MAX as usize {
433 return Err(Error::SectionLengthOverflow {
434 declared: entry.data.len(),
435 available: u16::MAX as usize,
436 });
437 }
438 buf[pos..pos + 4].copy_from_slice(&entry.context_id.to_be_bytes());
439 buf[pos + 4..pos + 6].copy_from_slice(&(entry.data.len() as u16).to_be_bytes());
440 pos += SERVICE_CONTEXT_FIXED;
441 buf[pos..pos + entry.data.len()].copy_from_slice(entry.data);
442 pos += entry.data.len();
443 }
444 Ok(pos)
445}
446
447fn write_biop_header(buf: &mut [u8], message_size: u32) {
449 buf[0..4].copy_from_slice(&BIOP_MAGIC.to_be_bytes());
450 buf[4] = BIOP_VERSION_MAJOR;
451 buf[5] = BIOP_VERSION_MINOR;
452 buf[6] = BYTE_ORDER_BIG_ENDIAN;
453 buf[7] = 0x00; buf[8..12].copy_from_slice(&message_size.to_be_bytes());
455}
456
457#[derive(Debug, Clone, PartialEq, Eq)]
462#[cfg_attr(feature = "serde", derive(serde::Serialize))]
463pub struct DirectoryMessage<'a> {
464 pub object_kind: [u8; 4],
466 #[cfg_attr(feature = "serde", serde(borrow))]
468 pub object_key: &'a [u8],
469 #[cfg_attr(feature = "serde", serde(borrow))]
471 pub object_info: &'a [u8],
472 #[cfg_attr(feature = "serde", serde(borrow))]
474 pub service_context: Vec<ServiceContext<'a>>,
475 pub bindings: Vec<Binding<'a>>,
477}
478
479impl<'a> DirectoryMessage<'a> {
480 pub fn is_service_gateway(&self) -> bool {
482 &self.object_kind == b"srg\0"
483 }
484
485 fn parse_from(
486 bytes: &'a [u8],
487 object_key: &'a [u8],
488 object_kind: [u8; 4],
489 pos: usize,
490 end: usize,
491 ) -> Result<Self> {
492 let mut cur = pos;
493
494 if cur + OBJECT_INFO_LEN_FIELD > end {
496 return Err(Error::BufferTooShort {
497 need: cur + OBJECT_INFO_LEN_FIELD,
498 have: end,
499 what: "DirectoryMessage objectInfo_length",
500 });
501 }
502 let obj_info_len = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
503 cur += OBJECT_INFO_LEN_FIELD;
504 if cur + obj_info_len > end {
505 return Err(Error::SectionLengthOverflow {
506 declared: obj_info_len,
507 available: end - cur,
508 });
509 }
510 let object_info = &bytes[cur..cur + obj_info_len];
511 cur += obj_info_len;
512
513 let (service_context, next) = parse_service_context_list(bytes, cur, end)?;
515 cur = next;
516
517 if cur + MESSAGE_BODY_LEN_FIELD > end {
519 return Err(Error::BufferTooShort {
520 need: cur + MESSAGE_BODY_LEN_FIELD,
521 have: end,
522 what: "DirectoryMessage messageBody_length",
523 });
524 }
525 let body_len =
526 u32::from_be_bytes([bytes[cur], bytes[cur + 1], bytes[cur + 2], bytes[cur + 3]])
527 as usize;
528 cur += MESSAGE_BODY_LEN_FIELD;
529 let body_end = cur + body_len;
530 if body_end > end {
531 return Err(Error::SectionLengthOverflow {
532 declared: body_len,
533 available: end - cur,
534 });
535 }
536
537 if cur + BINDINGS_COUNT_FIELD > body_end {
539 return Err(Error::BufferTooShort {
540 need: cur + BINDINGS_COUNT_FIELD,
541 have: body_end,
542 what: "DirectoryMessage bindings_count",
543 });
544 }
545 let bindings_count = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
546 cur += BINDINGS_COUNT_FIELD;
547
548 let mut bindings = Vec::with_capacity(bindings_count.min(256));
549 for _ in 0..bindings_count {
550 let (binding, next) = Binding::parse_from(bytes, cur, body_end)?;
551 bindings.push(binding);
552 cur = next;
553 }
554
555 Ok(DirectoryMessage {
556 object_kind,
557 object_key,
558 object_info,
559 service_context,
560 bindings,
561 })
562 }
563
564 fn body_len(&self) -> usize {
565 let bindings_len: usize = self.bindings.iter().map(|b| b.serialized_len()).sum();
566 BINDINGS_COUNT_FIELD + bindings_len
567 }
568
569 fn serialized_len_inner(&self) -> usize {
570 let key_part = OBJECT_KEY_LEN_FIELD
572 + self.object_key.len()
573 + OBJECT_KIND_LEN_FIELD
574 + OBJECT_KIND_DATA_LEN;
575 let info_part = OBJECT_INFO_LEN_FIELD + self.object_info.len();
576 let svc_ctx_part = service_context_list_len(&self.service_context);
577 let body_part = MESSAGE_BODY_LEN_FIELD + self.body_len();
578 key_part + info_part + svc_ctx_part + body_part
579 }
580
581 pub fn serialized_len_total(&self) -> usize {
583 BIOP_HEADER_LEN + self.serialized_len_inner()
584 }
585
586 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
587 let inner_len = self.serialized_len_inner();
588 let total = BIOP_HEADER_LEN + inner_len;
589 if buf.len() < total {
590 return Err(Error::OutputBufferTooSmall {
591 need: total,
592 have: buf.len(),
593 });
594 }
595 if inner_len > u32::MAX as usize {
596 return Err(Error::SectionLengthOverflow {
597 declared: inner_len,
598 available: u32::MAX as usize,
599 });
600 }
601 write_biop_header(buf, inner_len as u32);
602 let mut pos = BIOP_HEADER_LEN;
603
604 if self.object_key.len() > u8::MAX as usize {
606 return Err(Error::SectionLengthOverflow {
607 declared: self.object_key.len(),
608 available: u8::MAX as usize,
609 });
610 }
611 buf[pos] = self.object_key.len() as u8;
612 pos += OBJECT_KEY_LEN_FIELD;
613 buf[pos..pos + self.object_key.len()].copy_from_slice(self.object_key);
614 pos += self.object_key.len();
615
616 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
618 pos += OBJECT_KIND_LEN_FIELD;
619 buf[pos..pos + 4].copy_from_slice(&self.object_kind);
620 pos += OBJECT_KIND_DATA_LEN;
621
622 if self.object_info.len() > u16::MAX as usize {
624 return Err(Error::SectionLengthOverflow {
625 declared: self.object_info.len(),
626 available: u16::MAX as usize,
627 });
628 }
629 buf[pos..pos + 2].copy_from_slice(&(self.object_info.len() as u16).to_be_bytes());
630 pos += OBJECT_INFO_LEN_FIELD;
631 buf[pos..pos + self.object_info.len()].copy_from_slice(self.object_info);
632 pos += self.object_info.len();
633
634 pos += write_service_context_list(&mut buf[pos..], &self.service_context)?;
636
637 let body_len = self.body_len();
639 if body_len > u32::MAX as usize {
640 return Err(Error::SectionLengthOverflow {
641 declared: body_len,
642 available: u32::MAX as usize,
643 });
644 }
645 buf[pos..pos + 4].copy_from_slice(&(body_len as u32).to_be_bytes());
646 pos += MESSAGE_BODY_LEN_FIELD;
647
648 if self.bindings.len() > u16::MAX as usize {
650 return Err(Error::SectionLengthOverflow {
651 declared: self.bindings.len(),
652 available: u16::MAX as usize,
653 });
654 }
655 buf[pos..pos + 2].copy_from_slice(&(self.bindings.len() as u16).to_be_bytes());
656 pos += BINDINGS_COUNT_FIELD;
657
658 for binding in &self.bindings {
659 let written = binding.serialize_into_buf(&mut buf[pos..])?;
660 pos += written;
661 }
662
663 Ok(total)
664 }
665}
666
667#[derive(Debug, Clone, PartialEq, Eq)]
674#[cfg_attr(feature = "serde", derive(serde::Serialize))]
675pub struct FileMessage<'a> {
676 #[cfg_attr(feature = "serde", serde(borrow))]
678 pub object_key: &'a [u8],
679 pub content_size: u64,
681 #[cfg_attr(feature = "serde", serde(borrow))]
683 pub object_info_extra: &'a [u8],
684 #[cfg_attr(feature = "serde", serde(borrow))]
686 pub service_context: Vec<ServiceContext<'a>>,
687 #[cfg_attr(feature = "serde", serde(borrow))]
689 pub content: &'a [u8],
690}
691
692impl<'a> FileMessage<'a> {
693 fn parse_from(bytes: &'a [u8], object_key: &'a [u8], pos: usize, end: usize) -> Result<Self> {
694 let mut cur = pos;
695
696 if cur + OBJECT_INFO_LEN_FIELD > end {
698 return Err(Error::BufferTooShort {
699 need: cur + OBJECT_INFO_LEN_FIELD,
700 have: end,
701 what: "FileMessage objectInfo_length",
702 });
703 }
704 let obj_info_len = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
705 cur += OBJECT_INFO_LEN_FIELD;
706 if obj_info_len < FILE_CONTENT_SIZE_LEN {
707 return Err(Error::ValueOutOfRange {
708 field: "FileMessage.objectInfo_length",
709 reason: "FileMessage objectInfo must be at least 8 bytes (ContentSize)",
710 });
711 }
712 if cur + obj_info_len > end {
713 return Err(Error::SectionLengthOverflow {
714 declared: obj_info_len,
715 available: end - cur,
716 });
717 }
718 let content_size = u64::from_be_bytes([
719 bytes[cur],
720 bytes[cur + 1],
721 bytes[cur + 2],
722 bytes[cur + 3],
723 bytes[cur + 4],
724 bytes[cur + 5],
725 bytes[cur + 6],
726 bytes[cur + 7],
727 ]);
728 let object_info_extra = &bytes[cur + FILE_CONTENT_SIZE_LEN..cur + obj_info_len];
729 cur += obj_info_len;
730
731 let (service_context, next) = parse_service_context_list(bytes, cur, end)?;
733 cur = next;
734
735 if cur + MESSAGE_BODY_LEN_FIELD > end {
737 return Err(Error::BufferTooShort {
738 need: cur + MESSAGE_BODY_LEN_FIELD,
739 have: end,
740 what: "FileMessage messageBody_length",
741 });
742 }
743 let body_len =
744 u32::from_be_bytes([bytes[cur], bytes[cur + 1], bytes[cur + 2], bytes[cur + 3]])
745 as usize;
746 cur += MESSAGE_BODY_LEN_FIELD;
747 let body_end = cur + body_len;
748 if body_end > end {
749 return Err(Error::SectionLengthOverflow {
750 declared: body_len,
751 available: end - cur,
752 });
753 }
754
755 if cur + FILE_CONTENT_LEN_FIELD > body_end {
757 return Err(Error::BufferTooShort {
758 need: cur + FILE_CONTENT_LEN_FIELD,
759 have: body_end,
760 what: "FileMessage content_length",
761 });
762 }
763 let content_len =
764 u32::from_be_bytes([bytes[cur], bytes[cur + 1], bytes[cur + 2], bytes[cur + 3]])
765 as usize;
766 cur += FILE_CONTENT_LEN_FIELD;
767 if cur + content_len > body_end {
768 return Err(Error::SectionLengthOverflow {
769 declared: content_len,
770 available: body_end - cur,
771 });
772 }
773 let content = &bytes[cur..cur + content_len];
774
775 Ok(FileMessage {
776 object_key,
777 content_size,
778 object_info_extra,
779 service_context,
780 content,
781 })
782 }
783
784 fn serialized_len_inner(&self) -> usize {
785 let obj_info_total = FILE_CONTENT_SIZE_LEN + self.object_info_extra.len();
786 OBJECT_KEY_LEN_FIELD
787 + self.object_key.len()
788 + OBJECT_KIND_LEN_FIELD
789 + OBJECT_KIND_DATA_LEN
790 + OBJECT_INFO_LEN_FIELD
791 + obj_info_total
792 + service_context_list_len(&self.service_context)
793 + MESSAGE_BODY_LEN_FIELD
794 + FILE_CONTENT_LEN_FIELD
795 + self.content.len()
796 }
797
798 pub fn serialized_len_total(&self) -> usize {
800 BIOP_HEADER_LEN + self.serialized_len_inner()
801 }
802
803 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
804 let inner_len = self.serialized_len_inner();
805 let total = BIOP_HEADER_LEN + inner_len;
806 if buf.len() < total {
807 return Err(Error::OutputBufferTooSmall {
808 need: total,
809 have: buf.len(),
810 });
811 }
812 write_biop_header(buf, inner_len as u32);
813 let mut pos = BIOP_HEADER_LEN;
814
815 if self.object_key.len() > u8::MAX as usize {
816 return Err(Error::SectionLengthOverflow {
817 declared: self.object_key.len(),
818 available: u8::MAX as usize,
819 });
820 }
821 buf[pos] = self.object_key.len() as u8;
822 pos += OBJECT_KEY_LEN_FIELD;
823 buf[pos..pos + self.object_key.len()].copy_from_slice(self.object_key);
824 pos += self.object_key.len();
825
826 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
828 pos += OBJECT_KIND_LEN_FIELD;
829 buf[pos..pos + 4].copy_from_slice(b"fil\0");
830 pos += OBJECT_KIND_DATA_LEN;
831
832 let obj_info_total = FILE_CONTENT_SIZE_LEN + self.object_info_extra.len();
834 if obj_info_total > u16::MAX as usize {
835 return Err(Error::SectionLengthOverflow {
836 declared: obj_info_total,
837 available: u16::MAX as usize,
838 });
839 }
840 buf[pos..pos + 2].copy_from_slice(&(obj_info_total as u16).to_be_bytes());
841 pos += OBJECT_INFO_LEN_FIELD;
842 buf[pos..pos + 8].copy_from_slice(&self.content_size.to_be_bytes());
843 pos += FILE_CONTENT_SIZE_LEN;
844 buf[pos..pos + self.object_info_extra.len()].copy_from_slice(self.object_info_extra);
845 pos += self.object_info_extra.len();
846
847 pos += write_service_context_list(&mut buf[pos..], &self.service_context)?;
849
850 let body_len = FILE_CONTENT_LEN_FIELD + self.content.len();
852 buf[pos..pos + 4].copy_from_slice(&(body_len as u32).to_be_bytes());
853 pos += MESSAGE_BODY_LEN_FIELD;
854 buf[pos..pos + 4].copy_from_slice(&(self.content.len() as u32).to_be_bytes());
855 pos += FILE_CONTENT_LEN_FIELD;
856 buf[pos..pos + self.content.len()].copy_from_slice(self.content);
857
858 Ok(total)
859 }
860}
861
862#[derive(Debug, Clone, PartialEq, Eq)]
868#[cfg_attr(feature = "serde", derive(serde::Serialize))]
869pub struct DsmStreamInfo<'a> {
870 #[cfg_attr(feature = "serde", serde(borrow))]
872 pub description: &'a [u8],
873 pub duration_seconds: i32,
875 pub duration_microseconds: u16,
877 pub audio: u8,
879 pub video: u8,
881 pub data: u8,
883}
884
885impl<'a> DsmStreamInfo<'a> {
886 fn serialized_len(&self) -> usize {
888 STREAM_ADESC_LEN_FIELD + self.description.len() + STREAM_INFO_FIXED
889 }
890
891 fn parse_from(bytes: &'a [u8], pos: usize, end: usize) -> Result<(Self, usize)> {
893 if pos + STREAM_ADESC_LEN_FIELD > end {
895 return Err(Error::BufferTooShort {
896 need: pos + STREAM_ADESC_LEN_FIELD,
897 have: end,
898 what: "DsmStreamInfo aDescription_length",
899 });
900 }
901 let desc_len = bytes[pos] as usize;
902 let mut cur = pos + STREAM_ADESC_LEN_FIELD;
903
904 if cur + desc_len > end {
906 return Err(Error::SectionLengthOverflow {
907 declared: desc_len,
908 available: end - cur,
909 });
910 }
911 let description = &bytes[cur..cur + desc_len];
912 cur += desc_len;
913
914 if cur + STREAM_INFO_FIXED > end {
916 return Err(Error::BufferTooShort {
917 need: cur + STREAM_INFO_FIXED,
918 have: end,
919 what: "DsmStreamInfo fixed fields",
920 });
921 }
922 let duration_seconds =
923 i32::from_be_bytes([bytes[cur], bytes[cur + 1], bytes[cur + 2], bytes[cur + 3]]);
924 cur += 4;
925 let duration_microseconds = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]);
926 cur += 2;
927 let audio = bytes[cur];
928 cur += 1;
929 let video = bytes[cur];
930 cur += 1;
931 let data = bytes[cur];
932 cur += 1;
933
934 Ok((
935 DsmStreamInfo {
936 description,
937 duration_seconds,
938 duration_microseconds,
939 audio,
940 video,
941 data,
942 },
943 cur,
944 ))
945 }
946
947 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
948 let len = self.serialized_len();
949 if buf.len() < len {
950 return Err(Error::OutputBufferTooSmall {
951 need: len,
952 have: buf.len(),
953 });
954 }
955 if self.description.len() > u8::MAX as usize {
956 return Err(Error::SectionLengthOverflow {
957 declared: self.description.len(),
958 available: u8::MAX as usize,
959 });
960 }
961 buf[0] = self.description.len() as u8;
962 let mut pos = STREAM_ADESC_LEN_FIELD;
963 buf[pos..pos + self.description.len()].copy_from_slice(self.description);
964 pos += self.description.len();
965 buf[pos..pos + 4].copy_from_slice(&self.duration_seconds.to_be_bytes());
966 pos += 4;
967 buf[pos..pos + 2].copy_from_slice(&self.duration_microseconds.to_be_bytes());
968 pos += 2;
969 buf[pos] = self.audio;
970 pos += 1;
971 buf[pos] = self.video;
972 pos += 1;
973 buf[pos] = self.data;
974 pos += 1;
975 Ok(pos)
976 }
977}
978
979#[derive(Debug, Clone, PartialEq, Eq)]
984#[cfg_attr(feature = "serde", derive(serde::Serialize))]
985pub struct StreamMessage<'a> {
986 #[cfg_attr(feature = "serde", serde(borrow))]
988 pub object_key: &'a [u8],
989 pub stream_info: DsmStreamInfo<'a>,
991 #[cfg_attr(feature = "serde", serde(borrow))]
993 pub object_info_extra: &'a [u8],
994 #[cfg_attr(feature = "serde", serde(borrow))]
996 pub service_context: Vec<ServiceContext<'a>>,
997 pub taps: Vec<super::ior::Tap<'a>>,
999}
1000
1001impl<'a> StreamMessage<'a> {
1002 fn parse_from(bytes: &'a [u8], object_key: &'a [u8], pos: usize, end: usize) -> Result<Self> {
1003 let mut cur = pos;
1004
1005 if cur + OBJECT_INFO_LEN_FIELD > end {
1007 return Err(Error::BufferTooShort {
1008 need: cur + OBJECT_INFO_LEN_FIELD,
1009 have: end,
1010 what: "StreamMessage objectInfo_length",
1011 });
1012 }
1013 let obj_info_len = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
1014 cur += OBJECT_INFO_LEN_FIELD;
1015 if cur + obj_info_len > end {
1016 return Err(Error::SectionLengthOverflow {
1017 declared: obj_info_len,
1018 available: end - cur,
1019 });
1020 }
1021 let obj_info_start = cur;
1022 let obj_info_end = cur + obj_info_len;
1023
1024 let (stream_info, _) = DsmStreamInfo::parse_from(bytes, cur, obj_info_end)?;
1026 let info_len = stream_info.serialized_len();
1027 if obj_info_len < info_len {
1028 return Err(Error::ValueOutOfRange {
1029 field: "StreamMessage.objectInfo_length",
1030 reason: "objectInfo too short for DSM::Stream::Info_T",
1031 });
1032 }
1033 let object_info_extra = &bytes[obj_info_start + info_len..obj_info_end];
1034 cur = obj_info_end;
1035
1036 let (service_context, next) = parse_service_context_list(bytes, cur, end)?;
1038 cur = next;
1039
1040 if cur + MESSAGE_BODY_LEN_FIELD > end {
1042 return Err(Error::BufferTooShort {
1043 need: cur + MESSAGE_BODY_LEN_FIELD,
1044 have: end,
1045 what: "StreamMessage messageBody_length",
1046 });
1047 }
1048 let body_len =
1049 u32::from_be_bytes([bytes[cur], bytes[cur + 1], bytes[cur + 2], bytes[cur + 3]])
1050 as usize;
1051 cur += MESSAGE_BODY_LEN_FIELD;
1052 let body_end = cur + body_len;
1053 if body_end > end {
1054 return Err(Error::SectionLengthOverflow {
1055 declared: body_len,
1056 available: end - cur,
1057 });
1058 }
1059
1060 if cur + STREAM_TAPS_COUNT_FIELD > body_end {
1062 return Err(Error::BufferTooShort {
1063 need: cur + STREAM_TAPS_COUNT_FIELD,
1064 have: body_end,
1065 what: "StreamMessage taps_count",
1066 });
1067 }
1068 let taps_count = bytes[cur] as usize;
1069 cur += STREAM_TAPS_COUNT_FIELD;
1070
1071 let mut taps = Vec::with_capacity(taps_count.min(16));
1072 for _ in 0..taps_count {
1073 let (tap, next) = super::ior::Tap::parse_from(bytes, cur, body_end)?;
1074 taps.push(tap);
1075 cur = next;
1076 }
1077
1078 Ok(StreamMessage {
1079 object_key,
1080 stream_info,
1081 object_info_extra,
1082 service_context,
1083 taps,
1084 })
1085 }
1086
1087 fn body_len(&self) -> usize {
1088 let taps_len: usize = self.taps.iter().map(|t| t.serialized_len()).sum();
1089 STREAM_TAPS_COUNT_FIELD + taps_len
1090 }
1091
1092 fn obj_info_len(&self) -> usize {
1093 self.stream_info.serialized_len() + self.object_info_extra.len()
1094 }
1095
1096 fn serialized_len_inner(&self) -> usize {
1097 OBJECT_KEY_LEN_FIELD
1098 + self.object_key.len()
1099 + OBJECT_KIND_LEN_FIELD
1100 + OBJECT_KIND_DATA_LEN
1101 + OBJECT_INFO_LEN_FIELD
1102 + self.obj_info_len()
1103 + service_context_list_len(&self.service_context)
1104 + MESSAGE_BODY_LEN_FIELD
1105 + self.body_len()
1106 }
1107
1108 pub fn serialized_len_total(&self) -> usize {
1110 BIOP_HEADER_LEN + self.serialized_len_inner()
1111 }
1112
1113 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
1114 let inner_len = self.serialized_len_inner();
1115 let total = BIOP_HEADER_LEN + inner_len;
1116 if buf.len() < total {
1117 return Err(Error::OutputBufferTooSmall {
1118 need: total,
1119 have: buf.len(),
1120 });
1121 }
1122 write_biop_header(buf, inner_len as u32);
1123 let mut pos = BIOP_HEADER_LEN;
1124
1125 if self.object_key.len() > u8::MAX as usize {
1127 return Err(Error::SectionLengthOverflow {
1128 declared: self.object_key.len(),
1129 available: u8::MAX as usize,
1130 });
1131 }
1132 buf[pos] = self.object_key.len() as u8;
1133 pos += OBJECT_KEY_LEN_FIELD;
1134 buf[pos..pos + self.object_key.len()].copy_from_slice(self.object_key);
1135 pos += self.object_key.len();
1136
1137 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
1139 pos += OBJECT_KIND_LEN_FIELD;
1140 buf[pos..pos + 4].copy_from_slice(b"str\0");
1141 pos += OBJECT_KIND_DATA_LEN;
1142
1143 let oi_len = self.obj_info_len();
1145 if oi_len > u16::MAX as usize {
1146 return Err(Error::SectionLengthOverflow {
1147 declared: oi_len,
1148 available: u16::MAX as usize,
1149 });
1150 }
1151 buf[pos..pos + 2].copy_from_slice(&(oi_len as u16).to_be_bytes());
1152 pos += OBJECT_INFO_LEN_FIELD;
1153
1154 let written = self.stream_info.serialize_into_buf(&mut buf[pos..])?;
1156 pos += written;
1157
1158 buf[pos..pos + self.object_info_extra.len()].copy_from_slice(self.object_info_extra);
1160 pos += self.object_info_extra.len();
1161
1162 pos += write_service_context_list(&mut buf[pos..], &self.service_context)?;
1164
1165 let bl = self.body_len();
1167 buf[pos..pos + 4].copy_from_slice(&(bl as u32).to_be_bytes());
1168 pos += MESSAGE_BODY_LEN_FIELD;
1169
1170 if self.taps.len() > u8::MAX as usize {
1172 return Err(Error::SectionLengthOverflow {
1173 declared: self.taps.len(),
1174 available: u8::MAX as usize,
1175 });
1176 }
1177 buf[pos] = self.taps.len() as u8;
1178 pos += STREAM_TAPS_COUNT_FIELD;
1179 for tap in &self.taps {
1180 let written = tap.serialize_into_buf(&mut buf[pos..])?;
1181 pos += written;
1182 }
1183
1184 Ok(total)
1185 }
1186}
1187
1188#[derive(Debug, Clone, PartialEq, Eq)]
1193#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1194pub struct StreamEventMessage<'a> {
1195 #[cfg_attr(feature = "serde", serde(borrow))]
1197 pub object_key: &'a [u8],
1198 pub stream_info: DsmStreamInfo<'a>,
1200 pub event_names: Vec<&'a [u8]>,
1203 #[cfg_attr(feature = "serde", serde(borrow))]
1205 pub object_info_extra: &'a [u8],
1206 #[cfg_attr(feature = "serde", serde(borrow))]
1208 pub service_context: Vec<ServiceContext<'a>>,
1209 pub taps: Vec<super::ior::Tap<'a>>,
1211 pub event_ids: Vec<u16>,
1213}
1214
1215impl<'a> StreamEventMessage<'a> {
1216 fn parse_from(bytes: &'a [u8], object_key: &'a [u8], pos: usize, end: usize) -> Result<Self> {
1217 let mut cur = pos;
1218
1219 if cur + OBJECT_INFO_LEN_FIELD > end {
1221 return Err(Error::BufferTooShort {
1222 need: cur + OBJECT_INFO_LEN_FIELD,
1223 have: end,
1224 what: "StreamEventMessage objectInfo_length",
1225 });
1226 }
1227 let obj_info_len = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
1228 cur += OBJECT_INFO_LEN_FIELD;
1229 if cur + obj_info_len > end {
1230 return Err(Error::SectionLengthOverflow {
1231 declared: obj_info_len,
1232 available: end - cur,
1233 });
1234 }
1235 let obj_info_end = cur + obj_info_len;
1236
1237 let (stream_info, next_cur) = DsmStreamInfo::parse_from(bytes, cur, obj_info_end)?;
1239 cur = next_cur;
1240
1241 if cur + STREAM_EVENT_NAMES_COUNT_FIELD > obj_info_end {
1243 return Err(Error::BufferTooShort {
1244 need: cur + STREAM_EVENT_NAMES_COUNT_FIELD,
1245 have: obj_info_end,
1246 what: "StreamEventMessage eventNames_count",
1247 });
1248 }
1249 let event_names_count = u16::from_be_bytes([bytes[cur], bytes[cur + 1]]) as usize;
1250 cur += STREAM_EVENT_NAMES_COUNT_FIELD;
1251
1252 let mut event_names = Vec::with_capacity(event_names_count.min(64));
1253 for _ in 0..event_names_count {
1254 if cur + STREAM_EVENT_NAME_LEN_FIELD > obj_info_end {
1255 return Err(Error::BufferTooShort {
1256 need: cur + STREAM_EVENT_NAME_LEN_FIELD,
1257 have: obj_info_end,
1258 what: "StreamEventMessage eventName_length",
1259 });
1260 }
1261 let name_len = bytes[cur] as usize;
1262 cur += STREAM_EVENT_NAME_LEN_FIELD;
1263 if cur + name_len > obj_info_end {
1264 return Err(Error::SectionLengthOverflow {
1265 declared: name_len,
1266 available: obj_info_end - cur,
1267 });
1268 }
1269 event_names.push(&bytes[cur..cur + name_len]);
1270 cur += name_len;
1271 }
1272
1273 let object_info_extra = &bytes[cur..obj_info_end];
1275 cur = obj_info_end;
1276
1277 let (service_context, next) = parse_service_context_list(bytes, cur, end)?;
1279 cur = next;
1280
1281 if cur + MESSAGE_BODY_LEN_FIELD > end {
1283 return Err(Error::BufferTooShort {
1284 need: cur + MESSAGE_BODY_LEN_FIELD,
1285 have: end,
1286 what: "StreamEventMessage messageBody_length",
1287 });
1288 }
1289 let body_len =
1290 u32::from_be_bytes([bytes[cur], bytes[cur + 1], bytes[cur + 2], bytes[cur + 3]])
1291 as usize;
1292 cur += MESSAGE_BODY_LEN_FIELD;
1293 let body_end = cur + body_len;
1294 if body_end > end {
1295 return Err(Error::SectionLengthOverflow {
1296 declared: body_len,
1297 available: end - cur,
1298 });
1299 }
1300
1301 if cur + STREAM_TAPS_COUNT_FIELD > body_end {
1303 return Err(Error::BufferTooShort {
1304 need: cur + STREAM_TAPS_COUNT_FIELD,
1305 have: body_end,
1306 what: "StreamEventMessage taps_count",
1307 });
1308 }
1309 let taps_count = bytes[cur] as usize;
1310 cur += STREAM_TAPS_COUNT_FIELD;
1311
1312 let mut taps = Vec::with_capacity(taps_count.min(16));
1313 for _ in 0..taps_count {
1314 let (tap, next) = super::ior::Tap::parse_from(bytes, cur, body_end)?;
1315 taps.push(tap);
1316 cur = next;
1317 }
1318
1319 if cur + STREAM_EVENT_IDS_COUNT_FIELD > body_end {
1321 return Err(Error::BufferTooShort {
1322 need: cur + STREAM_EVENT_IDS_COUNT_FIELD,
1323 have: body_end,
1324 what: "StreamEventMessage eventIds_count",
1325 });
1326 }
1327 let event_ids_count = bytes[cur] as usize;
1328 cur += STREAM_EVENT_IDS_COUNT_FIELD;
1329 if event_ids_count != event_names_count {
1330 return Err(Error::ValueOutOfRange {
1331 field: "StreamEventMessage.eventIds_count",
1332 reason: "eventIds_count must equal eventNames_count",
1333 });
1334 }
1335
1336 let mut event_ids = Vec::with_capacity(event_ids_count.min(64));
1337 for _ in 0..event_ids_count {
1338 if cur + STREAM_EVENT_ID_LEN > body_end {
1339 return Err(Error::BufferTooShort {
1340 need: cur + STREAM_EVENT_ID_LEN,
1341 have: body_end,
1342 what: "StreamEventMessage eventId",
1343 });
1344 }
1345 event_ids.push(u16::from_be_bytes([bytes[cur], bytes[cur + 1]]));
1346 cur += STREAM_EVENT_ID_LEN;
1347 }
1348
1349 let _ = cur; Ok(StreamEventMessage {
1351 object_key,
1352 stream_info,
1353 event_names,
1354 object_info_extra,
1355 service_context,
1356 taps,
1357 event_ids,
1358 })
1359 }
1360
1361 fn event_list_wire_len(&self) -> usize {
1363 let names_len: usize = self
1364 .event_names
1365 .iter()
1366 .map(|n| STREAM_EVENT_NAME_LEN_FIELD + n.len())
1367 .sum();
1368 STREAM_EVENT_NAMES_COUNT_FIELD + names_len
1369 }
1370
1371 fn body_len(&self) -> usize {
1372 let taps_len: usize = self.taps.iter().map(|t| t.serialized_len()).sum();
1373 STREAM_TAPS_COUNT_FIELD
1374 + taps_len
1375 + STREAM_EVENT_IDS_COUNT_FIELD
1376 + self.event_ids.len() * STREAM_EVENT_ID_LEN
1377 }
1378
1379 fn obj_info_len(&self) -> usize {
1380 self.stream_info.serialized_len()
1381 + self.event_list_wire_len()
1382 + self.object_info_extra.len()
1383 }
1384
1385 fn serialized_len_inner(&self) -> usize {
1386 OBJECT_KEY_LEN_FIELD
1387 + self.object_key.len()
1388 + OBJECT_KIND_LEN_FIELD
1389 + OBJECT_KIND_DATA_LEN
1390 + OBJECT_INFO_LEN_FIELD
1391 + self.obj_info_len()
1392 + service_context_list_len(&self.service_context)
1393 + MESSAGE_BODY_LEN_FIELD
1394 + self.body_len()
1395 }
1396
1397 pub fn serialized_len_total(&self) -> usize {
1399 BIOP_HEADER_LEN + self.serialized_len_inner()
1400 }
1401
1402 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
1403 let inner_len = self.serialized_len_inner();
1404 let total = BIOP_HEADER_LEN + inner_len;
1405 if buf.len() < total {
1406 return Err(Error::OutputBufferTooSmall {
1407 need: total,
1408 have: buf.len(),
1409 });
1410 }
1411 write_biop_header(buf, inner_len as u32);
1412 let mut pos = BIOP_HEADER_LEN;
1413
1414 if self.object_key.len() > u8::MAX as usize {
1416 return Err(Error::SectionLengthOverflow {
1417 declared: self.object_key.len(),
1418 available: u8::MAX as usize,
1419 });
1420 }
1421 buf[pos] = self.object_key.len() as u8;
1422 pos += OBJECT_KEY_LEN_FIELD;
1423 buf[pos..pos + self.object_key.len()].copy_from_slice(self.object_key);
1424 pos += self.object_key.len();
1425
1426 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
1428 pos += OBJECT_KIND_LEN_FIELD;
1429 buf[pos..pos + 4].copy_from_slice(b"ste\0");
1430 pos += OBJECT_KIND_DATA_LEN;
1431
1432 let oi_len = self.obj_info_len();
1434 if oi_len > u16::MAX as usize {
1435 return Err(Error::SectionLengthOverflow {
1436 declared: oi_len,
1437 available: u16::MAX as usize,
1438 });
1439 }
1440 buf[pos..pos + 2].copy_from_slice(&(oi_len as u16).to_be_bytes());
1441 pos += OBJECT_INFO_LEN_FIELD;
1442
1443 let written = self.stream_info.serialize_into_buf(&mut buf[pos..])?;
1445 pos += written;
1446
1447 if self.event_names.len() > u16::MAX as usize {
1449 return Err(Error::SectionLengthOverflow {
1450 declared: self.event_names.len(),
1451 available: u16::MAX as usize,
1452 });
1453 }
1454 buf[pos..pos + 2].copy_from_slice(&(self.event_names.len() as u16).to_be_bytes());
1455 pos += STREAM_EVENT_NAMES_COUNT_FIELD;
1456 for name in &self.event_names {
1457 if name.len() > u8::MAX as usize {
1458 return Err(Error::SectionLengthOverflow {
1459 declared: name.len(),
1460 available: u8::MAX as usize,
1461 });
1462 }
1463 buf[pos] = name.len() as u8;
1464 pos += STREAM_EVENT_NAME_LEN_FIELD;
1465 buf[pos..pos + name.len()].copy_from_slice(name);
1466 pos += name.len();
1467 }
1468
1469 buf[pos..pos + self.object_info_extra.len()].copy_from_slice(self.object_info_extra);
1471 pos += self.object_info_extra.len();
1472
1473 pos += write_service_context_list(&mut buf[pos..], &self.service_context)?;
1475
1476 let bl = self.body_len();
1478 buf[pos..pos + 4].copy_from_slice(&(bl as u32).to_be_bytes());
1479 pos += MESSAGE_BODY_LEN_FIELD;
1480
1481 if self.taps.len() > u8::MAX as usize {
1483 return Err(Error::SectionLengthOverflow {
1484 declared: self.taps.len(),
1485 available: u8::MAX as usize,
1486 });
1487 }
1488 buf[pos] = self.taps.len() as u8;
1489 pos += STREAM_TAPS_COUNT_FIELD;
1490 for tap in &self.taps {
1491 let written = tap.serialize_into_buf(&mut buf[pos..])?;
1492 pos += written;
1493 }
1494
1495 if self.event_ids.len() > u8::MAX as usize {
1497 return Err(Error::SectionLengthOverflow {
1498 declared: self.event_ids.len(),
1499 available: u8::MAX as usize,
1500 });
1501 }
1502 buf[pos] = self.event_ids.len() as u8;
1503 pos += STREAM_EVENT_IDS_COUNT_FIELD;
1504 for &id in &self.event_ids {
1505 buf[pos..pos + 2].copy_from_slice(&id.to_be_bytes());
1506 pos += STREAM_EVENT_ID_LEN;
1507 }
1508
1509 Ok(total)
1510 }
1511}
1512
1513#[derive(Debug, Clone, PartialEq, Eq)]
1518#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1519#[non_exhaustive]
1520pub enum BiopMessage<'a> {
1521 Directory(DirectoryMessage<'a>),
1523 File(FileMessage<'a>),
1525 ServiceGateway(DirectoryMessage<'a>),
1527 Stream(StreamMessage<'a>),
1529 StreamEvent(StreamEventMessage<'a>),
1531}
1532
1533impl<'a> BiopMessage<'a> {
1534 pub fn parse_at(bytes: &'a [u8]) -> Result<(Self, usize)> {
1539 let (object_key, kind_bytes, message_size, pos) = parse_biop_header(bytes)?;
1540 let consumed = BIOP_HEADER_LEN + message_size;
1541 let end = consumed;
1542
1543 let msg = match &kind_bytes {
1544 b"dir\0" => {
1545 let dm = DirectoryMessage::parse_from(bytes, object_key, kind_bytes, pos, end)?;
1546 BiopMessage::Directory(dm)
1547 }
1548 b"srg\0" => {
1549 let dm = DirectoryMessage::parse_from(bytes, object_key, kind_bytes, pos, end)?;
1550 BiopMessage::ServiceGateway(dm)
1551 }
1552 b"fil\0" => {
1553 let fm = FileMessage::parse_from(bytes, object_key, pos, end)?;
1554 BiopMessage::File(fm)
1555 }
1556 b"str\0" => {
1557 let sm = StreamMessage::parse_from(bytes, object_key, pos, end)?;
1558 BiopMessage::Stream(sm)
1559 }
1560 b"ste\0" => {
1561 let se = StreamEventMessage::parse_from(bytes, object_key, pos, end)?;
1562 BiopMessage::StreamEvent(se)
1563 }
1564 _ => {
1565 return Err(Error::ValueOutOfRange {
1566 field: "BiopMessage.objectKind",
1567 reason: "unknown BIOP objectKind",
1568 });
1569 }
1570 };
1571
1572 Ok((msg, consumed))
1573 }
1574
1575 fn serialized_len_total(&self) -> usize {
1576 match self {
1577 Self::Directory(d) | Self::ServiceGateway(d) => d.serialized_len_total(),
1578 Self::File(f) => f.serialized_len_total(),
1579 Self::Stream(s) => s.serialized_len_total(),
1580 Self::StreamEvent(se) => se.serialized_len_total(),
1581 }
1582 }
1583}
1584
1585impl Serialize for BiopMessage<'_> {
1586 type Error = crate::error::Error;
1587
1588 fn serialized_len(&self) -> usize {
1589 self.serialized_len_total()
1590 }
1591
1592 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
1593 let len = self.serialized_len_total();
1594 if buf.len() < len {
1595 return Err(Error::OutputBufferTooSmall {
1596 need: len,
1597 have: buf.len(),
1598 });
1599 }
1600 match self {
1601 Self::Directory(d) | Self::ServiceGateway(d) => {
1602 d.serialize_into_buf(buf)?;
1603 }
1604 Self::File(f) => {
1605 f.serialize_into_buf(buf)?;
1606 }
1607 Self::Stream(s) => {
1608 s.serialize_into_buf(buf)?;
1609 }
1610 Self::StreamEvent(se) => {
1611 se.serialize_into_buf(buf)?;
1612 }
1613 }
1614 Ok(len)
1615 }
1616}
1617
1618#[derive(Debug, Clone, PartialEq, Eq)]
1623#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1624pub struct ModuleInfo<'a> {
1625 pub module_timeout: u32,
1627 pub block_timeout: u32,
1629 pub min_block_time: u32,
1631 #[cfg_attr(feature = "serde", serde(borrow))]
1633 pub taps: Vec<super::ior::Tap<'a>>,
1634 #[cfg_attr(feature = "serde", serde(borrow))]
1636 pub user_info: &'a [u8],
1637}
1638
1639impl<'a> ModuleInfo<'a> {
1640 pub fn descriptors(&self) -> impl Iterator<Item = (u8, &[u8])> {
1644 DescriptorIter {
1645 data: self.user_info,
1646 pos: 0,
1647 }
1648 }
1649
1650 pub fn compressed_module_descriptor(&self) -> Option<CompressedModuleDescriptor<'_>> {
1653 for (tag, data) in self.descriptors() {
1654 if tag == COMPRESSED_MODULE_DESCRIPTOR_TAG {
1655 return Some(CompressedModuleDescriptor { body: data });
1656 }
1657 }
1658 None
1659 }
1660}
1661
1662struct DescriptorIter<'a> {
1663 data: &'a [u8],
1664 pos: usize,
1665}
1666
1667impl<'a> Iterator for DescriptorIter<'a> {
1668 type Item = (u8, &'a [u8]);
1669 fn next(&mut self) -> Option<Self::Item> {
1670 let end = self.data.len();
1671 if self.pos + 2 > end {
1672 return None;
1673 }
1674 let tag = self.data[self.pos];
1675 let len = self.data[self.pos + 1] as usize;
1676 self.pos += 2;
1677 if self.pos + len > end {
1678 return None;
1679 }
1680 let d = &self.data[self.pos..self.pos + len];
1681 self.pos += len;
1682 Some((tag, d))
1683 }
1684}
1685
1686impl<'a> Parse<'a> for ModuleInfo<'a> {
1687 type Error = crate::error::Error;
1688
1689 fn parse(bytes: &'a [u8]) -> Result<Self> {
1690 let end = bytes.len();
1691 if end < MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD {
1692 return Err(Error::BufferTooShort {
1693 need: MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD,
1694 have: end,
1695 what: "ModuleInfo fixed fields",
1696 });
1697 }
1698 let module_timeout = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
1699 let block_timeout = u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
1700 let min_block_time = u32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]);
1701 let taps_count = bytes[12] as usize;
1702 let mut pos = MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD;
1703
1704 let mut taps = Vec::with_capacity(taps_count.min(8));
1705 for _ in 0..taps_count {
1706 let (tap, next) = super::ior::Tap::parse_from(bytes, pos, end)?;
1707 taps.push(tap);
1708 pos = next;
1709 }
1710
1711 if pos + MODULE_USER_INFO_LEN_FIELD > end {
1712 return Err(Error::BufferTooShort {
1713 need: pos + MODULE_USER_INFO_LEN_FIELD,
1714 have: end,
1715 what: "ModuleInfo UserInfoLength",
1716 });
1717 }
1718 let user_info_len = bytes[pos] as usize;
1719 pos += MODULE_USER_INFO_LEN_FIELD;
1720 if pos + user_info_len > end {
1721 return Err(Error::SectionLengthOverflow {
1722 declared: user_info_len,
1723 available: end - pos,
1724 });
1725 }
1726 let user_info = &bytes[pos..pos + user_info_len];
1727
1728 Ok(ModuleInfo {
1729 module_timeout,
1730 block_timeout,
1731 min_block_time,
1732 taps,
1733 user_info,
1734 })
1735 }
1736}
1737
1738impl Serialize for ModuleInfo<'_> {
1739 type Error = crate::error::Error;
1740
1741 fn serialized_len(&self) -> usize {
1742 let taps_len: usize = self.taps.iter().map(|t| t.serialized_len()).sum();
1743 MODULE_INFO_FIXED
1744 + MODULE_TAPS_COUNT_FIELD
1745 + taps_len
1746 + MODULE_USER_INFO_LEN_FIELD
1747 + self.user_info.len()
1748 }
1749
1750 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
1751 let len = self.serialized_len();
1752 if buf.len() < len {
1753 return Err(Error::OutputBufferTooSmall {
1754 need: len,
1755 have: buf.len(),
1756 });
1757 }
1758 buf[0..4].copy_from_slice(&self.module_timeout.to_be_bytes());
1759 buf[4..8].copy_from_slice(&self.block_timeout.to_be_bytes());
1760 buf[8..12].copy_from_slice(&self.min_block_time.to_be_bytes());
1761 if self.taps.len() > u8::MAX as usize {
1762 return Err(Error::SectionLengthOverflow {
1763 declared: self.taps.len(),
1764 available: u8::MAX as usize,
1765 });
1766 }
1767 buf[12] = self.taps.len() as u8;
1768 let mut pos = MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD;
1769 for tap in &self.taps {
1770 let written = tap.serialize_into_buf(&mut buf[pos..])?;
1771 pos += written;
1772 }
1773 if self.user_info.len() > u8::MAX as usize {
1774 return Err(Error::SectionLengthOverflow {
1775 declared: self.user_info.len(),
1776 available: u8::MAX as usize,
1777 });
1778 }
1779 buf[pos] = self.user_info.len() as u8;
1780 pos += MODULE_USER_INFO_LEN_FIELD;
1781 buf[pos..pos + self.user_info.len()].copy_from_slice(self.user_info);
1782 pos += self.user_info.len();
1783 Ok(pos)
1784 }
1785}
1786
1787#[derive(Debug, Clone, PartialEq, Eq)]
1795#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1796pub struct CompressedModuleDescriptor<'a> {
1797 #[cfg_attr(feature = "serde", serde(borrow))]
1799 pub body: &'a [u8],
1800}
1801
1802#[cfg(feature = "flate2")]
1807pub fn decompress_zlib(data: &[u8]) -> Result<Vec<u8>> {
1808 use std::io::Read;
1809 let mut decoder = flate2::read::ZlibDecoder::new(data);
1810 let mut out = Vec::new();
1811 decoder
1812 .read_to_end(&mut out)
1813 .map_err(|e| Error::ReservedBitsViolation {
1814 field: "compressed_module_descriptor body",
1815 reason: if e.kind() == std::io::ErrorKind::InvalidData {
1816 "zlib decompression failed: invalid data"
1817 } else {
1818 "zlib decompression failed"
1819 },
1820 })?;
1821 Ok(out)
1822}
1823
1824#[derive(Debug, Clone, PartialEq, Eq)]
1832#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1833pub struct ServiceGatewayInfo<'a> {
1834 pub ior: Ior<'a>,
1836 #[cfg_attr(feature = "serde", serde(borrow))]
1839 pub download_taps: &'a [u8],
1840 #[cfg_attr(feature = "serde", serde(borrow))]
1842 pub service_context: Vec<ServiceContext<'a>>,
1843 #[cfg_attr(feature = "serde", serde(borrow))]
1845 pub user_info: &'a [u8],
1846}
1847
1848impl<'a> ServiceGatewayInfo<'a> {
1849 pub fn parse(bytes: &'a [u8]) -> Result<Self> {
1851 let end = bytes.len();
1852 let ior = Ior::parse(bytes)?;
1853 let mut pos = ior.serialized_len();
1854
1855 if pos + SGI_DOWNLOAD_TAPS_COUNT_FIELD > end {
1858 return Err(Error::BufferTooShort {
1859 need: pos + SGI_DOWNLOAD_TAPS_COUNT_FIELD,
1860 have: end,
1861 what: "ServiceGatewayInfo downloadTaps_count",
1862 });
1863 }
1864 let tap_count = bytes[pos] as usize;
1865 let dl_taps_start = pos;
1866 pos += SGI_DOWNLOAD_TAPS_COUNT_FIELD;
1867 for _ in 0..tap_count {
1868 let (_, next) = super::ior::Tap::parse_from(bytes, pos, end)?;
1869 pos = next;
1870 }
1871 let download_taps = &bytes[dl_taps_start..pos];
1872
1873 let (service_context, next) = parse_service_context_list(bytes, pos, end)?;
1875 pos = next;
1876
1877 if pos + SGI_USER_INFO_LEN_FIELD > end {
1879 return Err(Error::BufferTooShort {
1880 need: pos + SGI_USER_INFO_LEN_FIELD,
1881 have: end,
1882 what: "ServiceGatewayInfo userInfoLength",
1883 });
1884 }
1885 let ui_len = u16::from_be_bytes([bytes[pos], bytes[pos + 1]]) as usize;
1886 pos += SGI_USER_INFO_LEN_FIELD;
1887 if pos + ui_len > end {
1888 return Err(Error::SectionLengthOverflow {
1889 declared: ui_len,
1890 available: end - pos,
1891 });
1892 }
1893 let user_info = &bytes[pos..pos + ui_len];
1894
1895 Ok(ServiceGatewayInfo {
1896 ior,
1897 download_taps,
1898 service_context,
1899 user_info,
1900 })
1901 }
1902
1903 pub fn to_bytes(&self) -> Vec<u8> {
1906 let len = self.ior.serialized_len()
1907 + self.download_taps.len()
1908 + service_context_list_len(&self.service_context)
1909 + SGI_USER_INFO_LEN_FIELD
1910 + self.user_info.len();
1911 let mut buf = vec![0u8; len];
1912 let mut pos = 0;
1913 let written = self
1914 .ior
1915 .serialize_into(&mut buf[pos..])
1916 .expect("IOR serialize");
1917 pos += written;
1918 buf[pos..pos + self.download_taps.len()].copy_from_slice(self.download_taps);
1919 pos += self.download_taps.len();
1920 pos += write_service_context_list(&mut buf[pos..], &self.service_context)
1921 .expect("serviceContext fits");
1922 buf[pos..pos + 2].copy_from_slice(&(self.user_info.len() as u16).to_be_bytes());
1923 pos += SGI_USER_INFO_LEN_FIELD;
1924 buf[pos..pos + self.user_info.len()].copy_from_slice(self.user_info);
1925 buf
1926 }
1927}
1928
1929#[cfg(test)]
1932mod tests {
1933 use super::*;
1934 use dvb_common::Parse;
1935
1936 fn sample_file_message(key: &'static [u8], content: &'static [u8]) -> BiopMessage<'static> {
1938 BiopMessage::File(FileMessage {
1939 object_key: key,
1940 content_size: content.len() as u64,
1941 object_info_extra: &[],
1942 service_context: vec![],
1943 content,
1944 })
1945 }
1946
1947 fn sample_dir_message() -> BiopMessage<'static> {
1949 use crate::carousel::biop::ior::{
1950 BiopProfileBody, ConnBinder, ObjectLocation, TaggedProfile,
1951 };
1952 let ior = crate::carousel::biop::ior::Ior {
1953 type_id: b"fil\0",
1954 profiles: vec![TaggedProfile::Biop(BiopProfileBody {
1955 object_location: ObjectLocation {
1956 carousel_id: 0xAB,
1957 module_id: 2,
1958 version_major: 1,
1959 version_minor: 0,
1960 object_key: &[0x02],
1961 },
1962 conn_binder: ConnBinder { taps: vec![] },
1963 extra: vec![],
1964 })],
1965 };
1966 BiopMessage::Directory(DirectoryMessage {
1967 object_kind: *b"dir\0",
1968 object_key: &[0x01],
1969 object_info: &[],
1970 service_context: vec![],
1971 bindings: vec![Binding {
1972 name: vec![NameComponent {
1973 id: b"index.html",
1974 kind: b"fil\0",
1975 }],
1976 binding_type: BindingType::NObject,
1977 ior,
1978 object_info: &[],
1979 }],
1980 })
1981 }
1982
1983 #[test]
1984 fn file_message_round_trip() {
1985 let content: &[u8] = b"Hello, BIOP!";
1986 let msg = sample_file_message(&[0x01], content);
1987 let mut buf = vec![0u8; msg.serialized_len()];
1988 msg.serialize_into(&mut buf).unwrap();
1989 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
1990 assert_eq!(consumed, buf.len());
1991 assert_eq!(parsed, msg);
1992 let mut buf2 = vec![0u8; parsed.serialized_len()];
1994 parsed.serialize_into(&mut buf2).unwrap();
1995 assert_eq!(buf, buf2);
1996 }
1997
1998 #[test]
1999 fn directory_message_round_trip() {
2000 let msg = sample_dir_message();
2001 let mut buf = vec![0u8; msg.serialized_len()];
2002 msg.serialize_into(&mut buf).unwrap();
2003 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
2004 assert_eq!(consumed, buf.len());
2005 assert_eq!(parsed, msg);
2006 let mut buf2 = vec![0u8; parsed.serialized_len()];
2007 parsed.serialize_into(&mut buf2).unwrap();
2008 assert_eq!(buf, buf2, "Directory message byte-exact re-serialize");
2009 }
2010
2011 #[test]
2012 fn module_info_round_trip() {
2013 use crate::carousel::biop::ior::Tap;
2014 let info = ModuleInfo {
2015 module_timeout: 0x00FFFFFF,
2016 block_timeout: 0x00FFFFFF,
2017 min_block_time: 0x00000064,
2018 taps: vec![Tap {
2019 id: 0,
2020 use_: 0x0017,
2021 association_tag: 0x0042,
2022 selector: &[],
2023 }],
2024 user_info: &[],
2025 };
2026 let mut buf = vec![0u8; info.serialized_len()];
2027 info.serialize_into(&mut buf).unwrap();
2028 let parsed = ModuleInfo::parse(&buf).unwrap();
2029 assert_eq!(parsed, info);
2030 let mut buf2 = vec![0u8; parsed.serialized_len()];
2031 parsed.serialize_into(&mut buf2).unwrap();
2032 assert_eq!(buf, buf2, "ModuleInfo byte-exact re-serialize");
2033 }
2034
2035 #[test]
2036 fn module_info_byte_anchor() {
2037 use crate::carousel::biop::ior::Tap;
2038 #[rustfmt::skip]
2043 let expected: &[u8] = &[
2044 0x00, 0x0F, 0x42, 0x40, 0x00, 0x0F, 0x42, 0x40, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x47, 0x00, 0x00, ];
2054 let info = ModuleInfo {
2055 module_timeout: 0x000F4240,
2056 block_timeout: 0x000F4240,
2057 min_block_time: 0x00000064,
2058 taps: vec![Tap {
2059 id: 0,
2060 use_: 0x0017,
2061 association_tag: 0x0047,
2062 selector: &[],
2063 }],
2064 user_info: &[],
2065 };
2066 let mut buf = vec![0u8; info.serialized_len()];
2067 info.serialize_into(&mut buf).unwrap();
2068 assert_eq!(buf.as_slice(), expected);
2069 let parsed = ModuleInfo::parse(expected).unwrap();
2070 assert_eq!(parsed, info);
2071 }
2072
2073 #[test]
2074 fn sgi_byte_anchor_m6() {
2075 #[rustfmt::skip]
2078 let raw: &[u8] = &[
2079 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,
2097 0x00, 0x00, 0x00, 0x00, ];
2101 assert_eq!(raw.len(), 64);
2102
2103 let sgi = ServiceGatewayInfo::parse(raw).unwrap();
2104
2105 assert_eq!(sgi.ior.type_id, b"srg\0");
2107 assert_eq!(sgi.ior.profiles.len(), 1);
2108 let bp = sgi.ior.biop_profile().unwrap();
2109 assert_eq!(bp.object_location.carousel_id, 0xAB);
2110 assert_eq!(bp.object_location.module_id, 1);
2111 assert_eq!(bp.object_location.version_major, 1);
2112 assert_eq!(bp.object_location.version_minor, 0);
2113 assert_eq!(bp.object_location.object_key, &[0x01]);
2114 assert_eq!(bp.conn_binder.taps.len(), 1);
2115 let tap = &bp.conn_binder.taps[0];
2116 assert_eq!(tap.use_, 0x0016);
2117 assert_eq!(tap.association_tag, 0x47);
2118 assert_eq!(tap.transaction_id(), Some(0x80000002));
2119 assert_eq!(tap.timeout(), Some(0xFFFFFFFF));
2120
2121 let out = sgi.to_bytes();
2123 assert_eq!(out.len(), 64, "SGI serialized length");
2124 assert_eq!(out.as_slice(), raw, "SGI byte-exact round-trip");
2125 }
2126
2127 #[cfg(feature = "serde")]
2128 #[test]
2129 fn biop_serde_round_trip() {
2130 let content: &[u8] = b"test content";
2131 let msg = sample_file_message(&[0x01], content);
2132 let json = serde_json::to_string(&msg).unwrap();
2133 assert!(json.contains("content_size"));
2134 }
2135
2136 #[cfg(feature = "flate2")]
2137 #[test]
2138 fn zlib_round_trip() {
2139 use flate2::{write::ZlibEncoder, Compression};
2140 use std::io::Write;
2141
2142 let original = b"Hello, compressed BIOP world! ".repeat(10);
2143 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
2144 encoder.write_all(&original).unwrap();
2145 let compressed = encoder.finish().unwrap();
2146
2147 let decompressed = decompress_zlib(&compressed).unwrap();
2148 assert_eq!(decompressed.as_slice(), original.as_slice());
2149 }
2150
2151 #[test]
2154 fn stream_message_round_trip() {
2155 use crate::carousel::biop::ior::Tap;
2156 let msg = BiopMessage::Stream(StreamMessage {
2157 object_key: &[0x01, 0x02],
2158 stream_info: DsmStreamInfo {
2159 description: b"audio stream",
2160 duration_seconds: -5,
2161 duration_microseconds: 500,
2162 audio: 1,
2163 video: 0,
2164 data: 0,
2165 },
2166 object_info_extra: b"\xDE\xAD",
2167 service_context: vec![],
2168 taps: vec![
2169 Tap {
2170 id: 0,
2171 use_: 0x0018,
2172 association_tag: 0x0010,
2173 selector: &[],
2174 },
2175 Tap {
2176 id: 0,
2177 use_: 0x0019,
2178 association_tag: 0x0011,
2179 selector: &[],
2180 },
2181 ],
2182 });
2183 let mut buf = vec![0u8; msg.serialized_len()];
2184 msg.serialize_into(&mut buf).unwrap();
2185 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
2186 assert_eq!(consumed, buf.len(), "consumed must equal total buf len");
2187 assert_eq!(parsed, msg);
2188 let mut buf2 = vec![0u8; parsed.serialized_len()];
2189 parsed.serialize_into(&mut buf2).unwrap();
2190 assert_eq!(buf, buf2, "StreamMessage byte-exact re-serialize");
2191 }
2192
2193 #[test]
2194 fn stream_event_message_round_trip() {
2195 use crate::carousel::biop::ior::Tap;
2196 let msg = BiopMessage::StreamEvent(StreamEventMessage {
2197 object_key: &[0x03],
2198 stream_info: DsmStreamInfo {
2199 description: b"event stream",
2200 duration_seconds: 3600,
2201 duration_microseconds: 0,
2202 audio: 0,
2203 video: 1,
2204 data: 0,
2205 },
2206 event_names: vec![b"play".as_ref(), b"pause".as_ref(), b"stop".as_ref()],
2207 object_info_extra: &[],
2208 service_context: vec![],
2209 taps: vec![Tap {
2210 id: 0,
2211 use_: 0x000C,
2212 association_tag: 0x0020,
2213 selector: &[],
2214 }],
2215 event_ids: vec![0x0001, 0x0002, 0x0003],
2216 });
2217 let mut buf = vec![0u8; msg.serialized_len()];
2218 msg.serialize_into(&mut buf).unwrap();
2219 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
2220 assert_eq!(consumed, buf.len(), "consumed must equal total buf len");
2221 assert_eq!(parsed, msg);
2222 let mut buf2 = vec![0u8; parsed.serialized_len()];
2223 parsed.serialize_into(&mut buf2).unwrap();
2224 assert_eq!(buf, buf2, "StreamEventMessage byte-exact re-serialize");
2225 }
2226
2227 #[test]
2228 fn stream_message_byte_anchor() {
2229 use crate::carousel::biop::ior::Tap;
2262 #[rustfmt::skip]
2263 let expected: &[u8] = &[
2264 0x42, 0x49, 0x4F, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x01, 0xAB, 0x00, 0x00, 0x00, 0x04, 0x73, 0x74, 0x72, 0x00, 0x00, 0x0D, 0x03, 0x76, 0x69, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
2288 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x47, 0x00, ];
2297 assert_eq!(expected.len(), 50);
2298 let expected_msg = BiopMessage::Stream(StreamMessage {
2299 object_key: &[0xAB],
2300 stream_info: DsmStreamInfo {
2301 description: b"vid",
2302 duration_seconds: 0,
2303 duration_microseconds: 0,
2304 audio: 1,
2305 video: 1,
2306 data: 0,
2307 },
2308 object_info_extra: &[],
2309 service_context: vec![],
2310 taps: vec![Tap {
2311 id: 0,
2312 use_: 0x0018,
2313 association_tag: 0x0047,
2314 selector: &[],
2315 }],
2316 });
2317
2318 let mut buf = vec![0u8; expected_msg.serialized_len()];
2320 expected_msg.serialize_into(&mut buf).unwrap();
2321 assert_eq!(
2322 buf.as_slice(),
2323 expected,
2324 "StreamMessage serialize must match byte anchor"
2325 );
2326
2327 let (parsed, consumed) = BiopMessage::parse_at(expected).unwrap();
2329 assert_eq!(consumed, expected.len());
2330 assert_eq!(
2331 parsed, expected_msg,
2332 "StreamMessage parse must match byte anchor struct"
2333 );
2334 }
2335
2336 #[test]
2337 fn stream_event_message_byte_anchor() {
2338 #[rustfmt::skip]
2375 let expected: &[u8] = &[
2376 0x42, 0x49, 0x4F, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x01, 0xCD, 0x00, 0x00, 0x00, 0x04, 0x73, 0x74, 0x65, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x66, 0x6F, 0x6F, 0x03, 0x62, 0x61, 0x72, 0x00,
2406 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, ];
2414 assert_eq!(expected.len(), 55);
2415
2416 let expected_msg = BiopMessage::StreamEvent(StreamEventMessage {
2417 object_key: &[0xCD],
2418 stream_info: DsmStreamInfo {
2419 description: &[],
2420 duration_seconds: 0,
2421 duration_microseconds: 0,
2422 audio: 0,
2423 video: 0,
2424 data: 0,
2425 },
2426 event_names: vec![b"foo".as_ref(), b"bar".as_ref()],
2427 object_info_extra: &[],
2428 service_context: vec![],
2429 taps: vec![],
2430 event_ids: vec![1, 2],
2431 });
2432
2433 let mut buf = vec![0u8; expected_msg.serialized_len()];
2435 expected_msg.serialize_into(&mut buf).unwrap();
2436 assert_eq!(
2437 buf.as_slice(),
2438 expected,
2439 "StreamEventMessage serialize must match byte anchor"
2440 );
2441
2442 let (parsed, consumed) = BiopMessage::parse_at(expected).unwrap();
2444 assert_eq!(consumed, expected.len());
2445 assert_eq!(
2446 parsed, expected_msg,
2447 "StreamEventMessage parse must match byte anchor struct"
2448 );
2449 }
2450
2451 #[test]
2452 fn service_context_typed_round_trip() {
2453 let msg = BiopMessage::File(FileMessage {
2455 object_key: &[0x01],
2456 content_size: 3,
2457 object_info_extra: &[],
2458 service_context: vec![
2459 ServiceContext {
2460 context_id: 0xDEADBEEF,
2461 data: &[1, 2, 3],
2462 },
2463 ServiceContext {
2464 context_id: 0x11223344,
2465 data: &[],
2466 },
2467 ],
2468 content: b"abc",
2469 });
2470
2471 let mut buf = vec![0u8; msg.serialized_len()];
2473 msg.serialize_into(&mut buf).unwrap();
2474
2475 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
2477 assert_eq!(consumed, buf.len(), "consumed must equal total buf len");
2478 assert_eq!(parsed, msg, "parsed must equal original");
2479
2480 let mut buf2 = vec![0u8; parsed.serialized_len()];
2482 parsed.serialize_into(&mut buf2).unwrap();
2483 assert_eq!(
2484 buf, buf2,
2485 "serviceContext typed round-trip must be byte-exact"
2486 );
2487
2488 assert_eq!(buf[32], 2, "serviceContextList_count must be 2");
2492 assert_eq!(&buf[33..37], &[0xDE, 0xAD, 0xBE, 0xEF]);
2494 assert_eq!(&buf[37..39], &[0x00, 0x03]);
2496 assert_eq!(&buf[39..42], &[0x01, 0x02, 0x03]);
2498 assert_eq!(&buf[42..46], &[0x11, 0x22, 0x33, 0x44]);
2500 assert_eq!(&buf[46..48], &[0x00, 0x00]);
2502 }
2503
2504 #[test]
2505 fn binding_type_full_range_round_trip() {
2506 for v in 0u8..=0xFF {
2507 let bt = BindingType::from_u8(v);
2508 assert_eq!(bt.to_u8(), v, "BindingType round-trip failed for 0x{v:02X}");
2509 }
2510 }
2511
2512 #[test]
2513 fn binding_type_known_values() {
2514 assert_eq!(BindingType::from_u8(0x01), BindingType::NObject);
2515 assert_eq!(BindingType::from_u8(0x02), BindingType::NContext);
2516 assert_eq!(BindingType::NObject.name(), "nobject");
2517 assert_eq!(BindingType::NContext.name(), "ncontext");
2518 assert_eq!(BindingType::Reserved(0x05).name(), "reserved");
2519 }
2520
2521 #[test]
2522 fn directory_message_binding_type_round_trip() {
2523 let msg = sample_dir_message();
2524 let mut buf = vec![0u8; msg.serialized_len()];
2525 msg.serialize_into(&mut buf).unwrap();
2526 let (parsed, _) = BiopMessage::parse_at(&buf).unwrap();
2527 match parsed {
2528 BiopMessage::Directory(d) => {
2529 assert_eq!(d.bindings[0].binding_type, BindingType::NObject);
2530 }
2531 other => panic!("expected Directory, got {other:?}"),
2532 }
2533 }
2534}