1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Default)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct Iprp {
9 pub ipco: Ipco,
10 pub ipma: Vec<Ipma>,
11}
12
13impl Atom for Iprp {
14 const KIND: FourCC = FourCC::new(b"iprp");
15
16 nested! {
17 required: [ Ipco ],
18 optional: [ ],
19 multiple: [ Ipma ],
20 }
21}
22
23#[derive(Debug, Clone, PartialEq, Default)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct Ipco {
26 pub properties: Vec<crate::Any>,
28}
29
30impl Atom for Ipco {
31 const KIND: FourCC = FourCC::new(b"ipco");
32
33 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
34 let mut props = vec![];
35 while let Some(prop) = crate::Any::decode_maybe(buf)? {
36 props.push(prop);
37 }
38 Ok(Self { properties: props })
39 }
40
41 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
42 for property in &self.properties {
43 property.encode(buf)?
44 }
45 Ok(())
46 }
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Default)]
50#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
51pub struct PropertyAssociation {
52 pub essential: bool,
53 pub property_index: u16,
54}
55
56impl PropertyAssociation {
57 fn encode<B: BufMut>(&self, buf: &mut B, prop_index_15_bit: bool) -> Result<()> {
58 if prop_index_15_bit {
59 let flag_and_prop_index = if self.essential {
60 0x8000 | self.property_index
61 } else {
62 self.property_index
63 };
64 flag_and_prop_index.encode(buf)
65 } else {
66 let flag_and_prop_index = if self.essential {
67 0x80 | (self.property_index as u8)
68 } else {
69 self.property_index as u8
70 };
71 flag_and_prop_index.encode(buf)
72 }
73 }
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Default)]
77#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
78pub struct PropertyAssociations {
79 pub item_id: u32,
80 pub associations: Vec<PropertyAssociation>,
81}
82
83impl PropertyAssociations {
84 fn encode<B: BufMut>(
85 &self,
86 buf: &mut B,
87 version: IpmaVersion,
88 prop_index_15_bit: bool,
89 ) -> Result<()> {
90 if version == IpmaVersion::V0 {
91 (self.item_id as u16).encode(buf)?;
92 } else {
93 self.item_id.encode(buf)?;
94 }
95 let association_count: u8 = self.associations.len() as u8;
96 association_count.encode(buf)?;
97 for association in &self.associations {
98 association.encode(buf, prop_index_15_bit)?;
99 }
100 Ok(())
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Default)]
105#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
106pub struct Ipma {
107 pub item_properties: Vec<PropertyAssociations>,
108}
109
110ext! {
111 name: Ipma,
112 versions: [0, 1],
113 flags: {
114 prop_index_15_bits = 1,
115 }
116}
117
118impl AtomExt for Ipma {
119 type Ext = IpmaExt;
120
121 const KIND_EXT: FourCC = FourCC::new(b"ipma");
122
123 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<Self::Ext> {
124 let mut version = IpmaVersion::V0;
125 let mut prop_index_15_bit = false;
126 for item_property in &self.item_properties {
127 if item_property.item_id > (u16::MAX as u32) {
128 version = IpmaVersion::V1;
129 }
130 for association in &item_property.associations {
131 if association.property_index > 0x7f {
132 prop_index_15_bit = true;
133 }
134 }
135 }
136 let entry_count: u32 = self.item_properties.len() as u32;
137 entry_count.encode(buf)?;
138 for item_property in &self.item_properties {
139 item_property.encode(buf, version, prop_index_15_bit)?;
140 }
141 Ok(IpmaExt {
142 version,
143 prop_index_15_bits: prop_index_15_bit,
144 })
145 }
146
147 fn decode_body_ext<B: Buf>(buf: &mut B, ext: Self::Ext) -> Result<Self> {
148 let entry_count = u32::decode(buf)?;
149 let mut item_properties = vec![];
150 for _i in 0..entry_count {
151 let item_id: u32 = if ext.version == IpmaVersion::V0 {
152 u16::decode(buf)? as u32
153 } else {
154 u32::decode(buf)?
155 };
156 let mut associations = vec![];
157 let association_count = u8::decode(buf)?;
158 for _j in 0..association_count {
161 if ext.prop_index_15_bits {
162 let flag_and_prop_index = u16::decode(buf)?;
163 let essential = (flag_and_prop_index & 0x8000) == 0x8000;
164 let property_index = flag_and_prop_index & 0x7fff;
165 associations.push(PropertyAssociation {
166 essential,
167 property_index,
168 });
169 } else {
170 let flag_and_prop_index = u8::decode(buf)?;
171 let essential = (flag_and_prop_index & 0x80) == 0x80;
172 let property_index = (flag_and_prop_index & 0x7f) as u16;
173 associations.push(PropertyAssociation {
174 essential,
175 property_index,
176 });
177 }
178 }
179 item_properties.push(PropertyAssociations {
180 item_id,
181 associations,
182 });
183 }
184 Ok(Self { item_properties })
185 }
186}