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)]
50pub struct PropertyAssociation {
51 pub essential: bool,
52 pub property_index: u16,
53}
54
55impl PropertyAssociation {
56 fn encode<B: BufMut>(&self, buf: &mut B, prop_index_15_bit: bool) -> Result<()> {
57 if prop_index_15_bit {
58 let flag_and_prop_index = if self.essential {
59 0x8000 | self.property_index
60 } else {
61 self.property_index
62 };
63 flag_and_prop_index.encode(buf)
64 } else {
65 let flag_and_prop_index = if self.essential {
66 0x80 | (self.property_index as u8)
67 } else {
68 self.property_index as u8
69 };
70 flag_and_prop_index.encode(buf)
71 }
72 }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, Default)]
76pub struct PropertyAssociations {
77 pub item_id: u32,
78 pub associations: Vec<PropertyAssociation>,
79}
80
81impl PropertyAssociations {
82 fn encode<B: BufMut>(
83 &self,
84 buf: &mut B,
85 version: IpmaVersion,
86 prop_index_15_bit: bool,
87 ) -> Result<()> {
88 if version == IpmaVersion::V0 {
89 (self.item_id as u16).encode(buf)?;
90 } else {
91 self.item_id.encode(buf)?;
92 }
93 let association_count: u8 = self.associations.len() as u8;
94 association_count.encode(buf)?;
95 for association in &self.associations {
96 association.encode(buf, prop_index_15_bit)?;
97 }
98 Ok(())
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, Default)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
104pub struct Ipma {
105 pub item_properties: Vec<PropertyAssociations>,
106}
107
108ext! {
109 name: Ipma,
110 versions: [0, 1],
111 flags: {
112 prop_index_15_bits = 1,
113 }
114}
115
116impl AtomExt for Ipma {
117 type Ext = IpmaExt;
118
119 const KIND_EXT: FourCC = FourCC::new(b"ipma");
120
121 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<Self::Ext> {
122 let mut version = IpmaVersion::V0;
123 let mut prop_index_15_bit = false;
124 for item_property in &self.item_properties {
125 if item_property.item_id > (u16::MAX as u32) {
126 version = IpmaVersion::V1;
127 }
128 for association in &item_property.associations {
129 if association.property_index > 0x7f {
130 prop_index_15_bit = true;
131 }
132 }
133 }
134 let entry_count: u32 = self.item_properties.len() as u32;
135 entry_count.encode(buf)?;
136 for item_property in &self.item_properties {
137 item_property.encode(buf, version, prop_index_15_bit)?;
138 }
139 Ok(IpmaExt {
140 version,
141 prop_index_15_bits: prop_index_15_bit,
142 })
143 }
144
145 fn decode_body_ext<B: Buf>(buf: &mut B, ext: Self::Ext) -> Result<Self> {
146 let entry_count = u32::decode(buf)?;
147 let mut item_properties = vec![];
148 for _i in 0..entry_count {
149 let item_id: u32 = if ext.version == IpmaVersion::V0 {
150 u16::decode(buf)? as u32
151 } else {
152 u32::decode(buf)?
153 };
154 let mut associations = vec![];
155 let association_count = u8::decode(buf)?;
156 for _j in 0..association_count {
159 if ext.prop_index_15_bits {
160 let flag_and_prop_index = u16::decode(buf)?;
161 let essential = (flag_and_prop_index & 0x8000) == 0x8000;
162 let property_index = flag_and_prop_index & 0x7fff;
163 associations.push(PropertyAssociation {
164 essential,
165 property_index,
166 });
167 } else {
168 let flag_and_prop_index = u8::decode(buf)?;
169 let essential = (flag_and_prop_index & 0x80) == 0x80;
170 let property_index = (flag_and_prop_index & 0x7f) as u16;
171 associations.push(PropertyAssociation {
172 essential,
173 property_index,
174 });
175 }
176 }
177 item_properties.push(PropertyAssociations {
178 item_id,
179 associations,
180 });
181 }
182 Ok(Self { item_properties })
183 }
184}