1use serde::Serialize;
2use std::io::{Read, Seek, Write};
3
4use crate::mp4box::*;
5
6#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
7pub struct DinfBox {
8 dref: DrefBox,
9}
10
11impl DinfBox {
12 pub fn get_type(&self) -> BoxType {
13 BoxType::DinfBox
14 }
15
16 pub fn get_size(&self) -> u64 {
17 HEADER_SIZE + self.dref.box_size()
18 }
19}
20
21impl Mp4Box for DinfBox {
22 fn box_type(&self) -> BoxType {
23 self.get_type()
24 }
25
26 fn box_size(&self) -> u64 {
27 self.get_size()
28 }
29
30 fn to_json(&self) -> Result<String> {
31 Ok(serde_json::to_string(&self).unwrap())
32 }
33
34 fn summary(&self) -> Result<String> {
35 let s = String::new();
36 Ok(s)
37 }
38}
39
40impl<R: Read + Seek> ReadBox<&mut R> for DinfBox {
41 fn read_box(reader: &mut R, size: u64) -> Result<Self> {
42 let start = box_start(reader)?;
43
44 let mut dref = None;
45
46 let mut current = reader.stream_position()?;
47 let end = start + size;
48 while current < end {
49 let header = BoxHeader::read(reader)?;
51 let BoxHeader { name, size: s } = header;
52 if s > size {
53 return Err(Error::InvalidData(
54 "dinf box contains a box with a larger size than it",
55 ));
56 }
57
58 match name {
59 BoxType::DrefBox => {
60 dref = Some(DrefBox::read_box(reader, s)?);
61 }
62 _ => {
63 skip_box(reader, s)?;
65 }
66 }
67
68 current = reader.stream_position()?;
69 }
70
71 if dref.is_none() {
72 return Err(Error::BoxNotFound(BoxType::DrefBox));
73 }
74
75 skip_bytes_to(reader, start + size)?;
76
77 Ok(DinfBox {
78 dref: dref.unwrap(),
79 })
80 }
81}
82
83impl<W: Write> WriteBox<&mut W> for DinfBox {
84 fn write_box(&self, writer: &mut W) -> Result<u64> {
85 let size = self.box_size();
86 BoxHeader::new(self.box_type(), size).write(writer)?;
87 self.dref.write_box(writer)?;
88 Ok(size)
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
93pub struct DrefBox {
94 pub version: u8,
95 pub flags: u32,
96
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub url: Option<UrlBox>,
99}
100
101impl Default for DrefBox {
102 fn default() -> Self {
103 DrefBox {
104 version: 0,
105 flags: 0,
106 url: Some(UrlBox::default()),
107 }
108 }
109}
110
111impl DrefBox {
112 pub fn get_type(&self) -> BoxType {
113 BoxType::DrefBox
114 }
115
116 pub fn get_size(&self) -> u64 {
117 let mut size = HEADER_SIZE + HEADER_EXT_SIZE + 4;
118 if let Some(ref url) = self.url {
119 size += url.box_size();
120 }
121 size
122 }
123}
124
125impl Mp4Box for DrefBox {
126 fn box_type(&self) -> BoxType {
127 self.get_type()
128 }
129
130 fn box_size(&self) -> u64 {
131 self.get_size()
132 }
133
134 fn to_json(&self) -> Result<String> {
135 Ok(serde_json::to_string(&self).unwrap())
136 }
137
138 fn summary(&self) -> Result<String> {
139 let s = String::new();
140 Ok(s)
141 }
142}
143
144impl<R: Read + Seek> ReadBox<&mut R> for DrefBox {
145 fn read_box(reader: &mut R, size: u64) -> Result<Self> {
146 let start = box_start(reader)?;
147
148 let mut current = reader.stream_position()?;
149
150 let (version, flags) = read_box_header_ext(reader)?;
151 let end = start + size;
152
153 let mut url = None;
154
155 let entry_count = reader.read_u32::<BigEndian>()?;
156 for _i in 0..entry_count {
157 if current >= end {
158 break;
159 }
160
161 let header = BoxHeader::read(reader)?;
163 let BoxHeader { name, size: s } = header;
164 if s > size {
165 return Err(Error::InvalidData(
166 "dinf box contains a box with a larger size than it",
167 ));
168 }
169
170 match name {
171 BoxType::UrlBox => {
172 url = Some(UrlBox::read_box(reader, s)?);
173 }
174 _ => {
175 skip_box(reader, s)?;
176 }
177 }
178
179 current = reader.stream_position()?;
180 }
181
182 skip_bytes_to(reader, start + size)?;
183
184 Ok(DrefBox {
185 version,
186 flags,
187 url,
188 })
189 }
190}
191
192impl<W: Write> WriteBox<&mut W> for DrefBox {
193 fn write_box(&self, writer: &mut W) -> Result<u64> {
194 let size = self.box_size();
195 BoxHeader::new(self.box_type(), size).write(writer)?;
196
197 write_box_header_ext(writer, self.version, self.flags)?;
198
199 writer.write_u32::<BigEndian>(1)?;
200
201 if let Some(ref url) = self.url {
202 url.write_box(writer)?;
203 }
204
205 Ok(size)
206 }
207}
208
209#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
210pub struct UrlBox {
211 pub version: u8,
212 pub flags: u32,
213 pub location: String,
214}
215
216impl Default for UrlBox {
217 fn default() -> Self {
218 UrlBox {
219 version: 0,
220 flags: 1,
221 location: String::default(),
222 }
223 }
224}
225
226impl UrlBox {
227 pub fn get_type(&self) -> BoxType {
228 BoxType::UrlBox
229 }
230
231 pub fn get_size(&self) -> u64 {
232 let mut size = HEADER_SIZE + HEADER_EXT_SIZE;
233
234 if !self.location.is_empty() {
235 size += self.location.bytes().len() as u64 + 1;
236 }
237
238 size
239 }
240}
241
242impl Mp4Box for UrlBox {
243 fn box_type(&self) -> BoxType {
244 self.get_type()
245 }
246
247 fn box_size(&self) -> u64 {
248 self.get_size()
249 }
250
251 fn to_json(&self) -> Result<String> {
252 Ok(serde_json::to_string(&self).unwrap())
253 }
254
255 fn summary(&self) -> Result<String> {
256 let s = format!("location={}", self.location);
257 Ok(s)
258 }
259}
260
261impl<R: Read + Seek> ReadBox<&mut R> for UrlBox {
262 fn read_box(reader: &mut R, size: u64) -> Result<Self> {
263 let start = box_start(reader)?;
264
265 let (version, flags) = read_box_header_ext(reader)?;
266
267 let buf_size = size
268 .checked_sub(HEADER_SIZE + HEADER_EXT_SIZE)
269 .ok_or(Error::InvalidData("url size too small"))?;
270
271 let mut buf = vec![0u8; buf_size as usize];
272 reader.read_exact(&mut buf)?;
273 if let Some(end) = buf.iter().position(|&b| b == b'\0') {
274 buf.truncate(end);
275 }
276 let location = String::from_utf8(buf).unwrap_or_default();
277
278 skip_bytes_to(reader, start + size)?;
279
280 Ok(UrlBox {
281 version,
282 flags,
283 location,
284 })
285 }
286}
287
288impl<W: Write> WriteBox<&mut W> for UrlBox {
289 fn write_box(&self, writer: &mut W) -> Result<u64> {
290 let size = self.box_size();
291 BoxHeader::new(self.box_type(), size).write(writer)?;
292
293 write_box_header_ext(writer, self.version, self.flags)?;
294
295 if !self.location.is_empty() {
296 writer.write_all(self.location.as_bytes())?;
297 writer.write_u8(0)?;
298 }
299
300 Ok(size)
301 }
302}