in mp4parse/src/lib.rs [3513:3592]
fn read_ipma<T: Read>(
src: &mut BMFFBox<T>,
strictness: ParseStrictness,
version: u8,
flags: u32,
) -> Result<TryVec<ItemPropertyAssociationEntry>> {
let entry_count = be_u32(src)?;
let num_association_bytes =
std::num::NonZeroU8::new(if flags & 1 == 1 { 2 } else { 1 }).unwrap();
let total_associations = calculate_ipma_total_associations(
version,
src.bytes_left(),
U32::new(entry_count),
num_association_bytes,
)?;
// Assuming most items will have at least `MIN_PROPERTIES` and knowing the
// total number of item -> property associations (`total_associations`),
// we can provide a good estimate for how many elements we'll need in this
// vector, even though we don't know precisely how many items there will be
// properties for.
let mut entries = TryVec::<ItemPropertyAssociationEntry>::with_capacity(
total_associations / ItemPropertiesBox::MIN_PROPERTIES,
)?;
for _ in 0..entry_count {
let item_id = ItemId::read(src, version)?;
if let Some(previous_association) = entries.last() {
#[allow(clippy::comparison_chain)]
if previous_association.item_id > item_id {
return Status::IpmaBadItemOrder.into();
} else if previous_association.item_id == item_id {
return Status::IpmaDuplicateItemId.into();
}
}
let association_count = src.read_u8()?;
let mut associations = TryVec::with_capacity(association_count.to_usize())?;
for _ in 0..association_count {
let association = src
.take(num_association_bytes.get().into())
.read_into_try_vec()?;
let mut association = BitReader::new(association.as_slice());
let essential = association.read_bool()?;
let property_index =
PropertyIndex(association.read_u16(association.remaining().try_into()?)?);
associations.push(Association {
essential,
property_index,
})?;
}
entries.push(ItemPropertyAssociationEntry {
item_id,
associations,
})?;
}
check_parser_state!(src.content);
if version != 0 {
if let Some(ItemPropertyAssociationEntry {
item_id: max_item_id,
..
}) = entries.last()
{
if *max_item_id <= ItemId(u16::MAX.into()) {
fail_with_status_if(
strictness == ParseStrictness::Strict,
Status::IpmaBadVersion,
)?;
}
}
}
trace!("read_ipma -> {:#?}", entries);
Ok(entries)
}