Skip to content

Commit 8aa0f2e

Browse files
kornelskibaumanj
andcommitted
Enforce correct iprp structure
Co-authored-by: baumanj <[email protected]>
1 parent a7eb5eb commit 8aa0f2e

File tree

1 file changed

+40
-26
lines changed

1 file changed

+40
-26
lines changed

mp4parse/src/lib.rs

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,36 +1557,49 @@ fn read_iref<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<SingleItemTypeRefer
15571557

15581558
fn read_iprp<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<AssociatedProperty>> {
15591559
let mut iter = src.box_iter();
1560-
let mut properties = TryHashMap::with_capacity(1)?;
1561-
let mut associations = TryVec::new();
1560+
1561+
let properties = match iter.next_box()? {
1562+
Some(mut b) if b.head.name == BoxType::ItemPropertyContainerBox => read_ipco(&mut b),
1563+
Some(_) => Err(Error::InvalidData("unexpected iprp child")),
1564+
None => Err(Error::UnexpectedEOF),
1565+
}?;
1566+
1567+
// Per ISO 23008-12:2017 § 9.3.1: There can be zero or more ipma boxes
1568+
// but "There shall be at most one ItemPropertyAssociationbox with a given
1569+
// pair of values of version and flags"
1570+
let mut ipma_version_and_flag_values_seen = TryHashMap::with_capacity(1)?;
1571+
let mut associated = TryVec::new();
15621572

15631573
while let Some(mut b) = iter.next_box()? {
1564-
match b.head.name {
1565-
BoxType::ItemPropertyContainerBox => {
1566-
properties = read_ipco(&mut b)?;
1567-
}
1568-
BoxType::ItemPropertyAssociationBox => {
1569-
associations = read_ipma(&mut b)?;
1574+
if b.head.name != BoxType::ItemPropertyAssociationBox {
1575+
return Err(Error::InvalidData("unexpected iprp child"));
1576+
}
1577+
1578+
let version_and_flags = read_fullbox_extra(&mut b)?;
1579+
if ipma_version_and_flag_values_seen
1580+
.insert(version_and_flags, ())?
1581+
.is_some()
1582+
{
1583+
return Err(Error::InvalidData("Duplicate ipma with same version/flags"));
1584+
}
1585+
let associations = read_ipma(&mut b, version_and_flags)?;
1586+
for a in associations {
1587+
if a.property_index == 0 {
1588+
if a.essential {
1589+
return Err(Error::InvalidData("0 property index can't be essential"));
1590+
}
1591+
continue;
15701592
}
1571-
_ => return Err(Error::InvalidData("unexpected ipco child")),
1572-
}
1573-
}
15741593

1575-
let mut associated = TryVec::new();
1576-
for a in associations {
1577-
if a.property_index == 0 {
1578-
if a.essential {
1579-
return Err(Error::InvalidData("0 property index can't be essential"));
1594+
if let Some(prop) = properties.get(&a.property_index) {
1595+
associated.push(AssociatedProperty {
1596+
item_id: a.item_id,
1597+
property: prop.try_clone()?,
1598+
})?;
15801599
}
1581-
continue;
15821600
}
15831601

1584-
if let Some(prop) = properties.get(&a.property_index) {
1585-
associated.push(AssociatedProperty {
1586-
item_id: a.item_id,
1587-
property: prop.try_clone()?,
1588-
})?;
1589-
}
1602+
check_parser_state!(b.content);
15901603
}
15911604

15921605
Ok(associated)
@@ -1620,9 +1633,10 @@ pub struct AssociatedProperty {
16201633
pub property: ItemProperty,
16211634
}
16221635

1623-
fn read_ipma<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<Association>> {
1624-
let (version, flags) = read_fullbox_extra(src)?;
1625-
1636+
fn read_ipma<T: Read>(
1637+
src: &mut BMFFBox<T>,
1638+
(version, flags): (u8, u32),
1639+
) -> Result<TryVec<Association>> {
16261640
let mut associations = TryVec::new();
16271641

16281642
let entry_count = be_u32(src)?;

0 commit comments

Comments
 (0)