1extern crate alloc;
14
15use alloc::vec::Vec;
16
17use broadcast_common::{Parse, Serialize};
18
19use crate::ber::{ber_length_size, decode_ber_length, encode_ber_length};
20use crate::error::{Error, Result};
21use crate::types::{UlBytes, ul_bytes_from_prefix};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27#[non_exhaustive]
28pub enum ItemLengthMode {
29 TwoByte,
32 Ber,
35}
36
37impl ItemLengthMode {
38 #[must_use]
40 pub fn name(&self) -> &'static str {
41 match self {
42 Self::TwoByte => "2-byte length",
43 Self::Ber => "BER length",
44 }
45 }
46
47 #[must_use]
49 pub fn registry_designator_byte(self) -> u8 {
50 match self {
51 Self::TwoByte => 0x53,
52 Self::Ber => 0x13,
53 }
54 }
55
56 #[must_use]
59 pub fn from_registry_designator_byte(b: u8) -> Option<Self> {
60 match b {
61 0x53 => Some(Self::TwoByte),
62 0x13 => Some(Self::Ber),
63 _ => None,
64 }
65 }
66}
67
68broadcast_common::impl_spec_display!(ItemLengthMode);
69
70const SET_KEY_FIXED: [(usize, u8); 8] = [
75 (0, 0x06),
76 (1, 0x0E),
77 (2, 0x2B),
78 (3, 0x34),
79 (4, 0x02),
80 (6, 0x01),
81 (9, 0x01),
82 (11, 0x01),
83];
84const SET_KEY_BYTE10: u8 = 0x01;
89const SET_KEY_BYTE12: u8 = 0x01;
90
91#[must_use]
96pub fn is_local_set_key(key: &UlBytes) -> bool {
97 SET_KEY_FIXED.iter().all(|&(i, v)| key[i] == v)
98 && ItemLengthMode::from_registry_designator_byte(key[5]).is_some()
99 && key[8] == 0x0D
100 && key[9] == SET_KEY_BYTE10
101 && key[10] == 0x01
102 && key[12] == SET_KEY_BYTE12
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
109#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
110#[non_exhaustive]
111pub enum StructuralSetKind {
112 Preface,
114 Identification,
116 ContentStorage,
118 EssenceContainerData,
120 MaterialPackage,
122 SourcePackage,
124 TimelineTrack,
127 EventTrackDm,
129 StaticTrackDm,
131 Sequence,
133 SourceClip,
136 TimecodeComponent,
138 DmSegment,
140 DmSourceClip,
142 Filler,
144 PackageMarkerObject,
146 FileDescriptor,
148 GenericPictureEssenceDescriptor,
150 CdciEssenceDescriptor,
152 RgbaEssenceDescriptor,
154 GenericSoundEssenceDescriptor,
156 GenericDataEssenceDescriptor,
158 MultipleDescriptor,
160 NetworkLocator,
162 TextLocator,
164 ApplicationPlugInObject,
166 ApplicationReferencedObject,
168 Unknown([u8; 2]),
172}
173
174impl StructuralSetKind {
175 #[must_use]
178 pub fn name(&self) -> &'static str {
179 match self {
180 Self::Preface => "Preface",
181 Self::Identification => "Identification",
182 Self::ContentStorage => "Content Storage",
183 Self::EssenceContainerData => "Essence Container Data",
184 Self::MaterialPackage => "Material Package",
185 Self::SourcePackage => "Source Package",
186 Self::TimelineTrack => "Timeline Track",
187 Self::EventTrackDm => "Event Track (DM)",
188 Self::StaticTrackDm => "Static Track (DM)",
189 Self::Sequence => "Sequence",
190 Self::SourceClip => "Source Clip",
191 Self::TimecodeComponent => "Timecode Component",
192 Self::DmSegment => "DM Segment",
193 Self::DmSourceClip => "DM Source Clip",
194 Self::Filler => "Filler",
195 Self::PackageMarkerObject => "Package Marker Object",
196 Self::FileDescriptor => "File Descriptor",
197 Self::GenericPictureEssenceDescriptor => "Generic Picture Essence Descriptor",
198 Self::CdciEssenceDescriptor => "CDCI Essence Descriptor",
199 Self::RgbaEssenceDescriptor => "RGBA Essence Descriptor",
200 Self::GenericSoundEssenceDescriptor => "Generic Sound Essence Descriptor",
201 Self::GenericDataEssenceDescriptor => "Generic Data Essence Descriptor",
202 Self::MultipleDescriptor => "Multiple Descriptor",
203 Self::NetworkLocator => "Network Locator",
204 Self::TextLocator => "Text Locator",
205 Self::ApplicationPlugInObject => "Application Plug-In Object",
206 Self::ApplicationReferencedObject => "Application Referenced Object",
207 Self::Unknown(_) => "unknown",
208 }
209 }
210
211 #[must_use]
213 pub fn from_bytes(b14: u8, b15: u8) -> Self {
214 match (b14, b15) {
215 (0x01, 0x2F) => Self::Preface,
216 (0x01, 0x30) => Self::Identification,
217 (0x01, 0x18) => Self::ContentStorage,
218 (0x01, 0x23) => Self::EssenceContainerData,
219 (0x01, 0x36) => Self::MaterialPackage,
220 (0x01, 0x37) => Self::SourcePackage,
221 (0x01, 0x3B) => Self::TimelineTrack,
222 (0x01, 0x39) => Self::EventTrackDm,
223 (0x01, 0x3A) => Self::StaticTrackDm,
224 (0x01, 0x0F) => Self::Sequence,
225 (0x01, 0x11) => Self::SourceClip,
226 (0x01, 0x14) => Self::TimecodeComponent,
227 (0x01, 0x41) => Self::DmSegment,
228 (0x01, 0x45) => Self::DmSourceClip,
229 (0x01, 0x09) => Self::Filler,
230 (0x01, 0x60) => Self::PackageMarkerObject,
231 (0x01, 0x25) => Self::FileDescriptor,
232 (0x01, 0x27) => Self::GenericPictureEssenceDescriptor,
233 (0x01, 0x28) => Self::CdciEssenceDescriptor,
234 (0x01, 0x29) => Self::RgbaEssenceDescriptor,
235 (0x01, 0x42) => Self::GenericSoundEssenceDescriptor,
236 (0x01, 0x43) => Self::GenericDataEssenceDescriptor,
237 (0x01, 0x44) => Self::MultipleDescriptor,
238 (0x01, 0x32) => Self::NetworkLocator,
239 (0x01, 0x33) => Self::TextLocator,
240 (0x01, 0x61) => Self::ApplicationPlugInObject,
241 (0x01, 0x62) => Self::ApplicationReferencedObject,
242 other => Self::Unknown([other.0, other.1]),
243 }
244 }
245
246 #[must_use]
248 pub fn to_bytes(self) -> [u8; 2] {
249 match self {
250 Self::Preface => [0x01, 0x2F],
251 Self::Identification => [0x01, 0x30],
252 Self::ContentStorage => [0x01, 0x18],
253 Self::EssenceContainerData => [0x01, 0x23],
254 Self::MaterialPackage => [0x01, 0x36],
255 Self::SourcePackage => [0x01, 0x37],
256 Self::TimelineTrack => [0x01, 0x3B],
257 Self::EventTrackDm => [0x01, 0x39],
258 Self::StaticTrackDm => [0x01, 0x3A],
259 Self::Sequence => [0x01, 0x0F],
260 Self::SourceClip => [0x01, 0x11],
261 Self::TimecodeComponent => [0x01, 0x14],
262 Self::DmSegment => [0x01, 0x41],
263 Self::DmSourceClip => [0x01, 0x45],
264 Self::Filler => [0x01, 0x09],
265 Self::PackageMarkerObject => [0x01, 0x60],
266 Self::FileDescriptor => [0x01, 0x25],
267 Self::GenericPictureEssenceDescriptor => [0x01, 0x27],
268 Self::CdciEssenceDescriptor => [0x01, 0x28],
269 Self::RgbaEssenceDescriptor => [0x01, 0x29],
270 Self::GenericSoundEssenceDescriptor => [0x01, 0x42],
271 Self::GenericDataEssenceDescriptor => [0x01, 0x43],
272 Self::MultipleDescriptor => [0x01, 0x44],
273 Self::NetworkLocator => [0x01, 0x32],
274 Self::TextLocator => [0x01, 0x33],
275 Self::ApplicationPlugInObject => [0x01, 0x61],
276 Self::ApplicationReferencedObject => [0x01, 0x62],
277 Self::Unknown([a, b]) => [a, b],
278 }
279 }
280}
281
282impl core::fmt::Display for StructuralSetKind {
283 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
284 match self {
285 Self::Unknown([a, b]) => write!(f, "unknown(0x{a:02X}{b:02X})"),
286 other => f.write_str(other.name()),
287 }
288 }
289}
290
291#[derive(Debug, Clone, Copy, PartialEq, Eq)]
293pub struct LocalSetItem<'a> {
294 pub tag: u16,
296 pub value: &'a [u8],
298}
299
300#[derive(Debug, Clone, PartialEq, Eq)]
305pub struct LocalSet<'a> {
306 pub key: UlBytes,
308 pub items: Vec<LocalSetItem<'a>>,
310}
311
312impl<'a> LocalSet<'a> {
313 #[must_use]
315 pub fn kind(&self) -> StructuralSetKind {
316 StructuralSetKind::from_bytes(self.key[13], self.key[14])
317 }
318
319 #[must_use]
327 pub fn item_length_mode(&self) -> ItemLengthMode {
328 ItemLengthMode::from_registry_designator_byte(self.key[5])
329 .unwrap_or(ItemLengthMode::TwoByte)
330 }
331
332 #[must_use]
334 pub fn get(&self, tag: u16) -> Option<&'a [u8]> {
335 self.items.iter().find(|i| i.tag == tag).map(|i| i.value)
336 }
337
338 #[must_use]
341 pub fn build_key(kind: StructuralSetKind, mode: ItemLengthMode) -> UlBytes {
342 let [b14, b15] = kind.to_bytes();
343 [
344 0x06,
345 0x0E,
346 0x2B,
347 0x34,
348 0x02,
349 mode.registry_designator_byte(),
350 0x01,
351 0x01, 0x0D,
353 0x01,
354 0x01,
355 0x01,
356 0x01,
357 b14,
358 b15,
359 0x00,
360 ]
361 }
362
363 pub fn parse_prefix(bytes: &'a [u8]) -> Result<(Self, usize)> {
367 if bytes.len() < 16 {
368 return Err(Error::BufferTooShort {
369 need: 16,
370 have: bytes.len(),
371 what: "Local Set key",
372 });
373 }
374 let key: UlBytes = ul_bytes_from_prefix(bytes);
375 if !is_local_set_key(&key) {
376 return Err(Error::KeyPrefixMismatch {
377 what: "Local Set (Table 16)",
378 });
379 }
380 let mode = ItemLengthMode::from_registry_designator_byte(key[5])
384 .unwrap_or(ItemLengthMode::TwoByte);
385
386 let (len, len_size) = decode_ber_length(&bytes[16..])?;
387 let value_start = 16 + len_size;
388 let len = usize::try_from(len).map_err(|_| Error::BufferTooShort {
389 need: usize::MAX,
390 have: bytes.len(),
391 what: "Local Set value (length exceeds platform usize)",
392 })?;
393 let value_end = value_start.checked_add(len).ok_or(Error::BufferTooShort {
394 need: usize::MAX,
395 have: bytes.len(),
396 what: "Local Set value (length overflow)",
397 })?;
398 if bytes.len() < value_end {
399 return Err(Error::BufferTooShort {
400 need: value_end,
401 have: bytes.len(),
402 what: "Local Set value",
403 });
404 }
405
406 let mut cursor = &bytes[value_start..value_end];
407 let mut items = Vec::new();
408 while !cursor.is_empty() {
409 if cursor.len() < 2 {
410 return Err(Error::BufferTooShort {
411 need: 2,
412 have: cursor.len(),
413 what: "Local Set item tag",
414 });
415 }
416 let tag = u16::from_be_bytes([cursor[0], cursor[1]]);
417 let rest = &cursor[2..];
418 let (item_len, item_len_size) = match mode {
419 ItemLengthMode::TwoByte => {
420 if rest.len() < 2 {
421 return Err(Error::BufferTooShort {
422 need: 2,
423 have: rest.len(),
424 what: "Local Set item 2-byte length",
425 });
426 }
427 (u64::from(u16::from_be_bytes([rest[0], rest[1]])), 2)
428 }
429 ItemLengthMode::Ber => decode_ber_length(rest)?,
430 };
431 let item_len = item_len as usize;
432 let value_start = item_len_size;
433 let value_end = value_start
434 .checked_add(item_len)
435 .ok_or(Error::BufferTooShort {
436 need: usize::MAX,
437 have: rest.len(),
438 what: "Local Set item value (length overflow)",
439 })?;
440 if rest.len() < value_end {
441 return Err(Error::BufferTooShort {
442 need: value_end,
443 have: rest.len(),
444 what: "Local Set item value",
445 });
446 }
447 items.push(LocalSetItem {
448 tag,
449 value: &rest[value_start..value_end],
450 });
451 cursor = &rest[value_end..];
452 }
453
454 Ok((LocalSet { key, items }, value_end))
455 }
456}
457
458impl<'a> Parse<'a> for LocalSet<'a> {
459 type Error = Error;
460
461 fn parse(bytes: &'a [u8]) -> Result<Self> {
462 let (set, consumed) = Self::parse_prefix(bytes)?;
463 if consumed != bytes.len() {
464 return Err(Error::BufferTooShort {
465 need: consumed,
466 have: bytes.len(),
467 what: "Local Set (trailing bytes after exact-fit parse)",
468 });
469 }
470 Ok(set)
471 }
472}
473
474impl Serialize for LocalSet<'_> {
475 type Error = Error;
476
477 fn serialized_len(&self) -> usize {
478 let mode = self.item_length_mode();
479 let items_len: usize = self
480 .items
481 .iter()
482 .map(|i| {
483 2 + match mode {
484 ItemLengthMode::TwoByte => 2,
485 ItemLengthMode::Ber => ber_length_size(i.value.len() as u64),
486 } + i.value.len()
487 })
488 .sum();
489 16 + ber_length_size(items_len as u64) + items_len
490 }
491
492 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
493 let total = self.serialized_len();
494 if buf.len() < total {
495 return Err(Error::BufferTooShort {
496 need: total,
497 have: buf.len(),
498 what: "Local Set",
499 });
500 }
501 buf[..16].copy_from_slice(&self.key);
502 let mode = self.item_length_mode();
503 let items_len: usize = self
504 .items
505 .iter()
506 .map(|i| {
507 2 + match mode {
508 ItemLengthMode::TwoByte => 2,
509 ItemLengthMode::Ber => ber_length_size(i.value.len() as u64),
510 } + i.value.len()
511 })
512 .sum();
513 let len_size = encode_ber_length(items_len as u64, &mut buf[16..])?;
514 let mut pos = 16 + len_size;
515 for item in &self.items {
516 buf[pos..pos + 2].copy_from_slice(&item.tag.to_be_bytes());
517 pos += 2;
518 match mode {
519 ItemLengthMode::TwoByte => {
520 let len = u16::try_from(item.value.len()).map_err(|_| {
521 Error::InvalidPropertyLength {
522 tag: item.tag,
523 name: "Local Set item",
524 found: item.value.len(),
525 expected: usize::from(u16::MAX),
526 }
527 })?;
528 buf[pos..pos + 2].copy_from_slice(&len.to_be_bytes());
529 pos += 2;
530 }
531 ItemLengthMode::Ber => {
532 pos += encode_ber_length(item.value.len() as u64, &mut buf[pos..])?;
533 }
534 }
535 buf[pos..pos + item.value.len()].copy_from_slice(item.value);
536 pos += item.value.len();
537 }
538 Ok(pos)
539 }
540}
541
542#[cfg(test)]
543mod tests {
544 use super::*;
545
546 #[test]
547 fn structural_set_kind_round_trips_every_named_variant() {
548 let variants = [
549 StructuralSetKind::Preface,
550 StructuralSetKind::Identification,
551 StructuralSetKind::ContentStorage,
552 StructuralSetKind::EssenceContainerData,
553 StructuralSetKind::MaterialPackage,
554 StructuralSetKind::SourcePackage,
555 StructuralSetKind::TimelineTrack,
556 StructuralSetKind::EventTrackDm,
557 StructuralSetKind::StaticTrackDm,
558 StructuralSetKind::Sequence,
559 StructuralSetKind::SourceClip,
560 StructuralSetKind::TimecodeComponent,
561 StructuralSetKind::DmSegment,
562 StructuralSetKind::DmSourceClip,
563 StructuralSetKind::Filler,
564 StructuralSetKind::PackageMarkerObject,
565 StructuralSetKind::FileDescriptor,
566 StructuralSetKind::GenericPictureEssenceDescriptor,
567 StructuralSetKind::CdciEssenceDescriptor,
568 StructuralSetKind::RgbaEssenceDescriptor,
569 StructuralSetKind::GenericSoundEssenceDescriptor,
570 StructuralSetKind::GenericDataEssenceDescriptor,
571 StructuralSetKind::MultipleDescriptor,
572 StructuralSetKind::NetworkLocator,
573 StructuralSetKind::TextLocator,
574 StructuralSetKind::ApplicationPlugInObject,
575 StructuralSetKind::ApplicationReferencedObject,
576 ];
577 for v in variants {
578 let bytes = v.to_bytes();
579 assert_eq!(StructuralSetKind::from_bytes(bytes[0], bytes[1]), v);
580 }
581 assert_eq!(
582 StructuralSetKind::from_bytes(0xFE, 0xFD),
583 StructuralSetKind::Unknown([0xFE, 0xFD])
584 );
585 }
586
587 #[test]
588 fn local_set_round_trip_two_byte_mode() {
589 let key = LocalSet::build_key(StructuralSetKind::Preface, ItemLengthMode::TwoByte);
590 let set = LocalSet {
591 key,
592 items: alloc::vec![
593 LocalSetItem {
594 tag: 0x3B02,
595 value: &[1, 2, 3, 4, 5, 6, 7, 8],
596 },
597 LocalSetItem {
598 tag: 0x3B05,
599 value: &[0x01, 0x03],
600 },
601 ],
602 };
603 let mut buf = alloc::vec![0u8; set.serialized_len()];
604 set.serialize_into(&mut buf).unwrap();
605 let parsed = LocalSet::parse(&buf).unwrap();
606 assert_eq!(parsed, set);
607 assert_eq!(parsed.kind(), StructuralSetKind::Preface);
608 assert_eq!(parsed.get(0x3B02), Some(&[1, 2, 3, 4, 5, 6, 7, 8][..]));
609 }
610
611 #[test]
612 fn local_set_round_trip_ber_mode() {
613 let key = LocalSet::build_key(StructuralSetKind::Identification, ItemLengthMode::Ber);
614 let big_value = alloc::vec![0x42u8; 70000];
615 let set = LocalSet {
616 key,
617 items: alloc::vec![LocalSetItem {
618 tag: 0x3C01,
619 value: &big_value,
620 }],
621 };
622 let mut buf = alloc::vec![0u8; set.serialized_len()];
623 set.serialize_into(&mut buf).unwrap();
624 let parsed = LocalSet::parse(&buf).unwrap();
625 assert_eq!(parsed, set);
626 assert_eq!(parsed.item_length_mode(), ItemLengthMode::Ber);
627 }
628
629 #[test]
630 fn non_local_set_key_rejected() {
631 let bytes = [0u8; 20];
632 assert!(matches!(
633 LocalSet::parse_prefix(&bytes),
634 Err(Error::KeyPrefixMismatch { .. })
635 ));
636 }
637}