1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use serde::Serialize;
3use std::io::{Read, Seek, Write};
4
5use crate::mp4box::*;
6
7#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
8pub struct HdlrBox {
9 pub version: u8,
10 pub flags: u32,
11 pub handler_type: FourCC,
12 pub name: String,
13}
14
15impl HdlrBox {
16 pub fn get_type(&self) -> BoxType {
17 BoxType::HdlrBox
18 }
19
20 pub fn get_size(&self) -> u64 {
21 HEADER_SIZE + HEADER_EXT_SIZE + 20 + self.name.len() as u64 + 1
22 }
23}
24
25impl Mp4Box for HdlrBox {
26 fn box_type(&self) -> BoxType {
27 self.get_type()
28 }
29
30 fn box_size(&self) -> u64 {
31 self.get_size()
32 }
33
34 fn to_json(&self) -> Result<String> {
35 Ok(serde_json::to_string(&self).unwrap())
36 }
37
38 fn summary(&self) -> Result<String> {
39 let s = format!("handler_type={} name={}", self.handler_type, self.name);
40 Ok(s)
41 }
42}
43
44impl<R: Read + Seek> ReadBox<&mut R> for HdlrBox {
45 fn read_box(reader: &mut R, size: u64) -> Result<Self> {
46 let start = box_start(reader)?;
47
48 let (version, flags) = read_box_header_ext(reader)?;
49
50 reader.read_u32::<BigEndian>()?; let handler = reader.read_u32::<BigEndian>()?;
52
53 skip_bytes(reader, 12)?; let buf_size = size
56 .checked_sub(HEADER_SIZE + HEADER_EXT_SIZE + 20)
57 .ok_or(Error::InvalidData("hdlr size too small"))?;
58
59 let mut buf = vec![0u8; buf_size as usize];
60 reader.read_exact(&mut buf)?;
61 if let Some(end) = buf.iter().position(|&b| b == b'\0') {
62 buf.truncate(end);
63 }
64 let handler_string = String::from_utf8(buf).unwrap_or_default();
65
66 skip_bytes_to(reader, start + size)?;
67
68 Ok(HdlrBox {
69 version,
70 flags,
71 handler_type: From::from(handler),
72 name: handler_string,
73 })
74 }
75}
76
77impl<W: Write> WriteBox<&mut W> for HdlrBox {
78 fn write_box(&self, writer: &mut W) -> Result<u64> {
79 let size = self.box_size();
80 BoxHeader::new(self.box_type(), size).write(writer)?;
81
82 write_box_header_ext(writer, self.version, self.flags)?;
83
84 writer.write_u32::<BigEndian>(0)?; writer.write_u32::<BigEndian>((&self.handler_type).into())?;
86
87 for _ in 0..3 {
89 writer.write_u32::<BigEndian>(0)?;
90 }
91
92 writer.write_all(self.name.as_bytes())?;
93 writer.write_u8(0)?;
94
95 Ok(size)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::mp4box::BoxHeader;
103 use std::io::Cursor;
104
105 #[test]
106 fn test_hdlr() {
107 let src_box = HdlrBox {
108 version: 0,
109 flags: 0,
110 handler_type: str::parse::<FourCC>("vide").unwrap(),
111 name: String::from("VideoHandler"),
112 };
113 let mut buf = Vec::new();
114 src_box.write_box(&mut buf).unwrap();
115 assert_eq!(buf.len(), src_box.box_size() as usize);
116
117 let mut reader = Cursor::new(&buf);
118 let header = BoxHeader::read(&mut reader).unwrap();
119 assert_eq!(header.name, BoxType::HdlrBox);
120 assert_eq!(src_box.box_size(), header.size);
121
122 let dst_box = HdlrBox::read_box(&mut reader, header.size).unwrap();
123 assert_eq!(src_box, dst_box);
124 }
125
126 #[test]
127 fn test_hdlr_empty() {
128 let src_box = HdlrBox {
129 version: 0,
130 flags: 0,
131 handler_type: str::parse::<FourCC>("vide").unwrap(),
132 name: String::new(),
133 };
134 let mut buf = Vec::new();
135 src_box.write_box(&mut buf).unwrap();
136 assert_eq!(buf.len(), src_box.box_size() as usize);
137
138 let mut reader = Cursor::new(&buf);
139 let header = BoxHeader::read(&mut reader).unwrap();
140 assert_eq!(header.name, BoxType::HdlrBox);
141 assert_eq!(src_box.box_size(), header.size);
142
143 let dst_box = HdlrBox::read_box(&mut reader, header.size).unwrap();
144 assert_eq!(src_box, dst_box);
145 }
146
147 #[test]
148 fn test_hdlr_extra() {
149 let real_src_box = HdlrBox {
150 version: 0,
151 flags: 0,
152 handler_type: str::parse::<FourCC>("vide").unwrap(),
153 name: String::from("Good"),
154 };
155 let src_box = HdlrBox {
156 version: 0,
157 flags: 0,
158 handler_type: str::parse::<FourCC>("vide").unwrap(),
159 name: String::from_utf8(b"Good\0Bad".to_vec()).unwrap(),
160 };
161 let mut buf = Vec::new();
162 src_box.write_box(&mut buf).unwrap();
163 assert_eq!(buf.len(), src_box.box_size() as usize);
164
165 let mut reader = Cursor::new(&buf);
166 let header = BoxHeader::read(&mut reader).unwrap();
167 assert_eq!(header.name, BoxType::HdlrBox);
168 assert_eq!(src_box.box_size(), header.size);
169
170 let dst_box = HdlrBox::read_box(&mut reader, header.size).unwrap();
171 assert_eq!(real_src_box, dst_box);
172 }
173}