read_fonts/generated/
font.rs1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for TableDirectory<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.table_records_byte_range().end
11 }
12 fn min_table_bytes(&self) -> &'a [u8] {
13 let range = self.min_byte_range();
14 self.data.as_bytes().get(range).unwrap_or_default()
15 }
16}
17
18impl<'a> FontRead<'a> for TableDirectory<'a> {
19 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
20 #[allow(clippy::absurd_extreme_comparisons)]
21 if data.len() < Self::MIN_SIZE {
22 return Err(ReadError::OutOfBounds);
23 }
24 Ok(Self { data })
25 }
26}
27
28#[derive(Clone)]
30pub struct TableDirectory<'a> {
31 data: FontData<'a>,
32}
33
34#[allow(clippy::needless_lifetimes)]
35impl<'a> TableDirectory<'a> {
36 pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN
37 + u16::RAW_BYTE_LEN
38 + u16::RAW_BYTE_LEN
39 + u16::RAW_BYTE_LEN
40 + u16::RAW_BYTE_LEN);
41 basic_table_impls!(impl_the_methods);
42
43 pub fn sfnt_version(&self) -> u32 {
45 let range = self.sfnt_version_byte_range();
46 self.data.read_at(range.start).ok().unwrap()
47 }
48
49 pub fn num_tables(&self) -> u16 {
51 let range = self.num_tables_byte_range();
52 self.data.read_at(range.start).ok().unwrap()
53 }
54
55 pub fn search_range(&self) -> u16 {
56 let range = self.search_range_byte_range();
57 self.data.read_at(range.start).ok().unwrap()
58 }
59
60 pub fn entry_selector(&self) -> u16 {
61 let range = self.entry_selector_byte_range();
62 self.data.read_at(range.start).ok().unwrap()
63 }
64
65 pub fn range_shift(&self) -> u16 {
66 let range = self.range_shift_byte_range();
67 self.data.read_at(range.start).ok().unwrap()
68 }
69
70 pub fn table_records(&self) -> &'a [TableRecord] {
72 let range = self.table_records_byte_range();
73 self.data.read_array(range).ok().unwrap_or_default()
74 }
75
76 pub fn sfnt_version_byte_range(&self) -> Range<usize> {
77 let start = 0;
78 start..start + u32::RAW_BYTE_LEN
79 }
80
81 pub fn num_tables_byte_range(&self) -> Range<usize> {
82 let start = self.sfnt_version_byte_range().end;
83 start..start + u16::RAW_BYTE_LEN
84 }
85
86 pub fn search_range_byte_range(&self) -> Range<usize> {
87 let start = self.num_tables_byte_range().end;
88 start..start + u16::RAW_BYTE_LEN
89 }
90
91 pub fn entry_selector_byte_range(&self) -> Range<usize> {
92 let start = self.search_range_byte_range().end;
93 start..start + u16::RAW_BYTE_LEN
94 }
95
96 pub fn range_shift_byte_range(&self) -> Range<usize> {
97 let start = self.entry_selector_byte_range().end;
98 start..start + u16::RAW_BYTE_LEN
99 }
100
101 pub fn table_records_byte_range(&self) -> Range<usize> {
102 let num_tables = self.num_tables();
103 let start = self.range_shift_byte_range().end;
104 start..start + (num_tables as usize).saturating_mul(TableRecord::RAW_BYTE_LEN)
105 }
106}
107
108const _: () = assert!(FontData::default_data_long_enough(TableDirectory::MIN_SIZE));
109
110impl Default for TableDirectory<'_> {
111 fn default() -> Self {
112 Self {
113 data: FontData::default_table_data(),
114 }
115 }
116}
117
118#[cfg(feature = "experimental_traverse")]
119impl<'a> SomeTable<'a> for TableDirectory<'a> {
120 fn type_name(&self) -> &str {
121 "TableDirectory"
122 }
123 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
124 match idx {
125 0usize => Some(Field::new("sfnt_version", self.sfnt_version())),
126 1usize => Some(Field::new("num_tables", self.num_tables())),
127 2usize => Some(Field::new("search_range", self.search_range())),
128 3usize => Some(Field::new("entry_selector", self.entry_selector())),
129 4usize => Some(Field::new("range_shift", self.range_shift())),
130 5usize => Some(Field::new(
131 "table_records",
132 traversal::FieldType::array_of_records(
133 stringify!(TableRecord),
134 self.table_records(),
135 self.offset_data(),
136 ),
137 )),
138 _ => None,
139 }
140 }
141}
142
143#[cfg(feature = "experimental_traverse")]
144#[allow(clippy::needless_lifetimes)]
145impl<'a> std::fmt::Debug for TableDirectory<'a> {
146 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147 (self as &dyn SomeTable<'a>).fmt(f)
148 }
149}
150
151#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
153#[repr(C)]
154#[repr(packed)]
155pub struct TableRecord {
156 pub tag: BigEndian<Tag>,
158 pub checksum: BigEndian<u32>,
160 pub offset: BigEndian<u32>,
162 pub length: BigEndian<u32>,
164}
165
166impl TableRecord {
167 pub fn tag(&self) -> Tag {
169 self.tag.get()
170 }
171
172 pub fn checksum(&self) -> u32 {
174 self.checksum.get()
175 }
176
177 pub fn offset(&self) -> u32 {
179 self.offset.get()
180 }
181
182 pub fn length(&self) -> u32 {
184 self.length.get()
185 }
186}
187
188impl FixedSize for TableRecord {
189 const RAW_BYTE_LEN: usize =
190 Tag::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
191}
192
193#[cfg(feature = "experimental_traverse")]
194impl<'a> SomeRecord<'a> for TableRecord {
195 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
196 RecordResolver {
197 name: "TableRecord",
198 get_field: Box::new(move |idx, _data| match idx {
199 0usize => Some(Field::new("tag", self.tag())),
200 1usize => Some(Field::new("checksum", self.checksum())),
201 2usize => Some(Field::new("offset", self.offset())),
202 3usize => Some(Field::new("length", self.length())),
203 _ => None,
204 }),
205 data,
206 }
207 }
208}
209
210impl<'a> MinByteRange<'a> for TTCHeader<'a> {
211 fn min_byte_range(&self) -> Range<usize> {
212 0..self.table_directory_offsets_byte_range().end
213 }
214 fn min_table_bytes(&self) -> &'a [u8] {
215 let range = self.min_byte_range();
216 self.data.as_bytes().get(range).unwrap_or_default()
217 }
218}
219
220impl<'a> FontRead<'a> for TTCHeader<'a> {
221 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
222 #[allow(clippy::absurd_extreme_comparisons)]
223 if data.len() < Self::MIN_SIZE {
224 return Err(ReadError::OutOfBounds);
225 }
226 Ok(Self { data })
227 }
228}
229
230#[derive(Clone)]
232pub struct TTCHeader<'a> {
233 data: FontData<'a>,
234}
235
236#[allow(clippy::needless_lifetimes)]
237impl<'a> TTCHeader<'a> {
238 pub const MIN_SIZE: usize = (Tag::RAW_BYTE_LEN + MajorMinor::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
239 basic_table_impls!(impl_the_methods);
240
241 pub fn ttc_tag(&self) -> Tag {
243 let range = self.ttc_tag_byte_range();
244 self.data.read_at(range.start).ok().unwrap()
245 }
246
247 pub fn version(&self) -> MajorMinor {
249 let range = self.version_byte_range();
250 self.data.read_at(range.start).ok().unwrap()
251 }
252
253 pub fn num_fonts(&self) -> u32 {
255 let range = self.num_fonts_byte_range();
256 self.data.read_at(range.start).ok().unwrap()
257 }
258
259 pub fn table_directory_offsets(&self) -> &'a [BigEndian<u32>] {
261 let range = self.table_directory_offsets_byte_range();
262 self.data.read_array(range).ok().unwrap_or_default()
263 }
264
265 pub fn dsig_tag(&self) -> Option<u32> {
267 let range = self.dsig_tag_byte_range();
268 (!range.is_empty())
269 .then(|| self.data.read_at(range.start).ok())
270 .flatten()
271 }
272
273 pub fn dsig_length(&self) -> Option<u32> {
275 let range = self.dsig_length_byte_range();
276 (!range.is_empty())
277 .then(|| self.data.read_at(range.start).ok())
278 .flatten()
279 }
280
281 pub fn dsig_offset(&self) -> Option<u32> {
283 let range = self.dsig_offset_byte_range();
284 (!range.is_empty())
285 .then(|| self.data.read_at(range.start).ok())
286 .flatten()
287 }
288
289 pub fn ttc_tag_byte_range(&self) -> Range<usize> {
290 let start = 0;
291 start..start + Tag::RAW_BYTE_LEN
292 }
293
294 pub fn version_byte_range(&self) -> Range<usize> {
295 let start = self.ttc_tag_byte_range().end;
296 start..start + MajorMinor::RAW_BYTE_LEN
297 }
298
299 pub fn num_fonts_byte_range(&self) -> Range<usize> {
300 let start = self.version_byte_range().end;
301 start..start + u32::RAW_BYTE_LEN
302 }
303
304 pub fn table_directory_offsets_byte_range(&self) -> Range<usize> {
305 let num_fonts = self.num_fonts();
306 let start = self.num_fonts_byte_range().end;
307 start..start + (num_fonts as usize).saturating_mul(u32::RAW_BYTE_LEN)
308 }
309
310 pub fn dsig_tag_byte_range(&self) -> Range<usize> {
311 let start = self.table_directory_offsets_byte_range().end;
312 start
313 ..(self.version().compatible((2u16, 0u16)))
314 .then(|| start + u32::RAW_BYTE_LEN)
315 .unwrap_or(start)
316 }
317
318 pub fn dsig_length_byte_range(&self) -> Range<usize> {
319 let start = self.dsig_tag_byte_range().end;
320 start
321 ..(self.version().compatible((2u16, 0u16)))
322 .then(|| start + u32::RAW_BYTE_LEN)
323 .unwrap_or(start)
324 }
325
326 pub fn dsig_offset_byte_range(&self) -> Range<usize> {
327 let start = self.dsig_length_byte_range().end;
328 start
329 ..(self.version().compatible((2u16, 0u16)))
330 .then(|| start + u32::RAW_BYTE_LEN)
331 .unwrap_or(start)
332 }
333}
334
335const _: () = assert!(FontData::default_data_long_enough(TTCHeader::MIN_SIZE));
336
337impl Default for TTCHeader<'_> {
338 fn default() -> Self {
339 Self {
340 data: FontData::default_table_data(),
341 }
342 }
343}
344
345#[cfg(feature = "experimental_traverse")]
346impl<'a> SomeTable<'a> for TTCHeader<'a> {
347 fn type_name(&self) -> &str {
348 "TTCHeader"
349 }
350 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
351 match idx {
352 0usize => Some(Field::new("ttc_tag", self.ttc_tag())),
353 1usize => Some(Field::new("version", self.version())),
354 2usize => Some(Field::new("num_fonts", self.num_fonts())),
355 3usize => Some(Field::new(
356 "table_directory_offsets",
357 self.table_directory_offsets(),
358 )),
359 4usize if self.version().compatible((2u16, 0u16)) => {
360 Some(Field::new("dsig_tag", self.dsig_tag().unwrap()))
361 }
362 5usize if self.version().compatible((2u16, 0u16)) => {
363 Some(Field::new("dsig_length", self.dsig_length().unwrap()))
364 }
365 6usize if self.version().compatible((2u16, 0u16)) => {
366 Some(Field::new("dsig_offset", self.dsig_offset().unwrap()))
367 }
368 _ => None,
369 }
370 }
371}
372
373#[cfg(feature = "experimental_traverse")]
374#[allow(clippy::needless_lifetimes)]
375impl<'a> std::fmt::Debug for TTCHeader<'a> {
376 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
377 (self as &dyn SomeTable<'a>).fmt(f)
378 }
379}