read_fonts/tables/postscript/
index.rs1use super::{Error, Index1, Index2};
6use crate::codegen_prelude::*;
7
8#[derive(Clone)]
10pub enum Index<'a> {
11 Empty,
12 Format1(Index1<'a>),
13 Format2(Index2<'a>),
14}
15
16impl<'a> Index<'a> {
17 pub fn new(data: &'a [u8], is_cff2: bool) -> Result<Self, Error> {
21 let data = FontData::new(data);
22 Ok(if is_cff2 {
23 Index2::read(data).map(|ix| ix.into())?
24 } else {
25 Index1::read(data).map(|ix| ix.into())?
26 })
27 }
28
29 pub fn count(&self) -> u32 {
31 match self {
32 Self::Empty => 0,
33 Self::Format1(ix) => ix.count() as u32,
34 Self::Format2(ix) => ix.count(),
35 }
36 }
37
38 pub fn subr_bias(&self) -> i32 {
43 let count = self.count();
44 if count < 1240 {
45 107
46 } else if count < 33900 {
47 1131
48 } else {
49 32768
50 }
51 }
52
53 pub fn size_in_bytes(&self) -> Result<usize, ReadError> {
55 match self {
56 Self::Empty => Ok(0),
57 Self::Format1(ix) => ix.size_in_bytes(),
58 Self::Format2(ix) => ix.size_in_bytes(),
59 }
60 }
61
62 pub fn get_offset(&self, index: usize) -> Result<usize, Error> {
64 match self {
65 Self::Empty => Err(ReadError::OutOfBounds.into()),
66 Self::Format1(ix) => ix.get_offset(index),
67 Self::Format2(ix) => ix.get_offset(index),
68 }
69 }
70
71 pub fn get(&self, index: usize) -> Result<&'a [u8], Error> {
73 match self {
74 Self::Empty => Err(ReadError::OutOfBounds.into()),
75 Self::Format1(ix) => ix.get(index),
76 Self::Format2(ix) => ix.get(index),
77 }
78 }
79}
80
81impl<'a> From<Index1<'a>> for Index<'a> {
82 fn from(value: Index1<'a>) -> Self {
83 Self::Format1(value)
84 }
85}
86
87impl<'a> From<Index2<'a>> for Index<'a> {
88 fn from(value: Index2<'a>) -> Self {
89 Self::Format2(value)
90 }
91}
92
93impl Default for Index<'_> {
94 fn default() -> Self {
95 Self::Empty
96 }
97}
98
99impl<'a> Index1<'a> {
100 pub fn size_in_bytes(&self) -> Result<usize, ReadError> {
102 const HEADER_SIZE: usize = 3;
104 const EMPTY_SIZE: usize = 2;
106 let count = self.count() as usize;
107 Ok(match count {
108 0 => EMPTY_SIZE,
109 _ => {
110 HEADER_SIZE
111 + self.offsets().len()
112 + self.get_offset(count).map_err(|_| ReadError::OutOfBounds)?
113 }
114 })
115 }
116
117 pub fn get_offset(&self, index: usize) -> Result<usize, Error> {
119 read_offset(
120 index,
121 self.count() as usize,
122 self.off_size(),
123 self.offsets(),
124 )
125 }
126
127 pub fn get(&self, index: usize) -> Result<&'a [u8], Error> {
129 self.data()
130 .get(self.get_offset(index)?..self.get_offset(index + 1)?)
131 .ok_or(ReadError::OutOfBounds.into())
132 }
133}
134
135impl<'a> Index2<'a> {
136 pub fn size_in_bytes(&self) -> Result<usize, ReadError> {
138 const HEADER_SIZE: usize = 5;
140 const EMPTY_SIZE: usize = 4;
142 let count = self.count() as usize;
143 Ok(match count {
144 0 => EMPTY_SIZE,
145 _ => {
146 HEADER_SIZE
147 + self.offsets().len()
148 + self.get_offset(count).map_err(|_| ReadError::OutOfBounds)?
149 }
150 })
151 }
152
153 pub fn get_offset(&self, index: usize) -> Result<usize, Error> {
155 read_offset(
156 index,
157 self.count() as usize,
158 self.off_size(),
159 self.offsets(),
160 )
161 }
162
163 pub fn get(&self, index: usize) -> Result<&'a [u8], Error> {
165 self.data()
166 .get(self.get_offset(index)?..self.get_offset(index + 1)?)
167 .ok_or(ReadError::OutOfBounds.into())
168 }
169}
170
171fn read_offset(
173 index: usize,
174 count: usize,
175 offset_size: u8,
176 offset_data: &[u8],
177) -> Result<usize, Error> {
178 if index > count {
188 Err(ReadError::OutOfBounds)?;
189 }
190 let data_offset = index * offset_size as usize;
191 let offset_data = FontData::new(offset_data);
192 match offset_size {
193 1 => offset_data.read_at::<u8>(data_offset)? as usize,
194 2 => offset_data.read_at::<u16>(data_offset)? as usize,
195 3 => offset_data.read_at::<Uint24>(data_offset)?.to_u32() as usize,
196 4 => offset_data.read_at::<u32>(data_offset)? as usize,
197 _ => return Err(Error::InvalidIndexOffsetSize(offset_size)),
198 }
199 .checked_sub(1)
201 .ok_or(Error::ZeroOffsetInIndex)
202}
203
204#[cfg(test)]
205mod tests {
206 use font_test_data::bebuffer::BeBuffer;
207
208 use super::*;
209
210 enum IndexParams {
211 Format1 { off_size: u8, count: usize },
212 Format2 { off_size: u8, count: usize },
213 }
214
215 #[test]
216 fn index_format1_offsize1_count4() {
217 test_index(IndexParams::Format1 {
218 off_size: 1,
219 count: 4,
220 });
221 }
222
223 #[test]
224 fn index_format1_offsize2_count64() {
225 test_index(IndexParams::Format1 {
226 off_size: 2,
227 count: 64,
228 });
229 }
230
231 #[test]
232 fn index_format1_offsize3_count128() {
233 test_index(IndexParams::Format1 {
234 off_size: 3,
235 count: 128,
236 });
237 }
238
239 #[test]
240 fn index_format1_offsize4_count256() {
241 test_index(IndexParams::Format1 {
242 off_size: 4,
243 count: 256,
244 });
245 }
246
247 #[test]
248 fn index_format2_offsize1_count4() {
249 test_index(IndexParams::Format2 {
250 off_size: 4,
251 count: 256,
252 });
253 }
254
255 #[test]
256 fn index_format2_offsize2_count64() {
257 test_index(IndexParams::Format2 {
258 off_size: 2,
259 count: 64,
260 });
261 }
262
263 #[test]
264 fn index_format2_offsize3_count128() {
265 test_index(IndexParams::Format2 {
266 off_size: 3,
267 count: 128,
268 });
269 }
270
271 #[test]
272 fn index_format2_offsize4_count256() {
273 test_index(IndexParams::Format2 {
274 off_size: 4,
275 count: 256,
276 });
277 }
278
279 fn test_index(params: IndexParams) {
280 let (fmt, off_size, count) = match params {
281 IndexParams::Format1 { off_size, count } => (1, off_size, count),
282 IndexParams::Format2 { off_size, count } => (2, off_size, count),
283 };
284 let buf = make_index(fmt, off_size, count);
285 let index = Index::new(buf.data(), fmt == 2).unwrap();
286 let built_off_size = match &index {
287 Index::Empty => 0,
288 Index::Format1(v1) => v1.off_size(),
289 Index::Format2(v2) => v2.off_size(),
290 };
291 assert_eq!(built_off_size, off_size);
292 assert_eq!(index.count(), count as u32);
293 for i in 0..count {
294 let object = index.get(i).unwrap();
295 let expected_len = (i + 1) * 10;
296 let expected_bytes = vec![i as u8; expected_len];
297 assert_eq!(object, expected_bytes);
298 }
299 }
300
301 fn make_index(fmt: u8, off_size: u8, count: usize) -> BeBuffer {
302 let mut buf = BeBuffer::new();
305 match fmt {
306 1 => buf = buf.push(count as u16),
307 2 => buf = buf.push(count as u32),
308 _ => panic!("INDEX fmt should be 1 or 2"),
309 }
310 if count == 0 {
311 return buf;
312 }
313 buf = buf.push(off_size);
314 let mut offset = 1usize;
316 for i in 0..count + 1 {
317 buf = match off_size {
318 1 => buf.push(offset as u8),
319 2 => buf.push(offset as u16),
320 3 => buf.push(Uint24::checked_new(offset as u32).unwrap()),
321 4 => buf.push(offset as u32),
322 _ => panic!("off_size should be 1-4"),
323 };
324 offset += (i + 1) * 10;
325 }
326 for i in 0..count {
328 buf = buf.extend(std::iter::repeat(i as u8).take((i + 1) * 10));
329 }
330 buf
331 }
332}