1use std::fmt::Debug;
2use std::io;
3
4use scuffle_bytes_util::zero_copy::{Deserialize, DeserializeSeed, Serialize, U24Be};
5use scuffle_bytes_util::{BitWriter, BytesCow, IoResultExt};
6
7use super::{
8 Brand, DataInformationBox, ExtendedTypeBox, FDItemInformationBox, GroupsListBox, HandlerBox, ProtectionSchemeInfoBox,
9 ScrambleSchemeInfoBox,
10};
11use crate::{BoxHeader, FullBoxHeader, IsoBox, IsoSized, UnknownBox, Utf8String};
12
13#[derive(IsoBox, Debug, PartialEq, Eq)]
17#[iso_box(box_type = b"meta", crate_path = crate)]
18pub struct MetaBox<'a> {
19 pub full_header: FullBoxHeader,
21 #[iso_box(nested_box)]
23 pub hdlr: HandlerBox,
24 #[iso_box(nested_box(collect))]
26 pub dinf: Option<DataInformationBox<'a>>,
27 #[iso_box(nested_box(collect))]
29 pub iloc: Option<ItemLocationBox>,
30 #[iso_box(nested_box(collect))]
32 pub ipro: Option<ItemProtectionBox<'a>>,
33 #[iso_box(nested_box(collect))]
35 pub iinf: Option<ItemInfoBox<'a>>,
36 #[iso_box(nested_box(collect))]
38 pub xml: Option<XmlBox>,
39 #[iso_box(nested_box(collect))]
41 pub bxml: Option<BinaryXmlBox<'a>>,
42 #[iso_box(nested_box(collect))]
44 pub pitm: Option<PrimaryItemBox>,
45 #[iso_box(nested_box(collect))]
47 pub fiin: Option<FDItemInformationBox>,
48 #[iso_box(nested_box(collect))]
50 pub idat: Option<ItemDataBox<'a>>,
51 #[iso_box(nested_box(collect))]
53 pub iref: Option<ItemReferenceBox>,
54 #[iso_box(nested_box(collect))]
56 pub iprp: Option<ItemPropertiesBox<'a>>,
57 #[iso_box(nested_box(collect))]
59 pub grpl: Option<GroupsListBox<'a>>,
60 #[iso_box(nested_box(collect_unknown))]
62 pub unknown_boxes: Vec<UnknownBox<'a>>,
63}
64
65#[derive(IsoBox, Debug, PartialEq, Eq)]
69#[iso_box(box_type = b"xml ", crate_path = crate)]
70pub struct XmlBox {
71 pub full_header: FullBoxHeader,
73 pub xml: Utf8String,
75}
76
77#[derive(IsoBox, Debug, PartialEq, Eq)]
81#[iso_box(box_type = b"bxml", crate_path = crate)]
82pub struct BinaryXmlBox<'a> {
83 pub full_header: FullBoxHeader,
85 pub data: BytesCow<'a>,
87}
88
89#[derive(IsoBox, Debug, PartialEq, Eq)]
93#[iso_box(box_type = b"iloc", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
94pub struct ItemLocationBox {
95 pub full_header: FullBoxHeader,
97 pub offset_size: u8,
99 pub length_size: u8,
101 pub base_offset_size: u8,
103 pub index_size: u8,
107 pub item_count: Option<u32>,
109 pub items: Vec<ItemLocationBoxItem>,
111}
112
113impl<'a> DeserializeSeed<'a, BoxHeader> for ItemLocationBox {
114 fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
115 where
116 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
117 {
118 let full_header = FullBoxHeader::deserialize(&mut reader)?;
119
120 let byte = u8::deserialize(&mut reader)?;
121 let offset_size = byte >> 4;
122
123 if ![0, 4, 8].contains(&offset_size) {
124 return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid offset_size"));
125 }
126
127 let length_size = byte & 0x0F;
128
129 if ![0, 4, 8].contains(&length_size) {
130 return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid length_size"));
131 }
132
133 let byte = u8::deserialize(&mut reader)?;
134 let base_offset_size = byte >> 4;
135
136 if ![0, 4, 8].contains(&base_offset_size) {
137 return Err(std::io::Error::new(
138 std::io::ErrorKind::InvalidData,
139 "Invalid base_offset_size",
140 ));
141 }
142
143 let index_size = byte & 0x0F;
144 if (full_header.version == 1 || full_header.version == 2) && ![0, 4, 8].contains(&index_size) {
145 return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid index_size"));
146 }
147
148 let item_count = if full_header.version < 2 {
149 Some(u16::deserialize(&mut reader)? as u32)
150 } else if full_header.version == 2 {
151 Some(u32::deserialize(&mut reader)?)
152 } else {
153 None
154 };
155
156 let mut items = Vec::with_capacity(item_count.unwrap_or(0) as usize);
157 for _ in 0..item_count.unwrap_or(0) {
158 let item_id = if full_header.version < 2 {
159 Some(u16::deserialize(&mut reader)? as u32)
160 } else if full_header.version == 2 {
161 Some(u32::deserialize(&mut reader)?)
162 } else {
163 None
164 };
165
166 let construction_method = if full_header.version == 1 || full_header.version == 2 {
167 let value = u16::deserialize(&mut reader)?;
168 Some((value & 0b1111) as u8)
169 } else {
170 None
171 };
172
173 let data_reference_index = u16::deserialize(&mut reader)?;
174 let base_offset = reader.try_read(base_offset_size as usize)?.pad_to_u64_be();
175 let extent_count = u16::deserialize(&mut reader)?;
176 let mut extents = Vec::with_capacity(extent_count as usize);
177 for _ in 0..extent_count {
178 let item_reference_index = if (full_header.version == 1 || full_header.version == 2) && index_size > 0 {
179 Some(reader.try_read(index_size as usize)?.pad_to_u64_be())
180 } else {
181 None
182 };
183 let extent_offset = reader.try_read(offset_size as usize)?.pad_to_u64_be();
184 let extent_length = reader.try_read(length_size as usize)?.pad_to_u64_be();
185
186 extents.push(ItemLocationBoxExtent {
187 item_reference_index,
188 extent_offset,
189 extent_length,
190 });
191 }
192
193 items.push(ItemLocationBoxItem {
194 item_id,
195 construction_method,
196 data_reference_index,
197 base_offset,
198 extent_count,
199 extents,
200 });
201 }
202
203 Ok(ItemLocationBox {
204 full_header,
205 offset_size,
206 length_size,
207 base_offset_size,
208 index_size,
209 item_count,
210 items,
211 })
212 }
213}
214
215impl Serialize for ItemLocationBox {
216 fn serialize<W>(&self, writer: W) -> std::io::Result<()>
217 where
218 W: std::io::Write,
219 {
220 let mut bit_writer = BitWriter::new(writer);
221
222 self.serialize_box_header(&mut bit_writer)?;
223 self.full_header.serialize(&mut bit_writer)?;
224 bit_writer.write_bits(self.offset_size as u64, 4)?;
225 bit_writer.write_bits(self.length_size as u64, 4)?;
226 bit_writer.write_bits(self.base_offset_size as u64, 4)?;
227 bit_writer.write_bits(self.index_size as u64, 4)?;
228
229 if self.full_header.version < 2 {
230 (self
231 .item_count
232 .ok_or(io::Error::new(io::ErrorKind::InvalidData, "item_count is required"))? as u16)
233 .serialize(&mut bit_writer)?;
234 } else if self.full_header.version == 2 {
235 self.item_count
236 .ok_or(io::Error::new(io::ErrorKind::InvalidData, "item_count is required"))?
237 .serialize(&mut bit_writer)?;
238 }
239
240 for item in &self.items {
241 item.serialize(&mut bit_writer, self)?;
242 }
243
244 Ok(())
245 }
246}
247
248impl IsoSized for ItemLocationBox {
249 fn size(&self) -> usize {
250 let mut size = 0;
251
252 size += self.full_header.size();
253 size += 1; size += 1; if self.full_header.version < 2 {
257 size += 2; } else if self.full_header.version == 2 {
259 size += 4; }
261
262 size += self.items.iter().map(|item| item.size(self)).sum::<usize>();
263
264 Self::add_header_size(size)
265 }
266}
267
268#[derive(Debug, PartialEq, Eq)]
270pub struct ItemLocationBoxItem {
271 pub item_id: Option<u32>,
273 pub construction_method: Option<u8>,
275 pub data_reference_index: u16,
278 pub base_offset: u64,
281 pub extent_count: u16,
284 pub extents: Vec<ItemLocationBoxExtent>,
286}
287
288impl ItemLocationBoxItem {
289 fn serialize<W>(&self, writer: W, parent: &ItemLocationBox) -> io::Result<()>
290 where
291 W: std::io::Write,
292 {
293 let mut bit_writer = BitWriter::new(writer);
294
295 if parent.full_header.version < 2 {
296 (self
297 .item_id
298 .ok_or(io::Error::new(io::ErrorKind::InvalidData, "item_id is required"))? as u16)
299 .serialize(&mut bit_writer)?;
300 } else if parent.full_header.version == 2 {
301 self.item_id
302 .ok_or(io::Error::new(io::ErrorKind::InvalidData, "item_id is required"))?
303 .serialize(&mut bit_writer)?;
304 }
305
306 if parent.full_header.version == 1 || parent.full_header.version == 2 {
307 bit_writer.write_bits(0, 12)?;
308 bit_writer.write_bits(
309 self.construction_method
310 .ok_or(io::Error::new(io::ErrorKind::InvalidData, "construction_method is required"))?
311 as u64,
312 4,
313 )?;
314 }
315
316 self.data_reference_index.serialize(&mut bit_writer)?;
317 bit_writer.write_bits(self.base_offset, parent.base_offset_size * 8)?;
318 self.extent_count.serialize(&mut bit_writer)?;
319
320 for extent in &self.extents {
321 extent.serialize(&mut bit_writer, parent)?;
322 }
323
324 Ok(())
325 }
326}
327
328impl ItemLocationBoxItem {
329 pub fn size(&self, parent: &ItemLocationBox) -> usize {
331 let mut size = 0;
332
333 if parent.full_header.version < 2 {
334 size += 2; } else if parent.full_header.version == 2 {
336 size += 4; }
338 if parent.full_header.version == 1 || parent.full_header.version == 2 {
339 size += 2; }
341 size += 2; size += parent.base_offset_size as usize; size += 2; size += self.extents.iter().map(|e| e.size(parent)).sum::<usize>();
345
346 size
347 }
348}
349
350#[derive(Debug, PartialEq, Eq)]
352pub struct ItemLocationBoxExtent {
353 pub item_reference_index: Option<u64>,
355 pub extent_offset: u64,
358 pub extent_length: u64,
362}
363
364impl ItemLocationBoxExtent {
365 fn serialize<W>(&self, writer: W, parent: &ItemLocationBox) -> io::Result<()>
366 where
367 W: std::io::Write,
368 {
369 let mut bit_writer = BitWriter::new(writer);
370
371 if (parent.full_header.version == 1 || parent.full_header.version == 2) && parent.index_size > 0 {
372 bit_writer.write_bits(
373 self.item_reference_index
374 .ok_or(io::Error::new(io::ErrorKind::InvalidData, "item_reference_index is required"))?,
375 parent.index_size * 8,
376 )?;
377 }
378 bit_writer.write_bits(self.extent_offset, parent.offset_size * 8)?;
379 bit_writer.write_bits(self.extent_length, parent.length_size * 8)?;
380
381 Ok(())
382 }
383}
384
385impl ItemLocationBoxExtent {
386 pub fn size(&self, parent: &ItemLocationBox) -> usize {
388 let mut size = 0;
389
390 if (parent.full_header.version == 1 || parent.full_header.version == 2) && parent.index_size > 0 {
391 size += parent.index_size as usize; }
393 size += parent.offset_size as usize; size += parent.length_size as usize; size
397 }
398}
399
400#[derive(IsoBox, Debug, PartialEq, Eq)]
404#[iso_box(box_type = b"pitm", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
405pub struct PrimaryItemBox {
406 pub full_header: FullBoxHeader,
408 pub item_id: u32,
412}
413
414impl<'a> DeserializeSeed<'a, BoxHeader> for PrimaryItemBox {
415 fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
416 where
417 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
418 {
419 let full_header = FullBoxHeader::deserialize(&mut reader)?;
420
421 let item_id = if full_header.version == 0 {
422 u16::deserialize(&mut reader)? as u32
423 } else {
424 u32::deserialize(&mut reader)?
425 };
426
427 Ok(PrimaryItemBox { full_header, item_id })
428 }
429}
430
431impl Serialize for PrimaryItemBox {
432 fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
433 where
434 W: std::io::Write,
435 {
436 self.serialize_box_header(&mut writer)?;
437 self.full_header.serialize(&mut writer)?;
438
439 if self.full_header.version == 0 {
440 (self.item_id as u16).serialize(&mut writer)?;
441 } else {
442 self.item_id.serialize(&mut writer)?;
443 }
444
445 Ok(())
446 }
447}
448
449impl IsoSized for PrimaryItemBox {
450 fn size(&self) -> usize {
451 let mut size = self.full_header.size();
452
453 if self.full_header.version == 0 {
454 size += 2; } else {
456 size += 4; }
458
459 Self::add_header_size(size)
460 }
461}
462
463#[derive(IsoBox, Debug, PartialEq, Eq)]
467#[iso_box(box_type = b"ipro", crate_path = crate)]
468pub struct ItemProtectionBox<'a> {
469 pub full_header: FullBoxHeader,
471 pub protection_count: u16,
473 #[iso_box(nested_box(collect))]
475 pub protection_information: Vec<ProtectionSchemeInfoBox<'a>>,
476}
477
478#[derive(IsoBox, Debug, PartialEq, Eq)]
482#[iso_box(box_type = b"iinf", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
483pub struct ItemInfoBox<'a> {
484 pub full_header: FullBoxHeader,
486 pub entry_count: u32,
488 #[iso_box(nested_box(collect))]
490 pub item_infos: Vec<ItemInfoEntry<'a>>,
491}
492
493impl<'a> DeserializeSeed<'a, BoxHeader> for ItemInfoBox<'a> {
494 fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
495 where
496 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
497 {
498 let full_header = FullBoxHeader::deserialize(&mut reader)?;
499
500 let entry_count = if full_header.version == 0 {
501 u16::deserialize(&mut reader)? as u32
502 } else {
503 u32::deserialize(&mut reader)?
504 };
505
506 let mut item_infos = Vec::with_capacity(entry_count as usize);
507 for _ in 0..entry_count {
508 item_infos.push(ItemInfoEntry::deserialize(&mut reader)?);
509 }
510
511 Ok(ItemInfoBox {
512 full_header,
513 entry_count,
514 item_infos,
515 })
516 }
517}
518
519impl Serialize for ItemInfoBox<'_> {
520 fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
521 where
522 W: std::io::Write,
523 {
524 self.serialize_box_header(&mut writer)?;
525 self.full_header.serialize(&mut writer)?;
526
527 if self.full_header.version == 0 {
528 (self.entry_count as u16).serialize(&mut writer)?;
529 } else {
530 self.entry_count.serialize(&mut writer)?;
531 }
532
533 for item_info in &self.item_infos {
534 item_info.serialize(&mut writer)?;
535 }
536
537 Ok(())
538 }
539}
540
541impl IsoSized for ItemInfoBox<'_> {
542 fn size(&self) -> usize {
543 let mut size = self.full_header.size();
544
545 if self.full_header.version == 0 {
546 size += 2; } else {
548 size += 4; }
550
551 size += self.item_infos.size();
552
553 Self::add_header_size(size)
554 }
555}
556
557#[derive(IsoBox, Debug, PartialEq, Eq)]
561#[iso_box(box_type = b"infe", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
562pub struct ItemInfoEntry<'a> {
563 pub full_header: FullBoxHeader,
565 pub item_id: Option<u32>,
568 pub item_protection_index: u16,
572 pub item_type: [u8; 4],
575 pub item_name: Utf8String,
577 pub item: Option<ItemInfoEntryItem>,
579 pub extension_type: Option<[u8; 4]>,
581 pub extension: Option<ItemInfoExtension<'a>>,
583}
584
585#[derive(Debug, PartialEq, Eq)]
587pub enum ItemInfoEntryItem {
588 Mime {
590 content_type: Utf8String,
593 content_encoding: Utf8String,
598 },
599 Uri {
601 item_uri_type: Utf8String,
603 },
604}
605
606impl<'a> DeserializeSeed<'a, BoxHeader> for ItemInfoEntry<'a> {
607 fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
608 where
609 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
610 {
611 let full_header = FullBoxHeader::deserialize(&mut reader)?;
612
613 let item_id = if full_header.version == 0 || full_header.version == 1 || full_header.version == 2 {
614 Some(u16::deserialize(&mut reader)? as u32)
615 } else if full_header.version == 3 {
616 Some(u32::deserialize(&mut reader)?)
617 } else {
618 None
619 };
620 let item_protection_index = u16::deserialize(&mut reader)?;
621 let item_type = if full_header.version == 0 || full_header.version == 1 {
622 *b"mime"
623 } else {
624 <[u8; 4]>::deserialize(&mut reader)?
625 };
626 let item_name = Utf8String::deserialize(&mut reader)?;
627
628 let item = match &item_type {
629 b"mime" => {
630 let content_type = Utf8String::deserialize(&mut reader)?;
631 let content_encoding = Utf8String::deserialize(&mut reader)?;
632
633 Some(ItemInfoEntryItem::Mime {
634 content_type,
635 content_encoding,
636 })
637 }
638 b"uri " => {
639 let item_uri_type = Utf8String::deserialize(&mut reader)?;
640 Some(ItemInfoEntryItem::Uri { item_uri_type })
641 }
642 _ => None,
643 };
644
645 let extension_type = if full_header.version == 1 {
646 <[u8; 4]>::deserialize(&mut reader).eof_to_none()?
647 } else {
648 None
649 };
650 let extension = if let Some(extension_type) = extension_type {
651 let extension = ItemInfoExtension::deserialize_seed(&mut reader, extension_type)?;
652 Some(extension)
653 } else {
654 None
655 };
656
657 Ok(Self {
658 full_header,
659 item_id,
660 item_protection_index,
661 item_type,
662 item_name,
663 item,
664 extension_type,
665 extension,
666 })
667 }
668}
669
670impl Serialize for ItemInfoEntry<'_> {
671 fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
672 where
673 W: std::io::Write,
674 {
675 self.serialize_box_header(&mut writer)?;
676 self.full_header.serialize(&mut writer)?;
677
678 if self.full_header.version == 0 || self.full_header.version == 1 {
679 (self
680 .item_id
681 .ok_or(io::Error::new(io::ErrorKind::InvalidData, "item_ID is required"))? as u16)
682 .serialize(&mut writer)?;
683 self.item_protection_index.serialize(&mut writer)?;
684 self.item_name.serialize(&mut writer)?;
685 if let Some(ItemInfoEntryItem::Mime {
686 content_type,
687 content_encoding,
688 }) = self.item.as_ref()
689 {
690 content_type.serialize(&mut writer)?;
691 content_encoding.serialize(&mut writer)?;
692 } else {
693 return Err(io::Error::new(io::ErrorKind::InvalidData, "content_type is required"));
694 }
695 }
696
697 if self.full_header.version == 1 {
698 if let Some(extension_type) = self.extension_type {
699 extension_type.serialize(&mut writer)?;
700 }
701 if let Some(extension) = self.extension.as_ref() {
702 extension.serialize(&mut writer)?;
703 }
704 }
705
706 if self.full_header.version >= 2 {
707 if self.full_header.version == 2 {
708 (self
709 .item_id
710 .ok_or(io::Error::new(io::ErrorKind::InvalidData, "item_ID is required"))? as u16)
711 .serialize(&mut writer)?;
712 } else if self.full_header.version == 3 {
713 self.item_id
714 .ok_or(io::Error::new(io::ErrorKind::InvalidData, "item_ID is required"))?
715 .serialize(&mut writer)?;
716 }
717
718 self.item_protection_index.serialize(&mut writer)?;
719 self.item_type.serialize(&mut writer)?;
720 self.item_name.serialize(&mut writer)?;
721 match &self.item {
722 Some(ItemInfoEntryItem::Mime {
723 content_type,
724 content_encoding,
725 }) => {
726 content_type.serialize(&mut writer)?;
727 content_encoding.serialize(&mut writer)?;
728 }
729 Some(ItemInfoEntryItem::Uri { item_uri_type }) => {
730 item_uri_type.serialize(&mut writer)?;
731 }
732 None => {}
733 }
734 }
735
736 Ok(())
737 }
738}
739
740impl IsoSized for ItemInfoEntry<'_> {
741 fn size(&self) -> usize {
742 let mut size = self.full_header.size();
743
744 if self.full_header.version == 0 || self.full_header.version == 1 {
745 size += 2; size += 2; size += self.item_name.size();
748 if let Some(ItemInfoEntryItem::Mime {
749 content_type,
750 content_encoding,
751 }) = &self.item
752 {
753 size += content_type.size();
754 size += content_encoding.size();
755 }
756 }
757 if self.full_header.version == 1 {
758 size += self.extension_type.size();
759 size += self.extension.size();
760 }
761 if self.full_header.version >= 2 {
762 if self.full_header.version == 2 {
763 size += 2; } else if self.full_header.version == 3 {
765 size += 4; }
767 size += 2; size += self.item_type.size();
769 size += self.item_name.size();
770 match &self.item {
771 Some(ItemInfoEntryItem::Mime {
772 content_type,
773 content_encoding,
774 }) => {
775 size += content_type.size();
776 size += content_encoding.size();
777 }
778 Some(ItemInfoEntryItem::Uri { item_uri_type }) => {
779 size += item_uri_type.size();
780 }
781 None => {}
782 }
783 }
784
785 Self::add_header_size(size)
786 }
787}
788
789#[derive(Debug, PartialEq, Eq)]
791pub enum ItemInfoExtension<'a> {
792 FDItemInfoExtension {
794 current_location: Utf8String,
796 current_md5: Utf8String,
799 content_length: u64,
801 transfer_length: u64,
804 entry_count: u8,
807 group_id: Vec<u32>,
810 },
811 Other {
813 extension_type: [u8; 4],
815 data: BytesCow<'a>,
817 },
818}
819
820impl<'a> DeserializeSeed<'a, [u8; 4]> for ItemInfoExtension<'a> {
821 fn deserialize_seed<R>(mut reader: R, seed: [u8; 4]) -> std::io::Result<Self>
822 where
823 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
824 {
825 match &seed {
826 b"fdel" => {
827 let current_location = Utf8String::deserialize(&mut reader)?;
828 let current_md5 = Utf8String::deserialize(&mut reader)?;
829 let content_length = u64::deserialize(&mut reader)?;
830 let transfer_length = u64::deserialize(&mut reader)?;
831 let entry_count = u8::deserialize(&mut reader)?;
832
833 let mut group_id = Vec::with_capacity(entry_count as usize);
834 for _ in 0..entry_count {
835 group_id.push(u32::deserialize(&mut reader)?);
836 }
837
838 Ok(ItemInfoExtension::FDItemInfoExtension {
839 current_location,
840 current_md5,
841 content_length,
842 transfer_length,
843 entry_count,
844 group_id,
845 })
846 }
847 _ => Ok(ItemInfoExtension::Other {
848 extension_type: seed,
849 data: reader.try_read_to_end()?,
850 }),
851 }
852 }
853}
854
855impl Serialize for ItemInfoExtension<'_> {
856 fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
857 where
858 W: std::io::Write,
859 {
860 match self {
861 ItemInfoExtension::FDItemInfoExtension {
862 current_location,
863 current_md5,
864 content_length,
865 transfer_length,
866 entry_count,
867 group_id,
868 } => {
869 current_location.serialize(&mut writer)?;
870 current_md5.serialize(&mut writer)?;
871 content_length.serialize(&mut writer)?;
872 transfer_length.serialize(&mut writer)?;
873 entry_count.serialize(&mut writer)?;
874
875 for id in group_id {
876 id.serialize(&mut writer)?;
877 }
878
879 Ok(())
880 }
881 ItemInfoExtension::Other { extension_type, data } => {
882 extension_type.serialize(&mut writer)?;
883 data.serialize(&mut writer)?;
884 Ok(())
885 }
886 }
887 }
888}
889
890impl IsoSized for ItemInfoExtension<'_> {
891 fn size(&self) -> usize {
892 match self {
893 ItemInfoExtension::FDItemInfoExtension {
894 current_location,
895 current_md5,
896 content_length,
897 transfer_length,
898 entry_count,
899 group_id,
900 } => {
901 current_location.size()
902 + current_md5.size()
903 + content_length.size()
904 + transfer_length.size()
905 + entry_count.size()
906 + group_id.size()
907 }
908 ItemInfoExtension::Other { data, .. } => data.size(),
909 }
910 }
911}
912
913#[derive(IsoBox, PartialEq, Eq)]
921#[iso_box(box_type = b"idat", crate_path = crate)]
922pub struct ItemDataBox<'a> {
923 pub data: BytesCow<'a>,
925}
926
927impl Debug for ItemDataBox<'_> {
928 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
929 f.debug_struct("ItemDataBox").field("data.len", &self.data.len()).finish()
930 }
931}
932
933#[derive(IsoBox, Debug, PartialEq, Eq)]
937#[iso_box(box_type = b"iref", skip_impl(deserialize_seed), crate_path = crate)]
938pub struct ItemReferenceBox {
939 pub full_header: FullBoxHeader,
941 #[iso_box(repeated)]
943 pub references: Vec<SingleItemTypeReferenceBox>,
944}
945
946impl<'a> DeserializeSeed<'a, BoxHeader> for ItemReferenceBox {
947 fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
948 where
949 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
950 {
951 let full_header = FullBoxHeader::deserialize(&mut reader)?;
952
953 let mut references = Vec::new();
954
955 loop {
956 let Some(header) = BoxHeader::deserialize(&mut reader).eof_to_none()? else {
957 break;
958 };
959
960 let Some(iso_box) =
961 SingleItemTypeReferenceBox::deserialize_seed(&mut reader, (header, full_header.version == 1))
962 .eof_to_none()?
963 else {
964 break;
965 };
966 references.push(iso_box);
967 }
968
969 Ok(ItemReferenceBox { full_header, references })
970 }
971}
972
973#[derive(Debug, PartialEq, Eq)]
977pub struct SingleItemTypeReferenceBox {
978 pub large: bool,
980 pub header: BoxHeader,
982 pub from_item_id: u32,
984 pub reference_count: u16,
986 pub to_item_id: Vec<u32>,
988}
989
990impl<'a> DeserializeSeed<'a, (BoxHeader, bool)> for SingleItemTypeReferenceBox {
991 fn deserialize_seed<R>(mut reader: R, seed: (BoxHeader, bool)) -> std::io::Result<Self>
992 where
993 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
994 {
995 let (header, large) = seed;
996
997 let from_item_id = if !large {
998 u16::deserialize(&mut reader)? as u32
999 } else {
1000 u32::deserialize(&mut reader)?
1001 };
1002 let reference_count = u16::deserialize(&mut reader)?;
1003 let mut to_item_id = Vec::with_capacity(reference_count as usize);
1004 for _ in 0..reference_count {
1005 if !large {
1006 to_item_id.push(u16::deserialize(&mut reader)? as u32);
1007 } else {
1008 to_item_id.push(u32::deserialize(&mut reader)?);
1009 }
1010 }
1011
1012 Ok(SingleItemTypeReferenceBox {
1013 large,
1014 header,
1015 from_item_id,
1016 reference_count,
1017 to_item_id,
1018 })
1019 }
1020}
1021
1022impl Serialize for SingleItemTypeReferenceBox {
1023 fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
1024 where
1025 W: std::io::Write,
1026 {
1027 self.header.serialize(&mut writer)?;
1028
1029 if !self.large {
1030 (self.from_item_id as u16).serialize(&mut writer)?;
1031 } else {
1032 self.from_item_id.serialize(&mut writer)?;
1033 }
1034 self.reference_count.serialize(&mut writer)?;
1035 for id in &self.to_item_id {
1036 if !self.large {
1037 (*id as u16).serialize(&mut writer)?;
1038 } else {
1039 id.serialize(&mut writer)?;
1040 }
1041 }
1042
1043 Ok(())
1044 }
1045}
1046
1047impl IsoSized for SingleItemTypeReferenceBox {
1048 fn size(&self) -> usize {
1049 let mut size = self.header.size();
1050
1051 if !self.large {
1052 size += 2; size += 2; size += self.to_item_id.len() * 2; } else {
1056 size += 4; size += 2; size += self.to_item_id.len() * 4; }
1060
1061 size
1062 }
1063}
1064
1065#[derive(IsoBox, Debug, PartialEq, Eq)]
1069#[iso_box(box_type = b"iprp", crate_path = crate)]
1070pub struct ItemPropertiesBox<'a> {
1071 #[iso_box(nested_box)]
1073 pub property_container: ItemPropertyContainerBox<'a>,
1074 #[iso_box(nested_box(collect))]
1076 pub association: Vec<ItemPropertyAssociationBox>,
1077}
1078
1079#[derive(IsoBox, Debug, PartialEq, Eq)]
1083#[iso_box(box_type = b"ipco", crate_path = crate)]
1084pub struct ItemPropertyContainerBox<'a> {
1085 #[iso_box(nested_box(collect))]
1087 pub etyp: Option<ExtendedTypeBox<'a>>,
1088 #[iso_box(nested_box(collect))]
1090 pub brnd: Vec<BrandProperty>,
1091 #[iso_box(nested_box(collect))]
1093 pub scrb: Vec<ScrambleSchemeInfoBox<'a>>,
1094 #[iso_box(nested_box(collect_unknown))]
1096 pub boxes: Vec<UnknownBox<'a>>,
1097}
1098
1099#[derive(IsoBox, Debug, PartialEq, Eq)]
1103#[iso_box(box_type = b"ipma", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
1104pub struct ItemPropertyAssociationBox {
1105 pub full_header: FullBoxHeader,
1107 pub entry_count: u32,
1109 pub entries: Vec<ItemPropertyAssociationBoxEntry>,
1111}
1112
1113impl<'a> DeserializeSeed<'a, BoxHeader> for ItemPropertyAssociationBox {
1114 fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
1115 where
1116 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
1117 {
1118 let full_header = FullBoxHeader::deserialize(&mut reader)?;
1119 let entry_count = u32::deserialize(&mut reader)?;
1120
1121 let mut entries = Vec::with_capacity(entry_count as usize);
1122 for _ in 0..entry_count {
1123 entries.push(ItemPropertyAssociationBoxEntry::deserialize_seed(&mut reader, &full_header)?);
1124 }
1125
1126 Ok(ItemPropertyAssociationBox {
1127 full_header,
1128 entry_count,
1129 entries,
1130 })
1131 }
1132}
1133
1134impl Serialize for ItemPropertyAssociationBox {
1135 fn serialize<W>(&self, mut writer: W) -> io::Result<()>
1136 where
1137 W: std::io::Write,
1138 {
1139 self.serialize_box_header(&mut writer)?;
1140 self.full_header.serialize(&mut writer)?;
1141 self.entry_count.serialize(&mut writer)?;
1142
1143 for entry in &self.entries {
1144 entry.serialize(&mut writer, &self.full_header)?;
1145 }
1146
1147 Ok(())
1148 }
1149}
1150
1151impl IsoSized for ItemPropertyAssociationBox {
1152 fn size(&self) -> usize {
1153 let mut size = self.full_header.size();
1154
1155 size += 4; size += self.entries.iter().map(|e| e.size(&self.full_header)).sum::<usize>();
1157
1158 Self::add_header_size(size)
1159 }
1160}
1161
1162#[derive(Debug, PartialEq, Eq)]
1164pub struct ItemPropertyAssociationBoxEntry {
1165 pub item_id: u32,
1167 pub association_count: u8,
1169 pub associations: Vec<ItemPropertyAssociationBoxEntryAssociation>,
1171}
1172
1173impl<'a> DeserializeSeed<'a, &FullBoxHeader> for ItemPropertyAssociationBoxEntry {
1174 fn deserialize_seed<R>(mut reader: R, seed: &FullBoxHeader) -> std::io::Result<Self>
1175 where
1176 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
1177 {
1178 let item_id = if seed.version < 1 {
1179 u16::deserialize(&mut reader)? as u32
1180 } else {
1181 u32::deserialize(&mut reader)?
1182 };
1183
1184 let assocation_count = u8::deserialize(&mut reader)?;
1185 let mut associations = Vec::with_capacity(assocation_count as usize);
1186 for _ in 0..assocation_count {
1187 associations.push(ItemPropertyAssociationBoxEntryAssociation::deserialize_seed(
1188 &mut reader,
1189 seed,
1190 )?);
1191 }
1192
1193 Ok(ItemPropertyAssociationBoxEntry {
1194 item_id,
1195 association_count: assocation_count,
1196 associations,
1197 })
1198 }
1199}
1200
1201impl ItemPropertyAssociationBoxEntry {
1202 fn serialize<W>(&self, mut writer: W, header: &FullBoxHeader) -> io::Result<()>
1203 where
1204 W: std::io::Write,
1205 {
1206 if header.version < 1 {
1207 (self.item_id as u16).serialize(&mut writer)?;
1208 } else {
1209 self.item_id.serialize(&mut writer)?;
1210 }
1211
1212 self.association_count.serialize(&mut writer)?;
1213 for association in &self.associations {
1214 association.serialize(&mut writer, header.flags)?;
1215 }
1216
1217 Ok(())
1218 }
1219}
1220
1221impl ItemPropertyAssociationBoxEntry {
1222 pub fn size(&self, header: &FullBoxHeader) -> usize {
1224 let mut size = 0;
1225
1226 if header.version < 1 {
1227 size += 2; } else {
1229 size += 4; }
1231 size += 1; size += self.associations.iter().map(|a| a.size(header.flags)).sum::<usize>();
1233
1234 size
1235 }
1236}
1237
1238#[derive(Debug, PartialEq, Eq)]
1240pub struct ItemPropertyAssociationBoxEntryAssociation {
1241 pub essential: bool,
1243 pub property_index: u16,
1247}
1248
1249impl<'a> DeserializeSeed<'a, &FullBoxHeader> for ItemPropertyAssociationBoxEntryAssociation {
1250 fn deserialize_seed<R>(mut reader: R, seed: &FullBoxHeader) -> std::io::Result<Self>
1251 where
1252 R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
1253 {
1254 let byte = u8::deserialize(&mut reader)?;
1255 let essential = byte >> 7 != 0;
1256 let property_index = (byte & 0b0111_1111) as u16;
1257
1258 if (*seed.flags & 0b1) != 0 {
1259 let low_byte = u8::deserialize(&mut reader)?;
1260
1261 Ok(Self {
1262 essential,
1263 property_index: (property_index << 8) | low_byte as u16,
1264 })
1265 } else {
1266 Ok(Self {
1267 essential,
1268 property_index,
1269 })
1270 }
1271 }
1272}
1273
1274impl ItemPropertyAssociationBoxEntryAssociation {
1275 fn serialize<W>(&self, mut writer: W, flags: U24Be) -> io::Result<()>
1276 where
1277 W: std::io::Write,
1278 {
1279 if (*flags & 0b1) != 0 {
1280 let mut byte = (self.essential as u8) << 7;
1282 byte |= ((self.property_index >> 8) as u8) & 0b0111_1111;
1283 byte.serialize(&mut writer)?;
1284
1285 let low_byte = (self.property_index & 0xFF) as u8;
1287 low_byte.serialize(&mut writer)?;
1288 } else {
1289 let byte = (self.essential as u8) << 7 | (self.property_index & 0b0111_1111) as u8;
1291 byte.serialize(&mut writer)?;
1292 }
1293
1294 Ok(())
1295 }
1296}
1297
1298impl ItemPropertyAssociationBoxEntryAssociation {
1299 pub fn size(&self, flags: U24Be) -> usize {
1301 if (*flags & 0b1) != 0 {
1302 2 } else {
1304 1 }
1306 }
1307}
1308
1309#[derive(IsoBox, Debug, PartialEq, Eq)]
1313#[iso_box(box_type = b"brnd", crate_path = crate)]
1314pub struct BrandProperty {
1315 #[iso_box(from = "[u8; 4]")]
1317 pub major_brand: Brand,
1318 pub minor_version: u32,
1320 #[iso_box(repeated, from = "[u8; 4]")]
1322 pub compatible_brands: Vec<Brand>,
1323}