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