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