1#[cfg(test)]
6pub mod test_utils;
7pub(crate) mod util;
8
9pub(crate) mod atom_ref;
10pub mod container;
11pub mod fourcc;
12pub mod iter;
13pub mod leaf;
14
15use bon::bon;
16
17use crate::{
18 atom::util::parser::rest_vec, parser::ParseAtomData, writer::SerializeAtom, ParseError,
19};
20
21pub use self::{container::*, fourcc::*, leaf::*};
22
23#[derive(Clone)]
25pub struct RawData {
26 atom_type: FourCC,
27 data: Vec<u8>,
28}
29
30impl RawData {
31 pub fn new(atom_type: FourCC, data: Vec<u8>) -> Self {
32 Self { atom_type, data }
33 }
34
35 pub fn as_slice(&self) -> &[u8] {
36 &self.data
37 }
38
39 pub fn to_vec(self) -> Vec<u8> {
40 self.data
41 }
42}
43
44impl ParseAtomData for RawData {
45 fn parse_atom_data(atom_type: FourCC, input: &[u8]) -> Result<Self, ParseError> {
46 use crate::atom::util::parser::stream;
47 use winnow::Parser;
48 let data = rest_vec.parse(stream(input))?;
49 Ok(RawData::new(atom_type, data))
50 }
51}
52
53impl SerializeAtom for RawData {
54 fn atom_type(&self) -> FourCC {
55 self.atom_type
56 }
57
58 fn into_body_bytes(self) -> Vec<u8> {
59 self.data
60 }
61}
62
63impl std::fmt::Debug for RawData {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 write!(f, "[u8; {}]", self.data.len())
66 }
67}
68
69#[derive(Debug, Clone)]
70pub struct AtomHeader {
71 pub atom_type: FourCC,
72 pub offset: usize,
73 pub header_size: usize,
74 pub data_size: usize,
75}
76
77impl AtomHeader {
78 pub fn new(atom_type: impl Into<FourCC>) -> Self {
79 Self {
80 atom_type: atom_type.into(),
81 offset: 0,
82 header_size: 0,
83 data_size: 0,
84 }
85 }
86
87 pub fn location(&self) -> (usize, usize) {
88 (self.offset, self.header_size + self.data_size)
89 }
90
91 pub fn atom_size(&self) -> usize {
92 self.header_size + self.data_size
93 }
94}
95
96#[derive(Debug, Clone)]
101pub struct Atom {
102 pub header: AtomHeader,
103 pub data: Option<AtomData>,
104 pub children: Vec<Atom>,
105}
106
107#[bon]
108impl Atom {
109 #[builder]
110 pub fn new(
111 header: AtomHeader,
112 #[builder(into)] data: Option<AtomData>,
113 #[builder(default = Vec::new())] children: Vec<Atom>,
114 ) -> Self {
115 Self {
116 header,
117 data,
118 children,
119 }
120 }
121
122 pub fn children_flat_retain_mut<P>(&mut self, mut pred: P)
125 where
126 P: FnMut(&mut Atom) -> bool,
127 {
128 let mut current_level = vec![self];
129
130 while !current_level.is_empty() {
131 let mut next_level = Vec::new();
132
133 for atom in current_level {
134 atom.children.retain_mut(|child| pred(child));
136
137 for child in &mut atom.children {
139 next_level.push(child);
140 }
141 }
142
143 current_level = next_level;
144 }
145 }
146}
147
148impl SerializeAtom for Atom {
149 fn atom_type(&self) -> FourCC {
150 self.header.atom_type
151 }
152
153 fn into_body_bytes(self) -> Vec<u8> {
155 let mut children_bytes = Vec::new();
157 for child in self.children {
158 let mut child_bytes = child.into_bytes();
159 children_bytes.append(&mut child_bytes);
160 }
161
162 let mut body = self
163 .data
164 .map(SerializeAtom::into_body_bytes)
165 .unwrap_or_default();
166
167 body.append(&mut children_bytes);
168 body
169 }
170}
171
172macro_rules! define_atom_data {
173 ( $(#[$meta:meta])* $enum:ident { $( $pattern:pat => $variant:ident($struct:ident) ),+ $(,)? } $(,)? ) => {
174 $(#[$meta])*
175 pub enum $enum {
176 $( $variant($struct), )+
177 }
178
179 $(
180 impl From<$struct> for $enum {
181 fn from(atom: $struct) -> Self {
182 $enum::$variant(atom)
183 }
184 }
185 )+
186
187 impl ParseAtomData for $enum {
188 fn parse_atom_data(
189 atom_type: FourCC,
190 input: &[u8],
191 ) -> Result<Self, ParseError> {
192 match atom_type {
193 $($pattern => $struct::parse_atom_data(atom_type, input).map($enum::from), )+
194 }
195 }
196 }
197
198 impl SerializeAtom for $enum {
199 fn atom_type(&self) -> FourCC {
200 match self {
201 $( $enum::$variant(atom) => atom.atom_type(), )+
202 }
203 }
204
205 fn into_body_bytes(self) -> Vec<u8> {
206 match self {
207 $( $enum::$variant(atom) => atom.into_body_bytes(), )+
208 }
209 }
210 }
211 };
212}
213
214define_atom_data!(
215 #[derive(Debug, Clone)]
219 AtomData {
220 ftyp::FTYP => FileType(FileTypeAtom),
221 mvhd::MVHD => MovieHeader(MovieHeaderAtom),
222 mdhd::MDHD => MediaHeader(MediaHeaderAtom),
223 elst::ELST => EditList(EditListAtom),
224 hdlr::HDLR => HandlerReference(HandlerReferenceAtom),
225 smhd::SMHD => SoundMediaHeader(SoundMediaHeaderAtom),
226 gmin::GMIN => BaseMediaInfo(BaseMediaInfoAtom),
227 text::TEXT => TextMediaInfo(TextMediaInfoAtom),
228 ilst::ILST => ItemList(ItemListAtom),
229 tkhd::TKHD => TrackHeader(TrackHeaderAtom),
230 stsd::STSD => SampleDescriptionTable(SampleDescriptionTableAtom),
231 tref::TREF => TrackReference(TrackReferenceAtom),
232 dref::DREF => DataReference(DataReferenceAtom),
233 stsz::STSZ => SampleSize(SampleSizeAtom),
234 stco_co64::STCO | stco_co64::CO64 => ChunkOffset(ChunkOffsetAtom),
235 stts::STTS => TimeToSample(TimeToSampleAtom),
236 stsc::STSC => SampleToChunk(SampleToChunkAtom),
237 chpl::CHPL => ChapterList(ChapterListAtom),
238 free::FREE | free::SKIP => Free(FreeAtom),
239 _ => RawData(RawData),
240 },
241);