mp4_atom/moov/trak/mdia/
hdlr.rs1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5pub struct Hdlr {
6 pub handler: FourCC,
7 pub name: String,
8}
9
10impl Default for Hdlr {
11 fn default() -> Self {
12 Hdlr {
13 handler: FourCC::new(b"none"),
14 name: String::new(),
15 }
16 }
17}
18
19impl AtomExt for Hdlr {
20 type Ext = ();
21 const KIND_EXT: FourCC = FourCC::new(b"hdlr");
22
23 fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> {
24 u32::decode(buf)?; let handler = FourCC::decode(buf)?;
26
27 <[u8; 12]>::decode(buf)?; let name = String::decode(buf)?;
30
31 if buf.has_remaining() {
33 tracing::warn!("Skipped {} extra trailing bytes in hdlr", buf.remaining());
34 buf.advance(buf.remaining());
35 }
36
37 Ok(Hdlr { handler, name })
38 }
39
40 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> {
41 0u32.encode(buf)?; self.handler.encode(buf)?;
43
44 [0u8; 12].encode(buf)?;
46
47 self.name.as_str().encode(buf)?;
48
49 Ok(())
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn test_hdlr() {
59 let expected = Hdlr {
60 handler: FourCC::new(b"vide"),
61 name: String::from("VideoHandler"),
62 };
63 let mut buf = Vec::new();
64 expected.encode(&mut buf).unwrap();
65
66 let mut buf = buf.as_ref();
67 let decoded = Hdlr::decode(&mut buf).unwrap();
68 assert_eq!(decoded, expected);
69 }
70
71 #[test]
72 fn test_hdlr_empty() {
73 let expected = Hdlr {
74 handler: FourCC::new(b"vide"),
75 name: String::new(),
76 };
77 let mut buf = Vec::new();
78 expected.encode(&mut buf).unwrap();
79
80 let mut buf = buf.as_ref();
81 let decoded = Hdlr::decode(&mut buf).unwrap();
82 assert_eq!(decoded, expected);
83 }
84
85 #[test]
86 fn test_hdlr_with_trailing_bytes() {
87 let mut buf = Vec::new();
91
92 buf.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); buf.extend_from_slice(b"hdlr");
95
96 buf.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]);
98
99 buf.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]);
101
102 buf.extend_from_slice(b"vide");
104
105 buf.extend_from_slice(&[0x00; 12]);
107
108 buf.extend_from_slice(b"VideoHandler\0");
110
111 buf.extend_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD]); let size = buf.len() as u32;
116 buf[0..4].copy_from_slice(&size.to_be_bytes());
117
118 let mut cursor = std::io::Cursor::new(&buf);
120 let decoded = Hdlr::decode(&mut cursor).expect("failed to decode hdlr with trailing bytes");
121
122 assert_eq!(decoded.handler, FourCC::new(b"vide"));
124 assert_eq!(decoded.name, "VideoHandler");
125
126 assert_eq!(cursor.position(), buf.len() as u64);
128 }
129
130 #[test]
131 fn test_hdlr_with_multiple_trailing_nulls() {
132 let mut buf = Vec::new();
135
136 buf.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); buf.extend_from_slice(b"hdlr");
139
140 buf.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]);
142
143 buf.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]);
145
146 buf.extend_from_slice(b"soun");
148
149 buf.extend_from_slice(&[0x00; 12]);
151
152 buf.extend_from_slice(b"SoundHandler\0");
154
155 buf.extend_from_slice(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
157
158 let size = buf.len() as u32;
160 buf[0..4].copy_from_slice(&size.to_be_bytes());
161
162 let mut cursor = std::io::Cursor::new(&buf);
164 let decoded = Hdlr::decode(&mut cursor).expect("failed to decode hdlr with trailing nulls");
165
166 assert_eq!(decoded.handler, FourCC::new(b"soun"));
168 assert_eq!(decoded.name, "SoundHandler");
169 assert_eq!(cursor.position(), buf.len() as u64);
170 }
171
172 #[test]
173 fn test_hdlr_roundtrip_with_trailing_bytes() {
174 let original = Hdlr {
178 handler: FourCC::new(b"meta"),
179 name: "MetaHandler".to_string(),
180 };
181
182 let mut encoded = Vec::new();
184 original.encode(&mut encoded).unwrap();
185
186 let mut cursor = std::io::Cursor::new(&encoded);
188 let decoded = Hdlr::decode(&mut cursor).expect("failed to decode clean hdlr");
189 assert_eq!(decoded, original);
190
191 let box_end = cursor.position() as usize;
193 let mut encoded_with_trash = encoded[..box_end].to_vec();
194
195 encoded_with_trash.extend_from_slice(&[0xFF, 0xEE, 0xDD]);
197
198 let new_size = encoded_with_trash.len() as u32;
200 encoded_with_trash[0..4].copy_from_slice(&new_size.to_be_bytes());
201
202 let mut cursor2 = std::io::Cursor::new(&encoded_with_trash);
204 let decoded2 = Hdlr::decode(&mut cursor2).expect("failed to decode hdlr with added trash");
205 assert_eq!(decoded2, original);
206 assert_eq!(cursor2.position(), encoded_with_trash.len() as u64);
207 }
208}