Skip to main content

mp4_atom/
coding.rs

1use std::ffi;
2
3use crate::*;
4
5/// Decode a type from a buffer.
6pub trait Decode: Sized {
7    /// Decode the type from the buffer.
8    fn decode<B: Buf>(buf: &mut B) -> Result<Self>;
9
10    /// Helper: Decode exactly size bytes from the buffer.
11    fn decode_exact<B: Buf>(buf: &mut B, size: usize) -> Result<Self> {
12        if buf.remaining() < size {
13            return Err(Error::OutOfBounds);
14        }
15
16        let mut inner = buf.slice(size);
17        let res = Self::decode(&mut inner)?;
18
19        if inner.has_remaining() {
20            return Err(Error::ShortRead);
21        }
22
23        buf.advance(size);
24
25        Ok(res)
26    }
27}
28
29/// Decode a type from a buffer if we have enough data.
30pub trait DecodeMaybe: Sized {
31    fn decode_maybe<B: Buf>(buf: &mut B) -> Result<Option<Self>>;
32}
33
34/// Decode an atom using the provided header
35pub trait DecodeAtom: Sized {
36    fn decode_atom<B: Buf>(header: &Header, buf: &mut B) -> Result<Self>;
37}
38
39/// Encode a type to a buffer.
40//
41// Why not BufMut?
42// Well it's because we need to write the size of each atom.
43// If we use BufMut, we can't seek backwards so we have to calculate it upfront.
44// If we use BufMut or Vec, then we can write 0 for the size, then write the atom, then go back and fix the size.
45pub trait Encode {
46    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()>;
47
48    #[cfg(test)]
49    fn assert_encode_decode(&self)
50    where
51        Self: std::fmt::Debug + PartialEq + Decode,
52    {
53        let mut buf = Vec::new();
54        Self::encode(self, &mut buf).unwrap();
55
56        let mut cursor = std::io::Cursor::new(&buf);
57        let decoded = Self::decode(&mut cursor).unwrap();
58
59        assert_eq!(self, &decoded, "different decoded result");
60    }
61}
62
63impl Decode for u8 {
64    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
65        Ok(Self::from_be_bytes(<[u8; 1]>::decode(buf)?))
66    }
67}
68
69impl Decode for i8 {
70    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
71        Ok(Self::from_be_bytes(<[u8; 1]>::decode(buf)?))
72    }
73}
74
75impl Decode for u16 {
76    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
77        Ok(Self::from_be_bytes(<[u8; 2]>::decode(buf)?))
78    }
79}
80
81impl Decode for i16 {
82    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
83        Ok(Self::from_be_bytes(<[u8; 2]>::decode(buf)?))
84    }
85}
86
87impl Decode for u32 {
88    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
89        Ok(Self::from_be_bytes(<[u8; 4]>::decode(buf)?))
90    }
91}
92
93impl Decode for i32 {
94    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
95        Ok(Self::from_be_bytes(<[u8; 4]>::decode(buf)?))
96    }
97}
98
99impl Decode for u64 {
100    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
101        Ok(Self::from_be_bytes(<[u8; 8]>::decode(buf)?))
102    }
103}
104
105impl Decode for i64 {
106    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
107        Ok(Self::from_be_bytes(<[u8; 8]>::decode(buf)?))
108    }
109}
110
111impl<const N: usize> Decode for [u8; N] {
112    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
113        if buf.remaining() < N {
114            return Err(Error::OutOfBounds);
115        }
116
117        let mut v = [0u8; N];
118        v.copy_from_slice(buf.slice(N));
119        buf.advance(N);
120
121        Ok(v)
122    }
123}
124
125impl<T: Decode> Decode for Vec<T> {
126    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
127        let mut vec = Vec::new();
128        while buf.has_remaining() {
129            let item = T::decode(buf)?;
130            vec.push(item);
131        }
132
133        Ok(vec)
134    }
135}
136
137impl Decode for String {
138    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
139        let mut bytes = Vec::new();
140        while buf.has_remaining() {
141            let byte = u8::decode(buf)?;
142            if byte == 0 {
143                break;
144            }
145
146            bytes.push(byte);
147        }
148
149        let str = ffi::CString::new(bytes).map_err(|err| Error::InvalidString(err.to_string()))?;
150        str.into_string()
151            .map_err(|err| Error::InvalidString(err.to_string()))
152    }
153}
154
155impl Encode for u8 {
156    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
157        self.to_be_bytes().encode(buf)
158    }
159}
160
161impl Encode for i8 {
162    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
163        self.to_be_bytes().encode(buf)
164    }
165}
166
167impl Encode for i16 {
168    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
169        self.to_be_bytes().encode(buf)
170    }
171}
172
173impl Encode for u16 {
174    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
175        self.to_be_bytes().encode(buf)
176    }
177}
178
179impl Encode for u32 {
180    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
181        self.to_be_bytes().encode(buf)
182    }
183}
184
185impl Encode for i32 {
186    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
187        self.to_be_bytes().encode(buf)
188    }
189}
190
191impl Encode for u64 {
192    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
193        self.to_be_bytes().encode(buf)
194    }
195}
196
197impl Encode for i64 {
198    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
199        self.to_be_bytes().encode(buf)
200    }
201}
202
203impl<const N: usize> Encode for [u8; N] {
204    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
205        buf.append_slice(self);
206        Ok(())
207    }
208}
209
210impl<T: Encode> Encode for &[T] {
211    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
212        for item in self.iter() {
213            item.encode(buf)?;
214        }
215
216        Ok(())
217    }
218}
219
220impl<T: Encode> Encode for Option<T> {
221    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
222        match self {
223            Some(v) => v.encode(buf),
224            None => Ok(()),
225        }
226    }
227}
228
229impl Encode for &str {
230    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
231        self.as_bytes().encode(buf)?;
232        0u8.encode(buf)?;
233        Ok(())
234    }
235}
236
237impl<T: Encode> Encode for Vec<T> {
238    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
239        for item in self.iter() {
240            item.encode(buf)?;
241        }
242
243        Ok(())
244    }
245}
246
247/// Decode a UTF-8 string preceded by its length in bytes, stored as `T`.
248pub(crate) fn decode_length_prefixed_utf8_string<T: Decode + Into<usize>>(
249    buf: &mut impl Buf,
250) -> Result<String> {
251    let len = T::decode(buf)?;
252    decode_utf8_string_with_length(buf, len.into())
253}
254
255/// Decode a UTF-8 string filling the rest of the buffer.
256pub(crate) fn decode_utf8_string(buf: &mut impl Buf) -> Result<String> {
257    decode_utf8_string_with_length(buf, buf.remaining())
258}
259
260/// Decode a UTF-8 string of `len` bytes.
261pub(crate) fn decode_utf8_string_with_length(buf: &mut impl Buf, len: usize) -> Result<String> {
262    if len > buf.remaining() {
263        return Err(Error::OutOfBounds);
264    }
265
266    let text = String::from_utf8(buf.slice(len).to_vec())
267        .map_err(|err| Error::InvalidString(err.to_string()))?;
268
269    buf.advance(len);
270    Ok(text)
271}
272
273/// Encode a UTF-8 string preceded by its length in bytes, stored as `T`. `kind`
274/// is only used to report a string whose length doesn't fit in `T`.
275pub(crate) fn encode_length_prefixed_string<T: Encode + TryFrom<usize>>(
276    buf: &mut impl BufMut,
277    text: &str,
278    kind: FourCC,
279) -> Result<()> {
280    let len: T = text.len().try_into().map_err(|_| Error::TooLarge(kind))?;
281    len.encode(buf)?;
282    buf.append_slice(text.as_bytes());
283    Ok(())
284}
285
286/// Decode a string preceded by its length in bytes, stored as `T`, see
287/// [`decode_bom_string_with_length`].
288pub(crate) fn decode_length_prefixed_bom_string<T: Decode + Into<usize>>(
289    buf: &mut impl Buf,
290) -> Result<String> {
291    let len = T::decode(buf)?;
292    decode_bom_string_with_length(buf, len.into())
293}
294
295/// Decode `len` bytes of text that is UTF-8, or UTF-16 (either byte order) if
296/// it starts with a byte order mark, as used by 3GPP timed text.
297pub(crate) fn decode_bom_string_with_length(buf: &mut impl Buf, len: usize) -> Result<String> {
298    if len > buf.remaining() {
299        return Err(Error::OutOfBounds);
300    }
301
302    let bytes = buf.slice(len);
303    let text = match bytes {
304        [0xFE, 0xFF, rest @ ..] => decode_utf16_units(rest, u16::from_be_bytes),
305        [0xFF, 0xFE, rest @ ..] => decode_utf16_units(rest, u16::from_le_bytes),
306        _ => String::from_utf8(bytes.to_vec()).map_err(|err| err.to_string()),
307    }
308    .map_err(Error::InvalidString)?;
309
310    buf.advance(len);
311    Ok(text)
312}
313
314fn decode_utf16_units(
315    bytes: &[u8],
316    from_bytes: fn([u8; 2]) -> u16,
317) -> std::result::Result<String, String> {
318    let (pairs, rest) = bytes.as_chunks::<2>();
319
320    if !rest.is_empty() {
321        return Err("UTF-16 payload has an odd byte length".to_string());
322    }
323
324    let units: Vec<u16> = pairs.iter().cloned().map(from_bytes).collect();
325    String::from_utf16(&units).map_err(|err| err.to_string())
326}
327
328#[cfg(test)]
329mod string_helper_tests {
330    use super::*;
331
332    #[test]
333    fn test_length_prefixed_string_roundtrip() {
334        let mut buf = Vec::new();
335        encode_length_prefixed_string::<u8>(&mut buf, "héllo", FourCC::new(b"test")).unwrap();
336        assert_eq!(buf[0] as usize, "héllo".len());
337
338        let mut slice = buf.as_slice();
339        assert_eq!(
340            decode_length_prefixed_utf8_string::<u8>(&mut slice).unwrap(),
341            "héllo"
342        );
343        assert!(slice.is_empty());
344    }
345
346    #[test]
347    fn test_length_prefixed_string_errors() {
348        let too_long = "a".repeat(256);
349        let err =
350            encode_length_prefixed_string::<u8>(&mut Vec::new(), &too_long, FourCC::new(b"test"));
351        assert!(matches!(err, Err(Error::TooLarge(_))));
352
353        // Declared length exceeds the remaining bytes.
354        let err = decode_length_prefixed_utf8_string::<u8>(&mut [5u8, b'a'].as_slice());
355        assert!(matches!(err, Err(Error::OutOfBounds)));
356    }
357
358    #[test]
359    fn test_bom_string() {
360        let mut utf8 = b"Hi".as_slice();
361        assert_eq!(decode_bom_string_with_length(&mut utf8, 2).unwrap(), "Hi");
362        assert!(utf8.is_empty());
363
364        let be = [0xFE, 0xFF, 0, b'H', 0, b'i'];
365        assert_eq!(
366            decode_bom_string_with_length(&mut be.as_slice(), 6).unwrap(),
367            "Hi"
368        );
369
370        let le = [0xFF, 0xFE, b'H', 0, b'i', 0];
371        assert_eq!(
372            decode_bom_string_with_length(&mut le.as_slice(), 6).unwrap(),
373            "Hi"
374        );
375    }
376
377    #[test]
378    fn test_bom_string_errors() {
379        // Longer than the buffer.
380        let err = decode_bom_string_with_length(&mut b"Hi".as_slice(), 3);
381        assert!(matches!(err, Err(Error::OutOfBounds)));
382
383        // Odd UTF-16 payload, and the buffer is left untouched on failure.
384        let odd = [0xFE, 0xFF, 0, b'H', 0];
385        let mut slice = odd.as_slice();
386        assert!(matches!(
387            decode_bom_string_with_length(&mut slice, 5),
388            Err(Error::InvalidString(_))
389        ));
390        assert_eq!(slice.len(), 5);
391    }
392}