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