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 let (boi, _) = bytes[cur..end]
187 .split_first_chunk::<2>()
188 .ok_or(Error::BufferTooShort {
189 need: cur + BINDING_OBJ_INFO_LEN_FIELD,
190 have: end,
191 what: "Binding objectInfo_length",
192 })?;
193 let obj_info_len = u16::from_be_bytes(*boi) 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 let (bhdr, _) = bytes
285 .split_first_chunk::<BIOP_HEADER_LEN>()
286 .ok_or(Error::BufferTooShort {
287 need: BIOP_HEADER_LEN,
288 have: total,
289 what: "BIOP message header",
290 })?;
291 let magic = u32::from_be_bytes([bhdr[0], bhdr[1], bhdr[2], bhdr[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 bhdr[4] != BIOP_VERSION_MAJOR || bhdr[5] != BIOP_VERSION_MINOR {
299 return Err(Error::ReservedBitsViolation {
300 field: "biop_version",
301 reason: "must be 1.0",
302 });
303 }
304 if bhdr[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([bhdr[8], bhdr[9], bhdr[10], bhdr[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 let (bkl, _) = bytes[pos..end]
342 .split_first_chunk::<4>()
343 .ok_or(Error::BufferTooShort {
344 need: pos + OBJECT_KIND_LEN_FIELD,
345 have: end,
346 what: "BIOP objectKind_length",
347 })?;
348 let kind_len = u32::from_be_bytes(*bkl) as usize;
349 pos += OBJECT_KIND_LEN_FIELD;
350 if kind_len != OBJECT_KIND_DATA_LEN {
351 return Err(Error::ValueOutOfRange {
352 field: "objectKind_length",
353 reason: "DVB BIOP objectKind must be exactly 4 bytes",
354 });
355 }
356 if pos + OBJECT_KIND_DATA_LEN > end {
357 return Err(Error::SectionLengthOverflow {
358 declared: OBJECT_KIND_DATA_LEN,
359 available: end - pos,
360 });
361 }
362 let mut kind_bytes = [0u8; 4];
363 kind_bytes.copy_from_slice(&bytes[pos..pos + 4]);
364 pos += OBJECT_KIND_DATA_LEN;
365
366 Ok((object_key, kind_bytes, message_size, pos))
367}
368
369fn parse_service_context_list<'a>(
372 bytes: &'a [u8],
373 pos: usize,
374 end: usize,
375) -> Result<(Vec<ServiceContext<'a>>, usize)> {
376 if pos + SERVICE_CONTEXT_COUNT_FIELD > end {
377 return Err(Error::BufferTooShort {
378 need: pos + SERVICE_CONTEXT_COUNT_FIELD,
379 have: end,
380 what: "serviceContextList_count",
381 });
382 }
383 let count = bytes[pos] as usize;
384 let mut cur = pos + SERVICE_CONTEXT_COUNT_FIELD;
385 let mut list = Vec::with_capacity(count.min(16));
386 for _ in 0..count {
387 let (sch, _) = bytes[cur..end]
388 .split_first_chunk::<SERVICE_CONTEXT_FIXED>()
389 .ok_or(Error::BufferTooShort {
390 need: cur + SERVICE_CONTEXT_FIXED,
391 have: end,
392 what: "serviceContext entry",
393 })?;
394 let context_id = u32::from_be_bytes([sch[0], sch[1], sch[2], sch[3]]);
395 let ctx_data_len = u16::from_be_bytes([sch[4], sch[5]]) as usize;
396 cur += SERVICE_CONTEXT_FIXED;
397 if cur + ctx_data_len > end {
398 return Err(Error::SectionLengthOverflow {
399 declared: ctx_data_len,
400 available: end - cur,
401 });
402 }
403 let data = &bytes[cur..cur + ctx_data_len];
404 cur += ctx_data_len;
405 list.push(ServiceContext { context_id, data });
406 }
407 Ok((list, cur))
408}
409
410fn service_context_list_len(list: &[ServiceContext]) -> usize {
412 SERVICE_CONTEXT_COUNT_FIELD
413 + list
414 .iter()
415 .map(|e| SERVICE_CONTEXT_FIXED + e.data.len())
416 .sum::<usize>()
417}
418
419fn write_service_context_list(buf: &mut [u8], list: &[ServiceContext]) -> Result<usize> {
421 if list.len() > u8::MAX as usize {
422 return Err(Error::SectionLengthOverflow {
423 declared: list.len(),
424 available: u8::MAX as usize,
425 });
426 }
427 buf[0] = list.len() as u8;
428 let mut pos = SERVICE_CONTEXT_COUNT_FIELD;
429 for entry in list {
430 if entry.data.len() > u16::MAX as usize {
431 return Err(Error::SectionLengthOverflow {
432 declared: entry.data.len(),
433 available: u16::MAX as usize,
434 });
435 }
436 buf[pos..pos + 4].copy_from_slice(&entry.context_id.to_be_bytes());
437 buf[pos + 4..pos + 6].copy_from_slice(&(entry.data.len() as u16).to_be_bytes());
438 pos += SERVICE_CONTEXT_FIXED;
439 buf[pos..pos + entry.data.len()].copy_from_slice(entry.data);
440 pos += entry.data.len();
441 }
442 Ok(pos)
443}
444
445fn write_biop_header(buf: &mut [u8], message_size: u32) {
447 buf[0..4].copy_from_slice(&BIOP_MAGIC.to_be_bytes());
448 buf[4] = BIOP_VERSION_MAJOR;
449 buf[5] = BIOP_VERSION_MINOR;
450 buf[6] = BYTE_ORDER_BIG_ENDIAN;
451 buf[7] = 0x00; buf[8..12].copy_from_slice(&message_size.to_be_bytes());
453}
454
455#[derive(Debug, Clone, PartialEq, Eq)]
460#[cfg_attr(feature = "serde", derive(serde::Serialize))]
461pub struct DirectoryMessage<'a> {
462 pub object_kind: [u8; 4],
464 #[cfg_attr(feature = "serde", serde(borrow))]
466 pub object_key: &'a [u8],
467 #[cfg_attr(feature = "serde", serde(borrow))]
469 pub object_info: &'a [u8],
470 #[cfg_attr(feature = "serde", serde(borrow))]
472 pub service_context: Vec<ServiceContext<'a>>,
473 pub bindings: Vec<Binding<'a>>,
475}
476
477impl<'a> DirectoryMessage<'a> {
478 pub fn is_service_gateway(&self) -> bool {
480 &self.object_kind == b"srg\0"
481 }
482
483 fn parse_from(
484 bytes: &'a [u8],
485 object_key: &'a [u8],
486 object_kind: [u8; 4],
487 pos: usize,
488 end: usize,
489 ) -> Result<Self> {
490 let mut cur = pos;
491
492 let (bdoi, _) = bytes[cur..end]
494 .split_first_chunk::<2>()
495 .ok_or(Error::BufferTooShort {
496 need: cur + OBJECT_INFO_LEN_FIELD,
497 have: end,
498 what: "DirectoryMessage objectInfo_length",
499 })?;
500 let obj_info_len = u16::from_be_bytes(*bdoi) as usize;
501 cur += OBJECT_INFO_LEN_FIELD;
502 if cur + obj_info_len > end {
503 return Err(Error::SectionLengthOverflow {
504 declared: obj_info_len,
505 available: end - cur,
506 });
507 }
508 let object_info = &bytes[cur..cur + obj_info_len];
509 cur += obj_info_len;
510
511 let (service_context, next) = parse_service_context_list(bytes, cur, end)?;
513 cur = next;
514
515 let (bbl, _) = bytes[cur..end]
517 .split_first_chunk::<4>()
518 .ok_or(Error::BufferTooShort {
519 need: cur + MESSAGE_BODY_LEN_FIELD,
520 have: end,
521 what: "DirectoryMessage messageBody_length",
522 })?;
523 let body_len = u32::from_be_bytes(*bbl) as usize;
524 cur += MESSAGE_BODY_LEN_FIELD;
525 let body_end = cur + body_len;
526 if body_end > end {
527 return Err(Error::SectionLengthOverflow {
528 declared: body_len,
529 available: end - cur,
530 });
531 }
532
533 let (bbc, _) =
535 bytes[cur..body_end]
536 .split_first_chunk::<2>()
537 .ok_or(Error::BufferTooShort {
538 need: cur + BINDINGS_COUNT_FIELD,
539 have: body_end,
540 what: "DirectoryMessage bindings_count",
541 })?;
542 let bindings_count = u16::from_be_bytes(*bbc) as usize;
543 cur += BINDINGS_COUNT_FIELD;
544
545 let mut bindings = Vec::with_capacity(bindings_count.min(256));
546 for _ in 0..bindings_count {
547 let (binding, next) = Binding::parse_from(bytes, cur, body_end)?;
548 bindings.push(binding);
549 cur = next;
550 }
551
552 Ok(DirectoryMessage {
553 object_kind,
554 object_key,
555 object_info,
556 service_context,
557 bindings,
558 })
559 }
560
561 fn body_len(&self) -> usize {
562 let bindings_len: usize = self.bindings.iter().map(|b| b.serialized_len()).sum();
563 BINDINGS_COUNT_FIELD + bindings_len
564 }
565
566 fn serialized_len_inner(&self) -> usize {
567 let key_part = OBJECT_KEY_LEN_FIELD
569 + self.object_key.len()
570 + OBJECT_KIND_LEN_FIELD
571 + OBJECT_KIND_DATA_LEN;
572 let info_part = OBJECT_INFO_LEN_FIELD + self.object_info.len();
573 let svc_ctx_part = service_context_list_len(&self.service_context);
574 let body_part = MESSAGE_BODY_LEN_FIELD + self.body_len();
575 key_part + info_part + svc_ctx_part + body_part
576 }
577
578 pub fn serialized_len_total(&self) -> usize {
580 BIOP_HEADER_LEN + self.serialized_len_inner()
581 }
582
583 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
584 let inner_len = self.serialized_len_inner();
585 let total = BIOP_HEADER_LEN + inner_len;
586 if buf.len() < total {
587 return Err(Error::OutputBufferTooSmall {
588 need: total,
589 have: buf.len(),
590 });
591 }
592 if inner_len > u32::MAX as usize {
593 return Err(Error::SectionLengthOverflow {
594 declared: inner_len,
595 available: u32::MAX as usize,
596 });
597 }
598 write_biop_header(buf, inner_len as u32);
599 let mut pos = BIOP_HEADER_LEN;
600
601 if self.object_key.len() > u8::MAX as usize {
603 return Err(Error::SectionLengthOverflow {
604 declared: self.object_key.len(),
605 available: u8::MAX as usize,
606 });
607 }
608 buf[pos] = self.object_key.len() as u8;
609 pos += OBJECT_KEY_LEN_FIELD;
610 buf[pos..pos + self.object_key.len()].copy_from_slice(self.object_key);
611 pos += self.object_key.len();
612
613 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
615 pos += OBJECT_KIND_LEN_FIELD;
616 buf[pos..pos + 4].copy_from_slice(&self.object_kind);
617 pos += OBJECT_KIND_DATA_LEN;
618
619 if self.object_info.len() > u16::MAX as usize {
621 return Err(Error::SectionLengthOverflow {
622 declared: self.object_info.len(),
623 available: u16::MAX as usize,
624 });
625 }
626 buf[pos..pos + 2].copy_from_slice(&(self.object_info.len() as u16).to_be_bytes());
627 pos += OBJECT_INFO_LEN_FIELD;
628 buf[pos..pos + self.object_info.len()].copy_from_slice(self.object_info);
629 pos += self.object_info.len();
630
631 pos += write_service_context_list(&mut buf[pos..], &self.service_context)?;
633
634 let body_len = self.body_len();
636 if body_len > u32::MAX as usize {
637 return Err(Error::SectionLengthOverflow {
638 declared: body_len,
639 available: u32::MAX as usize,
640 });
641 }
642 buf[pos..pos + 4].copy_from_slice(&(body_len as u32).to_be_bytes());
643 pos += MESSAGE_BODY_LEN_FIELD;
644
645 if self.bindings.len() > u16::MAX as usize {
647 return Err(Error::SectionLengthOverflow {
648 declared: self.bindings.len(),
649 available: u16::MAX as usize,
650 });
651 }
652 buf[pos..pos + 2].copy_from_slice(&(self.bindings.len() as u16).to_be_bytes());
653 pos += BINDINGS_COUNT_FIELD;
654
655 for binding in &self.bindings {
656 let written = binding.serialize_into_buf(&mut buf[pos..])?;
657 pos += written;
658 }
659
660 Ok(total)
661 }
662}
663
664#[derive(Debug, Clone, PartialEq, Eq)]
671#[cfg_attr(feature = "serde", derive(serde::Serialize))]
672pub struct FileMessage<'a> {
673 #[cfg_attr(feature = "serde", serde(borrow))]
675 pub object_key: &'a [u8],
676 pub content_size: u64,
678 #[cfg_attr(feature = "serde", serde(borrow))]
680 pub object_info_extra: &'a [u8],
681 #[cfg_attr(feature = "serde", serde(borrow))]
683 pub service_context: Vec<ServiceContext<'a>>,
684 #[cfg_attr(feature = "serde", serde(borrow))]
686 pub content: &'a [u8],
687}
688
689impl<'a> FileMessage<'a> {
690 fn parse_from(bytes: &'a [u8], object_key: &'a [u8], pos: usize, end: usize) -> Result<Self> {
691 let mut cur = pos;
692
693 let (bfoi, _) = bytes[cur..end]
695 .split_first_chunk::<2>()
696 .ok_or(Error::BufferTooShort {
697 need: cur + OBJECT_INFO_LEN_FIELD,
698 have: end,
699 what: "FileMessage objectInfo_length",
700 })?;
701 let obj_info_len = u16::from_be_bytes(*bfoi) as usize;
702 cur += OBJECT_INFO_LEN_FIELD;
703 if obj_info_len < FILE_CONTENT_SIZE_LEN {
704 return Err(Error::ValueOutOfRange {
705 field: "FileMessage.objectInfo_length",
706 reason: "FileMessage objectInfo must be at least 8 bytes (ContentSize)",
707 });
708 }
709 if cur + obj_info_len > end {
710 return Err(Error::SectionLengthOverflow {
711 declared: obj_info_len,
712 available: end - cur,
713 });
714 }
715 let (bcs, _) =
716 bytes[cur..end]
717 .split_first_chunk::<8>()
718 .ok_or(Error::SectionLengthOverflow {
719 declared: obj_info_len,
720 available: end - cur,
721 })?;
722 let content_size = u64::from_be_bytes(*bcs);
723 let object_info_extra = &bytes[cur + FILE_CONTENT_SIZE_LEN..cur + obj_info_len];
724 cur += obj_info_len;
725
726 let (service_context, next) = parse_service_context_list(bytes, cur, end)?;
728 cur = next;
729
730 let (bfbl, _) = bytes[cur..end]
732 .split_first_chunk::<4>()
733 .ok_or(Error::BufferTooShort {
734 need: cur + MESSAGE_BODY_LEN_FIELD,
735 have: end,
736 what: "FileMessage messageBody_length",
737 })?;
738 let body_len = u32::from_be_bytes(*bfbl) as usize;
739 cur += MESSAGE_BODY_LEN_FIELD;
740 let body_end = cur + body_len;
741 if body_end > end {
742 return Err(Error::SectionLengthOverflow {
743 declared: body_len,
744 available: end - cur,
745 });
746 }
747
748 let (bfcl, _) =
750 bytes[cur..body_end]
751 .split_first_chunk::<4>()
752 .ok_or(Error::BufferTooShort {
753 need: cur + FILE_CONTENT_LEN_FIELD,
754 have: body_end,
755 what: "FileMessage content_length",
756 })?;
757 let content_len = u32::from_be_bytes(*bfcl) as usize;
758 cur += FILE_CONTENT_LEN_FIELD;
759 if cur + content_len > body_end {
760 return Err(Error::SectionLengthOverflow {
761 declared: content_len,
762 available: body_end - cur,
763 });
764 }
765 let content = &bytes[cur..cur + content_len];
766
767 Ok(FileMessage {
768 object_key,
769 content_size,
770 object_info_extra,
771 service_context,
772 content,
773 })
774 }
775
776 fn serialized_len_inner(&self) -> usize {
777 let obj_info_total = FILE_CONTENT_SIZE_LEN + self.object_info_extra.len();
778 OBJECT_KEY_LEN_FIELD
779 + self.object_key.len()
780 + OBJECT_KIND_LEN_FIELD
781 + OBJECT_KIND_DATA_LEN
782 + OBJECT_INFO_LEN_FIELD
783 + obj_info_total
784 + service_context_list_len(&self.service_context)
785 + MESSAGE_BODY_LEN_FIELD
786 + FILE_CONTENT_LEN_FIELD
787 + self.content.len()
788 }
789
790 pub fn serialized_len_total(&self) -> usize {
792 BIOP_HEADER_LEN + self.serialized_len_inner()
793 }
794
795 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
796 let inner_len = self.serialized_len_inner();
797 let total = BIOP_HEADER_LEN + inner_len;
798 if buf.len() < total {
799 return Err(Error::OutputBufferTooSmall {
800 need: total,
801 have: buf.len(),
802 });
803 }
804 write_biop_header(buf, inner_len as u32);
805 let mut pos = BIOP_HEADER_LEN;
806
807 if self.object_key.len() > u8::MAX as usize {
808 return Err(Error::SectionLengthOverflow {
809 declared: self.object_key.len(),
810 available: u8::MAX as usize,
811 });
812 }
813 buf[pos] = self.object_key.len() as u8;
814 pos += OBJECT_KEY_LEN_FIELD;
815 buf[pos..pos + self.object_key.len()].copy_from_slice(self.object_key);
816 pos += self.object_key.len();
817
818 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
820 pos += OBJECT_KIND_LEN_FIELD;
821 buf[pos..pos + 4].copy_from_slice(b"fil\0");
822 pos += OBJECT_KIND_DATA_LEN;
823
824 let obj_info_total = FILE_CONTENT_SIZE_LEN + self.object_info_extra.len();
826 if obj_info_total > u16::MAX as usize {
827 return Err(Error::SectionLengthOverflow {
828 declared: obj_info_total,
829 available: u16::MAX as usize,
830 });
831 }
832 buf[pos..pos + 2].copy_from_slice(&(obj_info_total as u16).to_be_bytes());
833 pos += OBJECT_INFO_LEN_FIELD;
834 buf[pos..pos + 8].copy_from_slice(&self.content_size.to_be_bytes());
835 pos += FILE_CONTENT_SIZE_LEN;
836 buf[pos..pos + self.object_info_extra.len()].copy_from_slice(self.object_info_extra);
837 pos += self.object_info_extra.len();
838
839 pos += write_service_context_list(&mut buf[pos..], &self.service_context)?;
841
842 let body_len = FILE_CONTENT_LEN_FIELD + self.content.len();
844 buf[pos..pos + 4].copy_from_slice(&(body_len as u32).to_be_bytes());
845 pos += MESSAGE_BODY_LEN_FIELD;
846 buf[pos..pos + 4].copy_from_slice(&(self.content.len() as u32).to_be_bytes());
847 pos += FILE_CONTENT_LEN_FIELD;
848 buf[pos..pos + self.content.len()].copy_from_slice(self.content);
849
850 Ok(total)
851 }
852}
853
854#[derive(Debug, Clone, PartialEq, Eq)]
860#[cfg_attr(feature = "serde", derive(serde::Serialize))]
861pub struct DsmStreamInfo<'a> {
862 #[cfg_attr(feature = "serde", serde(borrow))]
864 pub description: &'a [u8],
865 pub duration_seconds: i32,
867 pub duration_microseconds: u16,
869 pub audio: u8,
871 pub video: u8,
873 pub data: u8,
875}
876
877impl<'a> DsmStreamInfo<'a> {
878 fn serialized_len(&self) -> usize {
880 STREAM_ADESC_LEN_FIELD + self.description.len() + STREAM_INFO_FIXED
881 }
882
883 fn parse_from(bytes: &'a [u8], pos: usize, end: usize) -> Result<(Self, usize)> {
885 if pos + STREAM_ADESC_LEN_FIELD > end {
887 return Err(Error::BufferTooShort {
888 need: pos + STREAM_ADESC_LEN_FIELD,
889 have: end,
890 what: "DsmStreamInfo aDescription_length",
891 });
892 }
893 let desc_len = bytes[pos] as usize;
894 let mut cur = pos + STREAM_ADESC_LEN_FIELD;
895
896 if cur + desc_len > end {
898 return Err(Error::SectionLengthOverflow {
899 declared: desc_len,
900 available: end - cur,
901 });
902 }
903 let description = &bytes[cur..cur + desc_len];
904 cur += desc_len;
905
906 let (sif, _) = bytes[cur..end]
908 .split_first_chunk::<STREAM_INFO_FIXED>()
909 .ok_or(Error::BufferTooShort {
910 need: cur + STREAM_INFO_FIXED,
911 have: end,
912 what: "DsmStreamInfo fixed fields",
913 })?;
914 let duration_seconds = i32::from_be_bytes([sif[0], sif[1], sif[2], sif[3]]);
915 let duration_microseconds = u16::from_be_bytes([sif[4], sif[5]]);
916 let audio = sif[6];
917 let video = sif[7];
918 let data = sif[8];
919 cur += STREAM_INFO_FIXED;
920
921 Ok((
922 DsmStreamInfo {
923 description,
924 duration_seconds,
925 duration_microseconds,
926 audio,
927 video,
928 data,
929 },
930 cur,
931 ))
932 }
933
934 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
935 let len = self.serialized_len();
936 if buf.len() < len {
937 return Err(Error::OutputBufferTooSmall {
938 need: len,
939 have: buf.len(),
940 });
941 }
942 if self.description.len() > u8::MAX as usize {
943 return Err(Error::SectionLengthOverflow {
944 declared: self.description.len(),
945 available: u8::MAX as usize,
946 });
947 }
948 buf[0] = self.description.len() as u8;
949 let mut pos = STREAM_ADESC_LEN_FIELD;
950 buf[pos..pos + self.description.len()].copy_from_slice(self.description);
951 pos += self.description.len();
952 buf[pos..pos + 4].copy_from_slice(&self.duration_seconds.to_be_bytes());
953 pos += 4;
954 buf[pos..pos + 2].copy_from_slice(&self.duration_microseconds.to_be_bytes());
955 pos += 2;
956 buf[pos] = self.audio;
957 pos += 1;
958 buf[pos] = self.video;
959 pos += 1;
960 buf[pos] = self.data;
961 pos += 1;
962 Ok(pos)
963 }
964}
965
966#[derive(Debug, Clone, PartialEq, Eq)]
971#[cfg_attr(feature = "serde", derive(serde::Serialize))]
972pub struct StreamMessage<'a> {
973 #[cfg_attr(feature = "serde", serde(borrow))]
975 pub object_key: &'a [u8],
976 pub stream_info: DsmStreamInfo<'a>,
978 #[cfg_attr(feature = "serde", serde(borrow))]
980 pub object_info_extra: &'a [u8],
981 #[cfg_attr(feature = "serde", serde(borrow))]
983 pub service_context: Vec<ServiceContext<'a>>,
984 pub taps: Vec<super::ior::Tap<'a>>,
986}
987
988impl<'a> StreamMessage<'a> {
989 fn parse_from(bytes: &'a [u8], object_key: &'a [u8], pos: usize, end: usize) -> Result<Self> {
990 let mut cur = pos;
991
992 let (bsmoi, _) = bytes[cur..end]
994 .split_first_chunk::<2>()
995 .ok_or(Error::BufferTooShort {
996 need: cur + OBJECT_INFO_LEN_FIELD,
997 have: end,
998 what: "StreamMessage objectInfo_length",
999 })?;
1000 let obj_info_len = u16::from_be_bytes(*bsmoi) as usize;
1001 cur += OBJECT_INFO_LEN_FIELD;
1002 if cur + obj_info_len > end {
1003 return Err(Error::SectionLengthOverflow {
1004 declared: obj_info_len,
1005 available: end - cur,
1006 });
1007 }
1008 let obj_info_start = cur;
1009 let obj_info_end = cur + obj_info_len;
1010
1011 let (stream_info, _) = DsmStreamInfo::parse_from(bytes, cur, obj_info_end)?;
1013 let info_len = stream_info.serialized_len();
1014 if obj_info_len < info_len {
1015 return Err(Error::ValueOutOfRange {
1016 field: "StreamMessage.objectInfo_length",
1017 reason: "objectInfo too short for DSM::Stream::Info_T",
1018 });
1019 }
1020 let object_info_extra = &bytes[obj_info_start + info_len..obj_info_end];
1021 cur = obj_info_end;
1022
1023 let (service_context, next) = parse_service_context_list(bytes, cur, end)?;
1025 cur = next;
1026
1027 let (bsmbl, _) = bytes[cur..end]
1029 .split_first_chunk::<4>()
1030 .ok_or(Error::BufferTooShort {
1031 need: cur + MESSAGE_BODY_LEN_FIELD,
1032 have: end,
1033 what: "StreamMessage messageBody_length",
1034 })?;
1035 let body_len = u32::from_be_bytes(*bsmbl) as usize;
1036 cur += MESSAGE_BODY_LEN_FIELD;
1037 let body_end = cur + body_len;
1038 if body_end > end {
1039 return Err(Error::SectionLengthOverflow {
1040 declared: body_len,
1041 available: end - cur,
1042 });
1043 }
1044
1045 if cur + STREAM_TAPS_COUNT_FIELD > body_end {
1047 return Err(Error::BufferTooShort {
1048 need: cur + STREAM_TAPS_COUNT_FIELD,
1049 have: body_end,
1050 what: "StreamMessage taps_count",
1051 });
1052 }
1053 let taps_count = bytes[cur] as usize;
1054 cur += STREAM_TAPS_COUNT_FIELD;
1055
1056 let mut taps = Vec::with_capacity(taps_count.min(16));
1057 for _ in 0..taps_count {
1058 let (tap, next) = super::ior::Tap::parse_from(bytes, cur, body_end)?;
1059 taps.push(tap);
1060 cur = next;
1061 }
1062
1063 Ok(StreamMessage {
1064 object_key,
1065 stream_info,
1066 object_info_extra,
1067 service_context,
1068 taps,
1069 })
1070 }
1071
1072 fn body_len(&self) -> usize {
1073 let taps_len: usize = self.taps.iter().map(|t| t.serialized_len()).sum();
1074 STREAM_TAPS_COUNT_FIELD + taps_len
1075 }
1076
1077 fn obj_info_len(&self) -> usize {
1078 self.stream_info.serialized_len() + self.object_info_extra.len()
1079 }
1080
1081 fn serialized_len_inner(&self) -> usize {
1082 OBJECT_KEY_LEN_FIELD
1083 + self.object_key.len()
1084 + OBJECT_KIND_LEN_FIELD
1085 + OBJECT_KIND_DATA_LEN
1086 + OBJECT_INFO_LEN_FIELD
1087 + self.obj_info_len()
1088 + service_context_list_len(&self.service_context)
1089 + MESSAGE_BODY_LEN_FIELD
1090 + self.body_len()
1091 }
1092
1093 pub fn serialized_len_total(&self) -> usize {
1095 BIOP_HEADER_LEN + self.serialized_len_inner()
1096 }
1097
1098 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
1099 let inner_len = self.serialized_len_inner();
1100 let total = BIOP_HEADER_LEN + inner_len;
1101 if buf.len() < total {
1102 return Err(Error::OutputBufferTooSmall {
1103 need: total,
1104 have: buf.len(),
1105 });
1106 }
1107 write_biop_header(buf, inner_len as u32);
1108 let mut pos = BIOP_HEADER_LEN;
1109
1110 if self.object_key.len() > u8::MAX as usize {
1112 return Err(Error::SectionLengthOverflow {
1113 declared: self.object_key.len(),
1114 available: u8::MAX as usize,
1115 });
1116 }
1117 buf[pos] = self.object_key.len() as u8;
1118 pos += OBJECT_KEY_LEN_FIELD;
1119 buf[pos..pos + self.object_key.len()].copy_from_slice(self.object_key);
1120 pos += self.object_key.len();
1121
1122 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
1124 pos += OBJECT_KIND_LEN_FIELD;
1125 buf[pos..pos + 4].copy_from_slice(b"str\0");
1126 pos += OBJECT_KIND_DATA_LEN;
1127
1128 let oi_len = self.obj_info_len();
1130 if oi_len > u16::MAX as usize {
1131 return Err(Error::SectionLengthOverflow {
1132 declared: oi_len,
1133 available: u16::MAX as usize,
1134 });
1135 }
1136 buf[pos..pos + 2].copy_from_slice(&(oi_len as u16).to_be_bytes());
1137 pos += OBJECT_INFO_LEN_FIELD;
1138
1139 let written = self.stream_info.serialize_into_buf(&mut buf[pos..])?;
1141 pos += written;
1142
1143 buf[pos..pos + self.object_info_extra.len()].copy_from_slice(self.object_info_extra);
1145 pos += self.object_info_extra.len();
1146
1147 pos += write_service_context_list(&mut buf[pos..], &self.service_context)?;
1149
1150 let bl = self.body_len();
1152 buf[pos..pos + 4].copy_from_slice(&(bl as u32).to_be_bytes());
1153 pos += MESSAGE_BODY_LEN_FIELD;
1154
1155 if self.taps.len() > u8::MAX as usize {
1157 return Err(Error::SectionLengthOverflow {
1158 declared: self.taps.len(),
1159 available: u8::MAX as usize,
1160 });
1161 }
1162 buf[pos] = self.taps.len() as u8;
1163 pos += STREAM_TAPS_COUNT_FIELD;
1164 for tap in &self.taps {
1165 let written = tap.serialize_into_buf(&mut buf[pos..])?;
1166 pos += written;
1167 }
1168
1169 Ok(total)
1170 }
1171}
1172
1173#[derive(Debug, Clone, PartialEq, Eq)]
1178#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1179pub struct StreamEventMessage<'a> {
1180 #[cfg_attr(feature = "serde", serde(borrow))]
1182 pub object_key: &'a [u8],
1183 pub stream_info: DsmStreamInfo<'a>,
1185 pub event_names: Vec<&'a [u8]>,
1188 #[cfg_attr(feature = "serde", serde(borrow))]
1190 pub object_info_extra: &'a [u8],
1191 #[cfg_attr(feature = "serde", serde(borrow))]
1193 pub service_context: Vec<ServiceContext<'a>>,
1194 pub taps: Vec<super::ior::Tap<'a>>,
1196 pub event_ids: Vec<u16>,
1198}
1199
1200impl<'a> StreamEventMessage<'a> {
1201 fn parse_from(bytes: &'a [u8], object_key: &'a [u8], pos: usize, end: usize) -> Result<Self> {
1202 let mut cur = pos;
1203
1204 let (bseoi, _) = bytes[cur..end]
1206 .split_first_chunk::<2>()
1207 .ok_or(Error::BufferTooShort {
1208 need: cur + OBJECT_INFO_LEN_FIELD,
1209 have: end,
1210 what: "StreamEventMessage objectInfo_length",
1211 })?;
1212 let obj_info_len = u16::from_be_bytes(*bseoi) as usize;
1213 cur += OBJECT_INFO_LEN_FIELD;
1214 if cur + obj_info_len > end {
1215 return Err(Error::SectionLengthOverflow {
1216 declared: obj_info_len,
1217 available: end - cur,
1218 });
1219 }
1220 let obj_info_end = cur + obj_info_len;
1221
1222 let (stream_info, next_cur) = DsmStreamInfo::parse_from(bytes, cur, obj_info_end)?;
1224 cur = next_cur;
1225
1226 let (benc, _) =
1228 bytes[cur..obj_info_end]
1229 .split_first_chunk::<2>()
1230 .ok_or(Error::BufferTooShort {
1231 need: cur + STREAM_EVENT_NAMES_COUNT_FIELD,
1232 have: obj_info_end,
1233 what: "StreamEventMessage eventNames_count",
1234 })?;
1235 let event_names_count = u16::from_be_bytes(*benc) as usize;
1236 cur += STREAM_EVENT_NAMES_COUNT_FIELD;
1237
1238 let mut event_names = Vec::with_capacity(event_names_count.min(64));
1239 for _ in 0..event_names_count {
1240 if cur + STREAM_EVENT_NAME_LEN_FIELD > obj_info_end {
1241 return Err(Error::BufferTooShort {
1242 need: cur + STREAM_EVENT_NAME_LEN_FIELD,
1243 have: obj_info_end,
1244 what: "StreamEventMessage eventName_length",
1245 });
1246 }
1247 let name_len = bytes[cur] as usize;
1248 cur += STREAM_EVENT_NAME_LEN_FIELD;
1249 if cur + name_len > obj_info_end {
1250 return Err(Error::SectionLengthOverflow {
1251 declared: name_len,
1252 available: obj_info_end - cur,
1253 });
1254 }
1255 event_names.push(&bytes[cur..cur + name_len]);
1256 cur += name_len;
1257 }
1258
1259 let object_info_extra = &bytes[cur..obj_info_end];
1261 cur = obj_info_end;
1262
1263 let (service_context, next) = parse_service_context_list(bytes, cur, end)?;
1265 cur = next;
1266
1267 let (bsebl, _) = bytes[cur..end]
1269 .split_first_chunk::<4>()
1270 .ok_or(Error::BufferTooShort {
1271 need: cur + MESSAGE_BODY_LEN_FIELD,
1272 have: end,
1273 what: "StreamEventMessage messageBody_length",
1274 })?;
1275 let body_len = u32::from_be_bytes(*bsebl) as usize;
1276 cur += MESSAGE_BODY_LEN_FIELD;
1277 let body_end = cur + body_len;
1278 if body_end > end {
1279 return Err(Error::SectionLengthOverflow {
1280 declared: body_len,
1281 available: end - cur,
1282 });
1283 }
1284
1285 if cur + STREAM_TAPS_COUNT_FIELD > body_end {
1287 return Err(Error::BufferTooShort {
1288 need: cur + STREAM_TAPS_COUNT_FIELD,
1289 have: body_end,
1290 what: "StreamEventMessage taps_count",
1291 });
1292 }
1293 let taps_count = bytes[cur] as usize;
1294 cur += STREAM_TAPS_COUNT_FIELD;
1295
1296 let mut taps = Vec::with_capacity(taps_count.min(16));
1297 for _ in 0..taps_count {
1298 let (tap, next) = super::ior::Tap::parse_from(bytes, cur, body_end)?;
1299 taps.push(tap);
1300 cur = next;
1301 }
1302
1303 if cur + STREAM_EVENT_IDS_COUNT_FIELD > body_end {
1305 return Err(Error::BufferTooShort {
1306 need: cur + STREAM_EVENT_IDS_COUNT_FIELD,
1307 have: body_end,
1308 what: "StreamEventMessage eventIds_count",
1309 });
1310 }
1311 let event_ids_count = bytes[cur] as usize;
1312 cur += STREAM_EVENT_IDS_COUNT_FIELD;
1313 if event_ids_count != event_names_count {
1314 return Err(Error::ValueOutOfRange {
1315 field: "StreamEventMessage.eventIds_count",
1316 reason: "eventIds_count must equal eventNames_count",
1317 });
1318 }
1319
1320 let mut event_ids = Vec::with_capacity(event_ids_count.min(64));
1321 for _ in 0..event_ids_count {
1322 let (bei, _) =
1323 bytes[cur..body_end]
1324 .split_first_chunk::<2>()
1325 .ok_or(Error::BufferTooShort {
1326 need: cur + STREAM_EVENT_ID_LEN,
1327 have: body_end,
1328 what: "StreamEventMessage eventId",
1329 })?;
1330 event_ids.push(u16::from_be_bytes(*bei));
1331 cur += STREAM_EVENT_ID_LEN;
1332 }
1333
1334 let _ = cur; Ok(StreamEventMessage {
1336 object_key,
1337 stream_info,
1338 event_names,
1339 object_info_extra,
1340 service_context,
1341 taps,
1342 event_ids,
1343 })
1344 }
1345
1346 fn event_list_wire_len(&self) -> usize {
1348 let names_len: usize = self
1349 .event_names
1350 .iter()
1351 .map(|n| STREAM_EVENT_NAME_LEN_FIELD + n.len())
1352 .sum();
1353 STREAM_EVENT_NAMES_COUNT_FIELD + names_len
1354 }
1355
1356 fn body_len(&self) -> usize {
1357 let taps_len: usize = self.taps.iter().map(|t| t.serialized_len()).sum();
1358 STREAM_TAPS_COUNT_FIELD
1359 + taps_len
1360 + STREAM_EVENT_IDS_COUNT_FIELD
1361 + self.event_ids.len() * STREAM_EVENT_ID_LEN
1362 }
1363
1364 fn obj_info_len(&self) -> usize {
1365 self.stream_info.serialized_len()
1366 + self.event_list_wire_len()
1367 + self.object_info_extra.len()
1368 }
1369
1370 fn serialized_len_inner(&self) -> usize {
1371 OBJECT_KEY_LEN_FIELD
1372 + self.object_key.len()
1373 + OBJECT_KIND_LEN_FIELD
1374 + OBJECT_KIND_DATA_LEN
1375 + OBJECT_INFO_LEN_FIELD
1376 + self.obj_info_len()
1377 + service_context_list_len(&self.service_context)
1378 + MESSAGE_BODY_LEN_FIELD
1379 + self.body_len()
1380 }
1381
1382 pub fn serialized_len_total(&self) -> usize {
1384 BIOP_HEADER_LEN + self.serialized_len_inner()
1385 }
1386
1387 fn serialize_into_buf(&self, buf: &mut [u8]) -> Result<usize> {
1388 let inner_len = self.serialized_len_inner();
1389 let total = BIOP_HEADER_LEN + inner_len;
1390 if buf.len() < total {
1391 return Err(Error::OutputBufferTooSmall {
1392 need: total,
1393 have: buf.len(),
1394 });
1395 }
1396 write_biop_header(buf, inner_len as u32);
1397 let mut pos = BIOP_HEADER_LEN;
1398
1399 if self.object_key.len() > u8::MAX as usize {
1401 return Err(Error::SectionLengthOverflow {
1402 declared: self.object_key.len(),
1403 available: u8::MAX as usize,
1404 });
1405 }
1406 buf[pos] = self.object_key.len() as u8;
1407 pos += OBJECT_KEY_LEN_FIELD;
1408 buf[pos..pos + self.object_key.len()].copy_from_slice(self.object_key);
1409 pos += self.object_key.len();
1410
1411 buf[pos..pos + 4].copy_from_slice(&(OBJECT_KIND_DATA_LEN as u32).to_be_bytes());
1413 pos += OBJECT_KIND_LEN_FIELD;
1414 buf[pos..pos + 4].copy_from_slice(b"ste\0");
1415 pos += OBJECT_KIND_DATA_LEN;
1416
1417 let oi_len = self.obj_info_len();
1419 if oi_len > u16::MAX as usize {
1420 return Err(Error::SectionLengthOverflow {
1421 declared: oi_len,
1422 available: u16::MAX as usize,
1423 });
1424 }
1425 buf[pos..pos + 2].copy_from_slice(&(oi_len as u16).to_be_bytes());
1426 pos += OBJECT_INFO_LEN_FIELD;
1427
1428 let written = self.stream_info.serialize_into_buf(&mut buf[pos..])?;
1430 pos += written;
1431
1432 if self.event_names.len() > u16::MAX as usize {
1434 return Err(Error::SectionLengthOverflow {
1435 declared: self.event_names.len(),
1436 available: u16::MAX as usize,
1437 });
1438 }
1439 buf[pos..pos + 2].copy_from_slice(&(self.event_names.len() as u16).to_be_bytes());
1440 pos += STREAM_EVENT_NAMES_COUNT_FIELD;
1441 for name in &self.event_names {
1442 if name.len() > u8::MAX as usize {
1443 return Err(Error::SectionLengthOverflow {
1444 declared: name.len(),
1445 available: u8::MAX as usize,
1446 });
1447 }
1448 buf[pos] = name.len() as u8;
1449 pos += STREAM_EVENT_NAME_LEN_FIELD;
1450 buf[pos..pos + name.len()].copy_from_slice(name);
1451 pos += name.len();
1452 }
1453
1454 buf[pos..pos + self.object_info_extra.len()].copy_from_slice(self.object_info_extra);
1456 pos += self.object_info_extra.len();
1457
1458 pos += write_service_context_list(&mut buf[pos..], &self.service_context)?;
1460
1461 let bl = self.body_len();
1463 buf[pos..pos + 4].copy_from_slice(&(bl as u32).to_be_bytes());
1464 pos += MESSAGE_BODY_LEN_FIELD;
1465
1466 if self.taps.len() > u8::MAX as usize {
1468 return Err(Error::SectionLengthOverflow {
1469 declared: self.taps.len(),
1470 available: u8::MAX as usize,
1471 });
1472 }
1473 buf[pos] = self.taps.len() as u8;
1474 pos += STREAM_TAPS_COUNT_FIELD;
1475 for tap in &self.taps {
1476 let written = tap.serialize_into_buf(&mut buf[pos..])?;
1477 pos += written;
1478 }
1479
1480 if self.event_ids.len() > u8::MAX as usize {
1482 return Err(Error::SectionLengthOverflow {
1483 declared: self.event_ids.len(),
1484 available: u8::MAX as usize,
1485 });
1486 }
1487 buf[pos] = self.event_ids.len() as u8;
1488 pos += STREAM_EVENT_IDS_COUNT_FIELD;
1489 for &id in &self.event_ids {
1490 buf[pos..pos + 2].copy_from_slice(&id.to_be_bytes());
1491 pos += STREAM_EVENT_ID_LEN;
1492 }
1493
1494 Ok(total)
1495 }
1496}
1497
1498#[derive(Debug, Clone, PartialEq, Eq)]
1503#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1504#[non_exhaustive]
1505pub enum BiopMessage<'a> {
1506 Directory(DirectoryMessage<'a>),
1508 File(FileMessage<'a>),
1510 ServiceGateway(DirectoryMessage<'a>),
1512 Stream(StreamMessage<'a>),
1514 StreamEvent(StreamEventMessage<'a>),
1516}
1517
1518impl<'a> BiopMessage<'a> {
1519 pub fn parse_at(bytes: &'a [u8]) -> Result<(Self, usize)> {
1524 let (object_key, kind_bytes, message_size, pos) = parse_biop_header(bytes)?;
1525 let consumed = BIOP_HEADER_LEN + message_size;
1526 let end = consumed;
1527
1528 let msg = match &kind_bytes {
1529 b"dir\0" => {
1530 let dm = DirectoryMessage::parse_from(bytes, object_key, kind_bytes, pos, end)?;
1531 BiopMessage::Directory(dm)
1532 }
1533 b"srg\0" => {
1534 let dm = DirectoryMessage::parse_from(bytes, object_key, kind_bytes, pos, end)?;
1535 BiopMessage::ServiceGateway(dm)
1536 }
1537 b"fil\0" => {
1538 let fm = FileMessage::parse_from(bytes, object_key, pos, end)?;
1539 BiopMessage::File(fm)
1540 }
1541 b"str\0" => {
1542 let sm = StreamMessage::parse_from(bytes, object_key, pos, end)?;
1543 BiopMessage::Stream(sm)
1544 }
1545 b"ste\0" => {
1546 let se = StreamEventMessage::parse_from(bytes, object_key, pos, end)?;
1547 BiopMessage::StreamEvent(se)
1548 }
1549 _ => {
1550 return Err(Error::ValueOutOfRange {
1551 field: "BiopMessage.objectKind",
1552 reason: "unknown BIOP objectKind",
1553 });
1554 }
1555 };
1556
1557 Ok((msg, consumed))
1558 }
1559
1560 fn serialized_len_total(&self) -> usize {
1561 match self {
1562 Self::Directory(d) | Self::ServiceGateway(d) => d.serialized_len_total(),
1563 Self::File(f) => f.serialized_len_total(),
1564 Self::Stream(s) => s.serialized_len_total(),
1565 Self::StreamEvent(se) => se.serialized_len_total(),
1566 }
1567 }
1568}
1569
1570impl Serialize for BiopMessage<'_> {
1571 type Error = crate::error::Error;
1572
1573 fn serialized_len(&self) -> usize {
1574 self.serialized_len_total()
1575 }
1576
1577 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
1578 let len = self.serialized_len_total();
1579 if buf.len() < len {
1580 return Err(Error::OutputBufferTooSmall {
1581 need: len,
1582 have: buf.len(),
1583 });
1584 }
1585 match self {
1586 Self::Directory(d) | Self::ServiceGateway(d) => {
1587 d.serialize_into_buf(buf)?;
1588 }
1589 Self::File(f) => {
1590 f.serialize_into_buf(buf)?;
1591 }
1592 Self::Stream(s) => {
1593 s.serialize_into_buf(buf)?;
1594 }
1595 Self::StreamEvent(se) => {
1596 se.serialize_into_buf(buf)?;
1597 }
1598 }
1599 Ok(len)
1600 }
1601}
1602
1603#[derive(Debug, Clone, PartialEq, Eq)]
1608#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1609pub struct ModuleInfo<'a> {
1610 pub module_timeout: u32,
1612 pub block_timeout: u32,
1614 pub min_block_time: u32,
1616 #[cfg_attr(feature = "serde", serde(borrow))]
1618 pub taps: Vec<super::ior::Tap<'a>>,
1619 #[cfg_attr(feature = "serde", serde(borrow))]
1621 pub user_info: &'a [u8],
1622}
1623
1624impl<'a> ModuleInfo<'a> {
1625 pub fn descriptors(&self) -> impl Iterator<Item = (u8, &[u8])> {
1629 DescriptorIter {
1630 data: self.user_info,
1631 pos: 0,
1632 }
1633 }
1634
1635 pub fn compressed_module_descriptor(&self) -> Option<CompressedModuleDescriptor<'_>> {
1638 for (tag, data) in self.descriptors() {
1639 if tag == COMPRESSED_MODULE_DESCRIPTOR_TAG {
1640 return Some(CompressedModuleDescriptor { body: data });
1641 }
1642 }
1643 None
1644 }
1645}
1646
1647struct DescriptorIter<'a> {
1648 data: &'a [u8],
1649 pos: usize,
1650}
1651
1652impl<'a> Iterator for DescriptorIter<'a> {
1653 type Item = (u8, &'a [u8]);
1654 fn next(&mut self) -> Option<Self::Item> {
1655 let end = self.data.len();
1656 if self.pos + 2 > end {
1657 return None;
1658 }
1659 let tag = self.data[self.pos];
1660 let len = self.data[self.pos + 1] as usize;
1661 self.pos += 2;
1662 if self.pos + len > end {
1663 return None;
1664 }
1665 let d = &self.data[self.pos..self.pos + len];
1666 self.pos += len;
1667 Some((tag, d))
1668 }
1669}
1670
1671impl<'a> Parse<'a> for ModuleInfo<'a> {
1672 type Error = crate::error::Error;
1673
1674 fn parse(bytes: &'a [u8]) -> Result<Self> {
1675 let end = bytes.len();
1676 let mi_fixed_len = MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD;
1677 let (mi_hdr, _) = bytes
1678 .split_first_chunk::<13>()
1679 .ok_or(Error::BufferTooShort {
1680 need: mi_fixed_len,
1681 have: end,
1682 what: "ModuleInfo fixed fields",
1683 })?;
1684 let module_timeout = u32::from_be_bytes([mi_hdr[0], mi_hdr[1], mi_hdr[2], mi_hdr[3]]);
1685 let block_timeout = u32::from_be_bytes([mi_hdr[4], mi_hdr[5], mi_hdr[6], mi_hdr[7]]);
1686 let min_block_time = u32::from_be_bytes([mi_hdr[8], mi_hdr[9], mi_hdr[10], mi_hdr[11]]);
1687 let taps_count = mi_hdr[12] as usize;
1688 let mut pos = MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD;
1689
1690 let mut taps = Vec::with_capacity(taps_count.min(8));
1691 for _ in 0..taps_count {
1692 let (tap, next) = super::ior::Tap::parse_from(bytes, pos, end)?;
1693 taps.push(tap);
1694 pos = next;
1695 }
1696
1697 if pos + MODULE_USER_INFO_LEN_FIELD > end {
1698 return Err(Error::BufferTooShort {
1699 need: pos + MODULE_USER_INFO_LEN_FIELD,
1700 have: end,
1701 what: "ModuleInfo UserInfoLength",
1702 });
1703 }
1704 let user_info_len = bytes[pos] as usize;
1705 pos += MODULE_USER_INFO_LEN_FIELD;
1706 if pos + user_info_len > end {
1707 return Err(Error::SectionLengthOverflow {
1708 declared: user_info_len,
1709 available: end - pos,
1710 });
1711 }
1712 let user_info = &bytes[pos..pos + user_info_len];
1713
1714 Ok(ModuleInfo {
1715 module_timeout,
1716 block_timeout,
1717 min_block_time,
1718 taps,
1719 user_info,
1720 })
1721 }
1722}
1723
1724impl Serialize for ModuleInfo<'_> {
1725 type Error = crate::error::Error;
1726
1727 fn serialized_len(&self) -> usize {
1728 let taps_len: usize = self.taps.iter().map(|t| t.serialized_len()).sum();
1729 MODULE_INFO_FIXED
1730 + MODULE_TAPS_COUNT_FIELD
1731 + taps_len
1732 + MODULE_USER_INFO_LEN_FIELD
1733 + self.user_info.len()
1734 }
1735
1736 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
1737 let len = self.serialized_len();
1738 if buf.len() < len {
1739 return Err(Error::OutputBufferTooSmall {
1740 need: len,
1741 have: buf.len(),
1742 });
1743 }
1744 buf[0..4].copy_from_slice(&self.module_timeout.to_be_bytes());
1745 buf[4..8].copy_from_slice(&self.block_timeout.to_be_bytes());
1746 buf[8..12].copy_from_slice(&self.min_block_time.to_be_bytes());
1747 if self.taps.len() > u8::MAX as usize {
1748 return Err(Error::SectionLengthOverflow {
1749 declared: self.taps.len(),
1750 available: u8::MAX as usize,
1751 });
1752 }
1753 buf[12] = self.taps.len() as u8;
1754 let mut pos = MODULE_INFO_FIXED + MODULE_TAPS_COUNT_FIELD;
1755 for tap in &self.taps {
1756 let written = tap.serialize_into_buf(&mut buf[pos..])?;
1757 pos += written;
1758 }
1759 if self.user_info.len() > u8::MAX as usize {
1760 return Err(Error::SectionLengthOverflow {
1761 declared: self.user_info.len(),
1762 available: u8::MAX as usize,
1763 });
1764 }
1765 buf[pos] = self.user_info.len() as u8;
1766 pos += MODULE_USER_INFO_LEN_FIELD;
1767 buf[pos..pos + self.user_info.len()].copy_from_slice(self.user_info);
1768 pos += self.user_info.len();
1769 Ok(pos)
1770 }
1771}
1772
1773#[derive(Debug, Clone, PartialEq, Eq)]
1781#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1782pub struct CompressedModuleDescriptor<'a> {
1783 #[cfg_attr(feature = "serde", serde(borrow))]
1785 pub body: &'a [u8],
1786}
1787
1788#[cfg(feature = "flate2")]
1793pub fn decompress_zlib(data: &[u8]) -> Result<Vec<u8>> {
1794 use std::io::Read;
1795 let mut decoder = flate2::read::ZlibDecoder::new(data);
1796 let mut out = Vec::new();
1797 decoder
1798 .read_to_end(&mut out)
1799 .map_err(|e| Error::ReservedBitsViolation {
1800 field: "compressed_module_descriptor body",
1801 reason: if e.kind() == std::io::ErrorKind::InvalidData {
1802 "zlib decompression failed: invalid data"
1803 } else {
1804 "zlib decompression failed"
1805 },
1806 })?;
1807 Ok(out)
1808}
1809
1810#[derive(Debug, Clone, PartialEq, Eq)]
1818#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1819pub struct ServiceGatewayInfo<'a> {
1820 pub ior: Ior<'a>,
1822 #[cfg_attr(feature = "serde", serde(borrow))]
1825 pub download_taps: &'a [u8],
1826 #[cfg_attr(feature = "serde", serde(borrow))]
1828 pub service_context: Vec<ServiceContext<'a>>,
1829 #[cfg_attr(feature = "serde", serde(borrow))]
1831 pub user_info: &'a [u8],
1832}
1833
1834impl<'a> ServiceGatewayInfo<'a> {
1835 pub fn parse(bytes: &'a [u8]) -> Result<Self> {
1837 let end = bytes.len();
1838 let ior = Ior::parse(bytes)?;
1839 let mut pos = ior.serialized_len();
1840
1841 if pos + SGI_DOWNLOAD_TAPS_COUNT_FIELD > end {
1844 return Err(Error::BufferTooShort {
1845 need: pos + SGI_DOWNLOAD_TAPS_COUNT_FIELD,
1846 have: end,
1847 what: "ServiceGatewayInfo downloadTaps_count",
1848 });
1849 }
1850 let tap_count = bytes[pos] as usize;
1851 let dl_taps_start = pos;
1852 pos += SGI_DOWNLOAD_TAPS_COUNT_FIELD;
1853 for _ in 0..tap_count {
1854 let (_, next) = super::ior::Tap::parse_from(bytes, pos, end)?;
1855 pos = next;
1856 }
1857 let download_taps = &bytes[dl_taps_start..pos];
1858
1859 let (service_context, next) = parse_service_context_list(bytes, pos, end)?;
1861 pos = next;
1862
1863 let (buil, _) = bytes[pos..end]
1865 .split_first_chunk::<2>()
1866 .ok_or(Error::BufferTooShort {
1867 need: pos + SGI_USER_INFO_LEN_FIELD,
1868 have: end,
1869 what: "ServiceGatewayInfo userInfoLength",
1870 })?;
1871 let ui_len = u16::from_be_bytes(*buil) as usize;
1872 pos += SGI_USER_INFO_LEN_FIELD;
1873 if pos + ui_len > end {
1874 return Err(Error::SectionLengthOverflow {
1875 declared: ui_len,
1876 available: end - pos,
1877 });
1878 }
1879 let user_info = &bytes[pos..pos + ui_len];
1880
1881 Ok(ServiceGatewayInfo {
1882 ior,
1883 download_taps,
1884 service_context,
1885 user_info,
1886 })
1887 }
1888
1889 pub fn to_bytes(&self) -> Vec<u8> {
1892 let len = self.ior.serialized_len()
1893 + self.download_taps.len()
1894 + service_context_list_len(&self.service_context)
1895 + SGI_USER_INFO_LEN_FIELD
1896 + self.user_info.len();
1897 let mut buf = vec![0u8; len];
1898 let mut pos = 0;
1899 let written = self
1900 .ior
1901 .serialize_into(&mut buf[pos..])
1902 .expect("IOR serialize");
1903 pos += written;
1904 buf[pos..pos + self.download_taps.len()].copy_from_slice(self.download_taps);
1905 pos += self.download_taps.len();
1906 pos += write_service_context_list(&mut buf[pos..], &self.service_context)
1907 .expect("serviceContext fits");
1908 buf[pos..pos + 2].copy_from_slice(&(self.user_info.len() as u16).to_be_bytes());
1909 pos += SGI_USER_INFO_LEN_FIELD;
1910 buf[pos..pos + self.user_info.len()].copy_from_slice(self.user_info);
1911 buf
1912 }
1913}
1914
1915#[cfg(test)]
1918mod tests {
1919 use super::*;
1920 use dvb_common::Parse;
1921
1922 fn sample_file_message(key: &'static [u8], content: &'static [u8]) -> BiopMessage<'static> {
1924 BiopMessage::File(FileMessage {
1925 object_key: key,
1926 content_size: content.len() as u64,
1927 object_info_extra: &[],
1928 service_context: vec![],
1929 content,
1930 })
1931 }
1932
1933 fn sample_dir_message() -> BiopMessage<'static> {
1935 use crate::carousel::biop::ior::{
1936 BiopProfileBody, ConnBinder, ObjectLocation, TaggedProfile,
1937 };
1938 let ior = crate::carousel::biop::ior::Ior {
1939 type_id: b"fil\0",
1940 profiles: vec![TaggedProfile::Biop(BiopProfileBody {
1941 object_location: ObjectLocation {
1942 carousel_id: 0xAB,
1943 module_id: 2,
1944 version_major: 1,
1945 version_minor: 0,
1946 object_key: &[0x02],
1947 },
1948 conn_binder: ConnBinder { taps: vec![] },
1949 extra: vec![],
1950 })],
1951 };
1952 BiopMessage::Directory(DirectoryMessage {
1953 object_kind: *b"dir\0",
1954 object_key: &[0x01],
1955 object_info: &[],
1956 service_context: vec![],
1957 bindings: vec![Binding {
1958 name: vec![NameComponent {
1959 id: b"index.html",
1960 kind: b"fil\0",
1961 }],
1962 binding_type: BindingType::NObject,
1963 ior,
1964 object_info: &[],
1965 }],
1966 })
1967 }
1968
1969 #[test]
1970 fn file_message_round_trip() {
1971 let content: &[u8] = b"Hello, BIOP!";
1972 let msg = sample_file_message(&[0x01], content);
1973 let mut buf = vec![0u8; msg.serialized_len()];
1974 msg.serialize_into(&mut buf).unwrap();
1975 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
1976 assert_eq!(consumed, buf.len());
1977 assert_eq!(parsed, msg);
1978 let mut buf2 = vec![0u8; parsed.serialized_len()];
1980 parsed.serialize_into(&mut buf2).unwrap();
1981 assert_eq!(buf, buf2);
1982 }
1983
1984 #[test]
1985 fn directory_message_round_trip() {
1986 let msg = sample_dir_message();
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()];
1993 parsed.serialize_into(&mut buf2).unwrap();
1994 assert_eq!(buf, buf2, "Directory message byte-exact re-serialize");
1995 }
1996
1997 #[test]
1998 fn module_info_round_trip() {
1999 use crate::carousel::biop::ior::Tap;
2000 let info = ModuleInfo {
2001 module_timeout: 0x00FFFFFF,
2002 block_timeout: 0x00FFFFFF,
2003 min_block_time: 0x00000064,
2004 taps: vec![Tap {
2005 id: 0,
2006 use_: 0x0017,
2007 association_tag: 0x0042,
2008 selector: &[],
2009 }],
2010 user_info: &[],
2011 };
2012 let mut buf = vec![0u8; info.serialized_len()];
2013 info.serialize_into(&mut buf).unwrap();
2014 let parsed = ModuleInfo::parse(&buf).unwrap();
2015 assert_eq!(parsed, info);
2016 let mut buf2 = vec![0u8; parsed.serialized_len()];
2017 parsed.serialize_into(&mut buf2).unwrap();
2018 assert_eq!(buf, buf2, "ModuleInfo byte-exact re-serialize");
2019 }
2020
2021 #[test]
2022 fn module_info_byte_anchor() {
2023 use crate::carousel::biop::ior::Tap;
2024 #[rustfmt::skip]
2029 let expected: &[u8] = &[
2030 0x00, 0x0F, 0x42, 0x40, 0x00, 0x0F, 0x42, 0x40, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x47, 0x00, 0x00, ];
2040 let info = ModuleInfo {
2041 module_timeout: 0x000F4240,
2042 block_timeout: 0x000F4240,
2043 min_block_time: 0x00000064,
2044 taps: vec![Tap {
2045 id: 0,
2046 use_: 0x0017,
2047 association_tag: 0x0047,
2048 selector: &[],
2049 }],
2050 user_info: &[],
2051 };
2052 let mut buf = vec![0u8; info.serialized_len()];
2053 info.serialize_into(&mut buf).unwrap();
2054 assert_eq!(buf.as_slice(), expected);
2055 let parsed = ModuleInfo::parse(expected).unwrap();
2056 assert_eq!(parsed, info);
2057 }
2058
2059 #[test]
2060 fn sgi_byte_anchor_m6() {
2061 #[rustfmt::skip]
2064 let raw: &[u8] = &[
2065 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,
2083 0x00, 0x00, 0x00, 0x00, ];
2087 assert_eq!(raw.len(), 64);
2088
2089 let sgi = ServiceGatewayInfo::parse(raw).unwrap();
2090
2091 assert_eq!(sgi.ior.type_id, b"srg\0");
2093 assert_eq!(sgi.ior.profiles.len(), 1);
2094 let bp = sgi.ior.biop_profile().unwrap();
2095 assert_eq!(bp.object_location.carousel_id, 0xAB);
2096 assert_eq!(bp.object_location.module_id, 1);
2097 assert_eq!(bp.object_location.version_major, 1);
2098 assert_eq!(bp.object_location.version_minor, 0);
2099 assert_eq!(bp.object_location.object_key, &[0x01]);
2100 assert_eq!(bp.conn_binder.taps.len(), 1);
2101 let tap = &bp.conn_binder.taps[0];
2102 assert_eq!(tap.use_, 0x0016);
2103 assert_eq!(tap.association_tag, 0x47);
2104 assert_eq!(tap.transaction_id(), Some(0x80000002));
2105 assert_eq!(tap.timeout(), Some(0xFFFFFFFF));
2106
2107 let out = sgi.to_bytes();
2109 assert_eq!(out.len(), 64, "SGI serialized length");
2110 assert_eq!(out.as_slice(), raw, "SGI byte-exact round-trip");
2111 }
2112
2113 #[cfg(feature = "serde")]
2114 #[test]
2115 fn biop_serde_round_trip() {
2116 let content: &[u8] = b"test content";
2117 let msg = sample_file_message(&[0x01], content);
2118 let json = serde_json::to_string(&msg).unwrap();
2119 assert!(json.contains("content_size"));
2120 }
2121
2122 #[cfg(feature = "flate2")]
2123 #[test]
2124 fn zlib_round_trip() {
2125 use flate2::{write::ZlibEncoder, Compression};
2126 use std::io::Write;
2127
2128 let original = b"Hello, compressed BIOP world! ".repeat(10);
2129 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
2130 encoder.write_all(&original).unwrap();
2131 let compressed = encoder.finish().unwrap();
2132
2133 let decompressed = decompress_zlib(&compressed).unwrap();
2134 assert_eq!(decompressed.as_slice(), original.as_slice());
2135 }
2136
2137 #[test]
2140 fn stream_message_round_trip() {
2141 use crate::carousel::biop::ior::Tap;
2142 let msg = BiopMessage::Stream(StreamMessage {
2143 object_key: &[0x01, 0x02],
2144 stream_info: DsmStreamInfo {
2145 description: b"audio stream",
2146 duration_seconds: -5,
2147 duration_microseconds: 500,
2148 audio: 1,
2149 video: 0,
2150 data: 0,
2151 },
2152 object_info_extra: b"\xDE\xAD",
2153 service_context: vec![],
2154 taps: vec![
2155 Tap {
2156 id: 0,
2157 use_: 0x0018,
2158 association_tag: 0x0010,
2159 selector: &[],
2160 },
2161 Tap {
2162 id: 0,
2163 use_: 0x0019,
2164 association_tag: 0x0011,
2165 selector: &[],
2166 },
2167 ],
2168 });
2169 let mut buf = vec![0u8; msg.serialized_len()];
2170 msg.serialize_into(&mut buf).unwrap();
2171 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
2172 assert_eq!(consumed, buf.len(), "consumed must equal total buf len");
2173 assert_eq!(parsed, msg);
2174 let mut buf2 = vec![0u8; parsed.serialized_len()];
2175 parsed.serialize_into(&mut buf2).unwrap();
2176 assert_eq!(buf, buf2, "StreamMessage byte-exact re-serialize");
2177 }
2178
2179 #[test]
2180 fn stream_event_message_round_trip() {
2181 use crate::carousel::biop::ior::Tap;
2182 let msg = BiopMessage::StreamEvent(StreamEventMessage {
2183 object_key: &[0x03],
2184 stream_info: DsmStreamInfo {
2185 description: b"event stream",
2186 duration_seconds: 3600,
2187 duration_microseconds: 0,
2188 audio: 0,
2189 video: 1,
2190 data: 0,
2191 },
2192 event_names: vec![b"play".as_ref(), b"pause".as_ref(), b"stop".as_ref()],
2193 object_info_extra: &[],
2194 service_context: vec![],
2195 taps: vec![Tap {
2196 id: 0,
2197 use_: 0x000C,
2198 association_tag: 0x0020,
2199 selector: &[],
2200 }],
2201 event_ids: vec![0x0001, 0x0002, 0x0003],
2202 });
2203 let mut buf = vec![0u8; msg.serialized_len()];
2204 msg.serialize_into(&mut buf).unwrap();
2205 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
2206 assert_eq!(consumed, buf.len(), "consumed must equal total buf len");
2207 assert_eq!(parsed, msg);
2208 let mut buf2 = vec![0u8; parsed.serialized_len()];
2209 parsed.serialize_into(&mut buf2).unwrap();
2210 assert_eq!(buf, buf2, "StreamEventMessage byte-exact re-serialize");
2211 }
2212
2213 #[test]
2214 fn stream_message_byte_anchor() {
2215 use crate::carousel::biop::ior::Tap;
2248 #[rustfmt::skip]
2249 let expected: &[u8] = &[
2250 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,
2274 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x47, 0x00, ];
2283 assert_eq!(expected.len(), 50);
2284 let expected_msg = BiopMessage::Stream(StreamMessage {
2285 object_key: &[0xAB],
2286 stream_info: DsmStreamInfo {
2287 description: b"vid",
2288 duration_seconds: 0,
2289 duration_microseconds: 0,
2290 audio: 1,
2291 video: 1,
2292 data: 0,
2293 },
2294 object_info_extra: &[],
2295 service_context: vec![],
2296 taps: vec![Tap {
2297 id: 0,
2298 use_: 0x0018,
2299 association_tag: 0x0047,
2300 selector: &[],
2301 }],
2302 });
2303
2304 let mut buf = vec![0u8; expected_msg.serialized_len()];
2306 expected_msg.serialize_into(&mut buf).unwrap();
2307 assert_eq!(
2308 buf.as_slice(),
2309 expected,
2310 "StreamMessage serialize must match byte anchor"
2311 );
2312
2313 let (parsed, consumed) = BiopMessage::parse_at(expected).unwrap();
2315 assert_eq!(consumed, expected.len());
2316 assert_eq!(
2317 parsed, expected_msg,
2318 "StreamMessage parse must match byte anchor struct"
2319 );
2320 }
2321
2322 #[test]
2323 fn stream_event_message_byte_anchor() {
2324 #[rustfmt::skip]
2361 let expected: &[u8] = &[
2362 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,
2392 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, ];
2400 assert_eq!(expected.len(), 55);
2401
2402 let expected_msg = BiopMessage::StreamEvent(StreamEventMessage {
2403 object_key: &[0xCD],
2404 stream_info: DsmStreamInfo {
2405 description: &[],
2406 duration_seconds: 0,
2407 duration_microseconds: 0,
2408 audio: 0,
2409 video: 0,
2410 data: 0,
2411 },
2412 event_names: vec![b"foo".as_ref(), b"bar".as_ref()],
2413 object_info_extra: &[],
2414 service_context: vec![],
2415 taps: vec![],
2416 event_ids: vec![1, 2],
2417 });
2418
2419 let mut buf = vec![0u8; expected_msg.serialized_len()];
2421 expected_msg.serialize_into(&mut buf).unwrap();
2422 assert_eq!(
2423 buf.as_slice(),
2424 expected,
2425 "StreamEventMessage serialize must match byte anchor"
2426 );
2427
2428 let (parsed, consumed) = BiopMessage::parse_at(expected).unwrap();
2430 assert_eq!(consumed, expected.len());
2431 assert_eq!(
2432 parsed, expected_msg,
2433 "StreamEventMessage parse must match byte anchor struct"
2434 );
2435 }
2436
2437 #[test]
2438 fn service_context_typed_round_trip() {
2439 let msg = BiopMessage::File(FileMessage {
2441 object_key: &[0x01],
2442 content_size: 3,
2443 object_info_extra: &[],
2444 service_context: vec![
2445 ServiceContext {
2446 context_id: 0xDEADBEEF,
2447 data: &[1, 2, 3],
2448 },
2449 ServiceContext {
2450 context_id: 0x11223344,
2451 data: &[],
2452 },
2453 ],
2454 content: b"abc",
2455 });
2456
2457 let mut buf = vec![0u8; msg.serialized_len()];
2459 msg.serialize_into(&mut buf).unwrap();
2460
2461 let (parsed, consumed) = BiopMessage::parse_at(&buf).unwrap();
2463 assert_eq!(consumed, buf.len(), "consumed must equal total buf len");
2464 assert_eq!(parsed, msg, "parsed must equal original");
2465
2466 let mut buf2 = vec![0u8; parsed.serialized_len()];
2468 parsed.serialize_into(&mut buf2).unwrap();
2469 assert_eq!(
2470 buf, buf2,
2471 "serviceContext typed round-trip must be byte-exact"
2472 );
2473
2474 assert_eq!(buf[32], 2, "serviceContextList_count must be 2");
2478 assert_eq!(&buf[33..37], &[0xDE, 0xAD, 0xBE, 0xEF]);
2480 assert_eq!(&buf[37..39], &[0x00, 0x03]);
2482 assert_eq!(&buf[39..42], &[0x01, 0x02, 0x03]);
2484 assert_eq!(&buf[42..46], &[0x11, 0x22, 0x33, 0x44]);
2486 assert_eq!(&buf[46..48], &[0x00, 0x00]);
2488 }
2489
2490 #[test]
2491 fn binding_type_full_range_round_trip() {
2492 for v in 0u8..=0xFF {
2493 let bt = BindingType::from_u8(v);
2494 assert_eq!(bt.to_u8(), v, "BindingType round-trip failed for 0x{v:02X}");
2495 }
2496 }
2497
2498 #[test]
2499 fn binding_type_known_values() {
2500 assert_eq!(BindingType::from_u8(0x01), BindingType::NObject);
2501 assert_eq!(BindingType::from_u8(0x02), BindingType::NContext);
2502 assert_eq!(BindingType::NObject.name(), "nobject");
2503 assert_eq!(BindingType::NContext.name(), "ncontext");
2504 assert_eq!(BindingType::Reserved(0x05).name(), "reserved");
2505 }
2506
2507 #[test]
2508 fn directory_message_binding_type_round_trip() {
2509 let msg = sample_dir_message();
2510 let mut buf = vec![0u8; msg.serialized_len()];
2511 msg.serialize_into(&mut buf).unwrap();
2512 let (parsed, _) = BiopMessage::parse_at(&buf).unwrap();
2513 match parsed {
2514 BiopMessage::Directory(d) => {
2515 assert_eq!(d.bindings[0].binding_type, BindingType::NObject);
2516 }
2517 other => panic!("expected Directory, got {other:?}"),
2518 }
2519 }
2520}