mp4_atom/moov/trak/mdia/minf/stbl/stsd/
ftab.rs1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Eq, Default)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct FontEntry {
11 pub font_id: u16,
12 pub font: String,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq, Default)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct Ftab {
18 pub font_entries: Vec<FontEntry>,
19}
20
21impl Atom for Ftab {
22 const KIND: FourCC = FourCC::new(b"ftab");
23
24 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
25 let entry_count = u16::decode(buf)?;
26 let mut font_entries = Vec::with_capacity(std::cmp::min(8, entry_count as usize));
27 for _ in 0..entry_count {
28 let font_id = u16::decode(buf)?;
29 let font = decode_length_prefixed_bom_string::<u8>(buf)?;
30 let font_entry = FontEntry { font_id, font };
31 font_entries.push(font_entry);
32 }
33 Ok(Ftab { font_entries })
34 }
35
36 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
37 let entry_count: u16 = self
38 .font_entries
39 .len()
40 .try_into()
41 .map_err(|_| Error::TooLarge(Self::KIND))?;
42 entry_count.encode(buf)?;
43 for font_entry in &self.font_entries {
44 font_entry.font_id.encode(buf)?;
45 encode_length_prefixed_string::<u8>(buf, &font_entry.font, Self::KIND)?;
47 }
48
49 Ok(())
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn test_ftab_utf16_font_names_decode_as_utf8_on_encode() {
59 let utf16le = [b"\xFF\xFE".as_slice(), b"S\0e\0r\0i\0f\0"].concat();
60 let utf16be = [b"\xFE\xFF".as_slice(), b"\0S\0a\0n\0s"].concat();
61
62 let mut body = vec![0, 2];
63 for (id, name) in [(1u8, &utf16le), (2, &utf16be)] {
64 body.extend([0, id, name.len() as u8]);
65 body.extend(name);
66 }
67
68 let ftab = Ftab::decode_body(&mut body.as_slice()).unwrap();
69 assert_eq!(
70 ftab.font_entries,
71 vec![
72 FontEntry {
73 font_id: 1,
74 font: "Serif".into()
75 },
76 FontEntry {
77 font_id: 2,
78 font: "Sans".into()
79 },
80 ]
81 );
82
83 let mut encoded = Vec::new();
85 ftab.encode_body(&mut encoded).unwrap();
86 assert_eq!(encoded, b"\0\x02\0\x01\x05Serif\0\x02\x04Sans");
87 }
88
89 #[test]
90 fn test_ftab_font_name_exceeds_buffer() {
91 let err = Ftab::decode_body(&mut [0, 1, 0, 1, 9, b'a'].as_slice()).unwrap_err();
92 assert!(matches!(err, Error::OutOfBounds));
93 }
94}