ttf_parser/tables/cff/
index.rs

1use crate::parser::{FromData, NumFrom, Stream, U24};
2
3pub trait IndexSize: FromData {
4    fn to_u32(self) -> u32;
5}
6
7impl IndexSize for u16 {
8    fn to_u32(self) -> u32 {
9        u32::from(self)
10    }
11}
12
13impl IndexSize for u32 {
14    fn to_u32(self) -> u32 {
15        self
16    }
17}
18
19#[inline]
20pub fn parse_index<'a, T: IndexSize>(s: &mut Stream<'a>) -> Option<Index<'a>> {
21    let count = s.read::<T>()?;
22    parse_index_impl(count.to_u32(), s)
23}
24
25#[inline(never)]
26fn parse_index_impl<'a>(count: u32, s: &mut Stream<'a>) -> Option<Index<'a>> {
27    if count == 0 || count == u32::MAX {
28        return Some(Index::default());
29    }
30
31    let offset_size = s.read::<OffsetSize>()?;
32    let offsets_len = (count + 1).checked_mul(offset_size.to_u32())?;
33    let offsets = VarOffsets {
34        data: s.read_bytes(usize::num_from(offsets_len))?,
35        offset_size,
36    };
37
38    // Last offset indicates a Data Index size.
39    match offsets.last() {
40        Some(last_offset) => {
41            let data = s.read_bytes(usize::num_from(last_offset))?;
42            Some(Index { data, offsets })
43        }
44        None => Some(Index::default()),
45    }
46}
47
48#[inline]
49pub fn skip_index<T: IndexSize>(s: &mut Stream) -> Option<()> {
50    let count = s.read::<T>()?;
51    skip_index_impl(count.to_u32(), s)
52}
53
54#[inline(never)]
55fn skip_index_impl(count: u32, s: &mut Stream) -> Option<()> {
56    if count == 0 || count == u32::MAX {
57        return Some(());
58    }
59
60    let offset_size = s.read::<OffsetSize>()?;
61    let offsets_len = (count + 1).checked_mul(offset_size.to_u32())?;
62    let offsets = VarOffsets {
63        data: s.read_bytes(usize::num_from(offsets_len))?,
64        offset_size,
65    };
66
67    if let Some(last_offset) = offsets.last() {
68        s.advance(usize::num_from(last_offset));
69    }
70
71    Some(())
72}
73
74#[derive(Clone, Copy, Debug)]
75pub struct VarOffsets<'a> {
76    pub data: &'a [u8],
77    pub offset_size: OffsetSize,
78}
79
80impl<'a> VarOffsets<'a> {
81    pub fn get(&self, index: u32) -> Option<u32> {
82        if index >= self.len() {
83            return None;
84        }
85
86        let start = usize::num_from(index) * self.offset_size.to_usize();
87        let mut s = Stream::new_at(self.data, start)?;
88        let n: u32 = match self.offset_size {
89            OffsetSize::Size1 => u32::from(s.read::<u8>()?),
90            OffsetSize::Size2 => u32::from(s.read::<u16>()?),
91            OffsetSize::Size3 => s.read::<U24>()?.0,
92            OffsetSize::Size4 => s.read::<u32>()?,
93        };
94
95        // Offsets are offset by one byte in the font,
96        // so we have to shift them back.
97        n.checked_sub(1)
98    }
99
100    #[inline]
101    pub fn last(&self) -> Option<u32> {
102        if !self.is_empty() {
103            self.get(self.len() - 1)
104        } else {
105            None
106        }
107    }
108
109    #[inline]
110    pub fn len(&self) -> u32 {
111        self.data.len() as u32 / self.offset_size as u32
112    }
113
114    #[inline]
115    pub fn is_empty(&self) -> bool {
116        self.len() == 0
117    }
118}
119
120#[derive(Clone, Copy, Debug)]
121pub struct Index<'a> {
122    pub data: &'a [u8],
123    pub offsets: VarOffsets<'a>,
124}
125
126impl<'a> Default for Index<'a> {
127    #[inline]
128    fn default() -> Self {
129        Index {
130            data: b"",
131            offsets: VarOffsets {
132                data: b"",
133                offset_size: OffsetSize::Size1,
134            },
135        }
136    }
137}
138
139impl<'a> IntoIterator for Index<'a> {
140    type Item = &'a [u8];
141    type IntoIter = IndexIter<'a>;
142
143    #[inline]
144    fn into_iter(self) -> Self::IntoIter {
145        IndexIter {
146            data: self,
147            offset_index: 0,
148        }
149    }
150}
151
152impl<'a> Index<'a> {
153    #[inline]
154    pub fn len(&self) -> u32 {
155        // Last offset points to the byte after the `Object data`. We should skip it.
156        self.offsets.len().saturating_sub(1)
157    }
158
159    pub fn get(&self, index: u32) -> Option<&'a [u8]> {
160        let next_index = index.checked_add(1)?; // make sure we do not overflow
161        let start = usize::num_from(self.offsets.get(index)?);
162        let end = usize::num_from(self.offsets.get(next_index)?);
163        self.data.get(start..end)
164    }
165}
166
167pub struct IndexIter<'a> {
168    data: Index<'a>,
169    offset_index: u32,
170}
171
172impl<'a> Iterator for IndexIter<'a> {
173    type Item = &'a [u8];
174
175    #[inline]
176    fn next(&mut self) -> Option<Self::Item> {
177        if self.offset_index == self.data.len() {
178            return None;
179        }
180
181        let index = self.offset_index;
182        self.offset_index += 1;
183        self.data.get(index)
184    }
185}
186
187#[derive(Clone, Copy, PartialEq, Eq, Debug)]
188pub enum OffsetSize {
189    Size1 = 1,
190    Size2 = 2,
191    Size3 = 3,
192    Size4 = 4,
193}
194
195impl OffsetSize {
196    #[inline]
197    pub fn to_u32(self) -> u32 {
198        self as u32
199    }
200    #[inline]
201    pub fn to_usize(self) -> usize {
202        self as usize
203    }
204}
205
206impl FromData for OffsetSize {
207    const SIZE: usize = 1;
208
209    #[inline]
210    fn parse(data: &[u8]) -> Option<Self> {
211        match data.get(0)? {
212            1 => Some(OffsetSize::Size1),
213            2 => Some(OffsetSize::Size2),
214            3 => Some(OffsetSize::Size3),
215            4 => Some(OffsetSize::Size4),
216            _ => None,
217        }
218    }
219}
220
221#[cfg(test)]
222mod tests {
223    use super::*;
224
225    #[test]
226    fn parse_offset_size() {
227        assert_eq!(core::mem::size_of::<OffsetSize>(), 1);
228
229        assert_eq!(Stream::new(&[0x00]).read::<OffsetSize>(), None);
230        assert_eq!(
231            Stream::new(&[0x01]).read::<OffsetSize>(),
232            Some(OffsetSize::Size1)
233        );
234        assert_eq!(Stream::new(&[0x05]).read::<OffsetSize>(), None);
235    }
236}