1extern crate alloc;
6
7use alloc::vec::Vec;
8
9use broadcast_common::{Parse, Serialize};
10
11use crate::error::{Error, Result};
12use crate::local_set::{LocalSet, StructuralSetKind};
13use crate::sets::{
14 InterchangeObjectFields, LocalSetOwnedItem, collect_dark, finish_owned_set, get_optional_fixed,
15 get_optional_raw, get_required_fixed, get_required_raw, owned_set_serialized_len,
16 serialize_owned_set,
17};
18use crate::types::{MxfTimestamp, UlBytes, parse_uid_batch, serialize_uid_batch};
19
20pub const TAG_LAST_MODIFIED_DATE: u16 = 0x3B02;
22pub const TAG_VERSION: u16 = 0x3B05;
24pub const TAG_OBJECT_MODEL_VERSION: u16 = 0x3B07;
26pub const TAG_PRIMARY_PACKAGE: u16 = 0x3B08;
28pub const TAG_IDENTIFICATIONS: u16 = 0x3B06;
30pub const TAG_CONTENT_STORAGE: u16 = 0x3B03;
32pub const TAG_OPERATIONAL_PATTERN: u16 = 0x3B09;
34pub const TAG_ESSENCE_CONTAINERS: u16 = 0x3B0A;
36pub const TAG_DM_SCHEMES: u16 = 0x3B0B;
38
39const KNOWN_TAGS: [u16; 12] = [
40 crate::sets::TAG_INSTANCE_UID,
41 crate::sets::TAG_GENERATION_UID,
42 crate::sets::TAG_OBJECT_CLASS,
43 TAG_LAST_MODIFIED_DATE,
44 TAG_VERSION,
45 TAG_OBJECT_MODEL_VERSION,
46 TAG_PRIMARY_PACKAGE,
47 TAG_IDENTIFICATIONS,
48 TAG_CONTENT_STORAGE,
49 TAG_OPERATIONAL_PATTERN,
50 TAG_ESSENCE_CONTAINERS,
51 TAG_DM_SCHEMES,
52];
53
54pub const VERSION_1_3: u16 = 0x0103;
56
57#[derive(Debug, Clone, PartialEq, Eq)]
68pub struct Preface {
69 pub interchange: InterchangeObjectFields,
71 pub last_modified_date: MxfTimestamp,
73 pub version: u16,
76 pub object_model_version: Option<u32>,
78 pub primary_package: Option<UlBytes>,
81 pub identifications: Vec<UlBytes>,
87 pub content_storage: UlBytes,
90 pub operational_pattern: UlBytes,
93 pub essence_containers: Vec<UlBytes>,
96 pub dm_schemes: Vec<UlBytes>,
99 pub dark: Vec<(u16, Vec<u8>)>,
103}
104
105impl<'a> Parse<'a> for Preface {
106 type Error = Error;
107
108 fn parse(bytes: &'a [u8]) -> Result<Self> {
109 let set = LocalSet::parse(bytes)?;
110 if set.kind() != StructuralSetKind::Preface {
111 return Err(Error::KeyPrefixMismatch {
112 what: "Preface (Table 17)",
113 });
114 }
115 let items = &set.items;
116 let interchange = InterchangeObjectFields::decode(items, "Preface")?;
117 let last_modified_date = MxfTimestamp::parse(get_required_raw(
118 items,
119 TAG_LAST_MODIFIED_DATE,
120 "Last Modified Date",
121 "Preface",
122 )?)?;
123 let version = u16::from_be_bytes(get_required_fixed::<2>(
124 items,
125 TAG_VERSION,
126 "Version",
127 "Preface",
128 )?);
129 let object_model_version =
130 get_optional_fixed::<4>(items, TAG_OBJECT_MODEL_VERSION, "Object Model Version")?
131 .map(u32::from_be_bytes);
132 let primary_package =
133 get_optional_fixed::<16>(items, TAG_PRIMARY_PACKAGE, "Primary Package")?;
134 let identifications = match get_optional_raw(items, TAG_IDENTIFICATIONS) {
135 Some(raw) => parse_uid_batch(raw)?,
136 None => Vec::new(),
137 };
138 let content_storage =
139 get_required_fixed::<16>(items, TAG_CONTENT_STORAGE, "Content Storage", "Preface")?;
140 let operational_pattern = get_required_fixed::<16>(
141 items,
142 TAG_OPERATIONAL_PATTERN,
143 "Operational Pattern",
144 "Preface",
145 )?;
146 let essence_containers = parse_uid_batch(get_required_raw(
147 items,
148 TAG_ESSENCE_CONTAINERS,
149 "EssenceContainers",
150 "Preface",
151 )?)?;
152 let dm_schemes = parse_uid_batch(get_required_raw(
153 items,
154 TAG_DM_SCHEMES,
155 "DM Schemes",
156 "Preface",
157 )?)?;
158 let dark = collect_dark(items, &KNOWN_TAGS);
159
160 Ok(Preface {
161 interchange,
162 last_modified_date,
163 version,
164 object_model_version,
165 primary_package,
166 identifications,
167 content_storage,
168 operational_pattern,
169 essence_containers,
170 dm_schemes,
171 dark,
172 })
173 }
174}
175
176impl Preface {
177 fn owned_items(&self) -> Vec<LocalSetOwnedItem> {
178 let mut out = Vec::new();
179 self.interchange.encode_into(&mut out);
180 {
181 let mut buf = [0u8; crate::types::TIMESTAMP_LEN];
182 self.last_modified_date
183 .serialize_into(&mut buf)
184 .expect("fixed-size buffer");
185 out.push(LocalSetOwnedItem::owned(
186 TAG_LAST_MODIFIED_DATE,
187 buf.to_vec(),
188 ));
189 }
190 out.push(LocalSetOwnedItem::fixed(
191 TAG_VERSION,
192 self.version.to_be_bytes(),
193 ));
194 if let Some(v) = self.object_model_version {
195 out.push(LocalSetOwnedItem::fixed(
196 TAG_OBJECT_MODEL_VERSION,
197 v.to_be_bytes(),
198 ));
199 }
200 if let Some(p) = self.primary_package {
201 out.push(LocalSetOwnedItem::fixed(TAG_PRIMARY_PACKAGE, p));
202 }
203 out.push(LocalSetOwnedItem::owned(
204 TAG_IDENTIFICATIONS,
205 serialize_uid_batch(&self.identifications),
206 ));
207 out.push(LocalSetOwnedItem::fixed(
208 TAG_CONTENT_STORAGE,
209 self.content_storage,
210 ));
211 out.push(LocalSetOwnedItem::fixed(
212 TAG_OPERATIONAL_PATTERN,
213 self.operational_pattern,
214 ));
215 out.push(LocalSetOwnedItem::owned(
216 TAG_ESSENCE_CONTAINERS,
217 serialize_uid_batch(&self.essence_containers),
218 ));
219 out.push(LocalSetOwnedItem::owned(
220 TAG_DM_SCHEMES,
221 serialize_uid_batch(&self.dm_schemes),
222 ));
223 out
224 }
225}
226
227impl Serialize for Preface {
228 type Error = Error;
229
230 fn serialized_len(&self) -> usize {
231 let (key, items) =
232 finish_owned_set(StructuralSetKind::Preface, self.owned_items(), &self.dark);
233 owned_set_serialized_len(key, &items)
234 }
235
236 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
237 let (key, items) =
238 finish_owned_set(StructuralSetKind::Preface, self.owned_items(), &self.dark);
239 serialize_owned_set(key, &items, buf)
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246
247 fn sample() -> Preface {
248 Preface {
249 interchange: InterchangeObjectFields {
250 instance_uid: [0x11; 16],
251 generation_uid: Some([0x22; 16]),
252 object_class: None,
253 },
254 last_modified_date: MxfTimestamp {
255 year: 2019,
256 month: 11,
257 day: 28,
258 hour: 10,
259 minute: 0,
260 second: 0,
261 msec_div4: 0,
262 },
263 version: VERSION_1_3,
264 object_model_version: Some(1),
265 primary_package: Some([0x33; 16]),
266 identifications: alloc::vec![[0x44; 16]],
267 content_storage: [0x55; 16],
268 operational_pattern: [0x66; 16],
269 essence_containers: alloc::vec![[0x77; 16]],
270 dm_schemes: Vec::new(),
271 dark: Vec::new(),
272 }
273 }
274
275 #[test]
276 fn construct_serialize_parse_round_trip() {
277 let preface = sample();
278 let mut buf = alloc::vec![0u8; preface.serialized_len()];
279 preface.serialize_into(&mut buf).unwrap();
280 let parsed = Preface::parse(&buf).unwrap();
281 assert_eq!(parsed, preface);
282
283 let mut buf2 = alloc::vec![0u8; parsed.serialized_len()];
285 parsed.serialize_into(&mut buf2).unwrap();
286 assert_eq!(buf, buf2);
287 }
288
289 #[test]
290 fn mutation_changes_serialized_bytes() {
291 let mut preface = sample();
292 let original = preface.to_bytes();
293 preface.version = 0x0200;
294 let mutated = preface.to_bytes();
295 assert_ne!(original, mutated);
296 assert_eq!(Preface::parse(&mutated).unwrap().version, 0x0200);
297 }
298
299 #[test]
300 fn dark_tags_preserved_round_trip() {
301 let mut preface = sample();
302 preface.dark = alloc::vec![(0x8001, alloc::vec![9, 9, 9])];
303 let bytes = preface.to_bytes();
304 let parsed = Preface::parse(&bytes).unwrap();
305 assert_eq!(parsed.dark, preface.dark);
306 }
307
308 #[test]
309 fn identifications_absent_tolerated_e_req_not_hard_required() {
310 let mut preface = sample();
315 preface.identifications = Vec::new();
316 let owned = preface.owned_items();
317 let items: Vec<LocalSetOwnedItem> = owned
318 .into_iter()
319 .filter(|item| item.tag != TAG_IDENTIFICATIONS)
320 .collect();
321 let (key, encoded) = finish_owned_set(StructuralSetKind::Preface, items, &Vec::new());
322 let mut buf = alloc::vec![0u8; owned_set_serialized_len(key, &encoded)];
323 serialize_owned_set(key, &encoded, &mut buf).unwrap();
324
325 let parsed = Preface::parse(&buf).expect("absent Identifications must not error");
326 assert_eq!(parsed.identifications, Vec::<UlBytes>::new());
327 }
328
329 #[test]
330 fn wrong_kind_rejected() {
331 let key = LocalSet::build_key(
332 StructuralSetKind::Identification,
333 crate::local_set::ItemLengthMode::TwoByte,
334 );
335 let set = LocalSet {
336 key,
337 items: Vec::new(),
338 };
339 let bytes = set.to_bytes();
340 assert!(matches!(
341 Preface::parse(&bytes),
342 Err(Error::KeyPrefixMismatch { .. })
343 ));
344 }
345}