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
108#[cfg(feature = "experimental_traverse")]
109impl<'a> SomeTable<'a> for TableDirectory<'a> {
110 fn type_name(&self) -> &str {
111 "TableDirectory"
112 }
113 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
114 match idx {
115 0usize => Some(Field::new("sfnt_version", self.sfnt_version())),
116 1usize => Some(Field::new("num_tables", self.num_tables())),
117 2usize => Some(Field::new("search_range", self.search_range())),
118 3usize => Some(Field::new("entry_selector", self.entry_selector())),
119 4usize => Some(Field::new("range_shift", self.range_shift())),
120 5usize => Some(Field::new(
121 "table_records",
122 traversal::FieldType::array_of_records(
123 stringify!(TableRecord),
124 self.table_records(),
125 self.offset_data(),
126 ),
127 )),
128 _ => None,
129 }
130 }
131}
132
133#[cfg(feature = "experimental_traverse")]
134#[allow(clippy::needless_lifetimes)]
135impl<'a> std::fmt::Debug for TableDirectory<'a> {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 (self as &dyn SomeTable<'a>).fmt(f)
138 }
139}
140
141#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
143#[repr(C)]
144#[repr(packed)]
145pub struct TableRecord {
146 pub tag: BigEndian<Tag>,
148 pub checksum: BigEndian<u32>,
150 pub offset: BigEndian<u32>,
152 pub length: BigEndian<u32>,
154}
155
156impl TableRecord {
157 pub fn tag(&self) -> Tag {
159 self.tag.get()
160 }
161
162 pub fn checksum(&self) -> u32 {
164 self.checksum.get()
165 }
166
167 pub fn offset(&self) -> u32 {
169 self.offset.get()
170 }
171
172 pub fn length(&self) -> u32 {
174 self.length.get()
175 }
176}
177
178impl FixedSize for TableRecord {
179 const RAW_BYTE_LEN: usize =
180 Tag::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
181}
182
183#[cfg(feature = "experimental_traverse")]
184impl<'a> SomeRecord<'a> for TableRecord {
185 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
186 RecordResolver {
187 name: "TableRecord",
188 get_field: Box::new(move |idx, _data| match idx {
189 0usize => Some(Field::new("tag", self.tag())),
190 1usize => Some(Field::new("checksum", self.checksum())),
191 2usize => Some(Field::new("offset", self.offset())),
192 3usize => Some(Field::new("length", self.length())),
193 _ => None,
194 }),
195 data,
196 }
197 }
198}
199
200impl<'a> MinByteRange<'a> for TTCHeader<'a> {
201 fn min_byte_range(&self) -> Range<usize> {
202 0..self.table_directory_offsets_byte_range().end
203 }
204 fn min_table_bytes(&self) -> &'a [u8] {
205 let range = self.min_byte_range();
206 self.data.as_bytes().get(range).unwrap_or_default()
207 }
208}
209
210impl<'a> FontRead<'a> for TTCHeader<'a> {
211 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
212 #[allow(clippy::absurd_extreme_comparisons)]
213 if data.len() < Self::MIN_SIZE {
214 return Err(ReadError::OutOfBounds);
215 }
216 Ok(Self { data })
217 }
218}
219
220#[derive(Clone)]
222pub struct TTCHeader<'a> {
223 data: FontData<'a>,
224}
225
226#[allow(clippy::needless_lifetimes)]
227impl<'a> TTCHeader<'a> {
228 pub const MIN_SIZE: usize = (Tag::RAW_BYTE_LEN + MajorMinor::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
229 basic_table_impls!(impl_the_methods);
230
231 pub fn ttc_tag(&self) -> Tag {
233 let range = self.ttc_tag_byte_range();
234 self.data.read_at(range.start).ok().unwrap()
235 }
236
237 pub fn version(&self) -> MajorMinor {
239 let range = self.version_byte_range();
240 self.data.read_at(range.start).ok().unwrap()
241 }
242
243 pub fn num_fonts(&self) -> u32 {
245 let range = self.num_fonts_byte_range();
246 self.data.read_at(range.start).ok().unwrap()
247 }
248
249 pub fn table_directory_offsets(&self) -> &'a [BigEndian<u32>] {
251 let range = self.table_directory_offsets_byte_range();
252 self.data.read_array(range).ok().unwrap_or_default()
253 }
254
255 pub fn dsig_tag(&self) -> Option<u32> {
257 let range = self.dsig_tag_byte_range();
258 (!range.is_empty())
259 .then(|| self.data.read_at(range.start).ok())
260 .flatten()
261 }
262
263 pub fn dsig_length(&self) -> Option<u32> {
265 let range = self.dsig_length_byte_range();
266 (!range.is_empty())
267 .then(|| self.data.read_at(range.start).ok())
268 .flatten()
269 }
270
271 pub fn dsig_offset(&self) -> Option<u32> {
273 let range = self.dsig_offset_byte_range();
274 (!range.is_empty())
275 .then(|| self.data.read_at(range.start).ok())
276 .flatten()
277 }
278
279 pub fn ttc_tag_byte_range(&self) -> Range<usize> {
280 let start = 0;
281 start..start + Tag::RAW_BYTE_LEN
282 }
283
284 pub fn version_byte_range(&self) -> Range<usize> {
285 let start = self.ttc_tag_byte_range().end;
286 start..start + MajorMinor::RAW_BYTE_LEN
287 }
288
289 pub fn num_fonts_byte_range(&self) -> Range<usize> {
290 let start = self.version_byte_range().end;
291 start..start + u32::RAW_BYTE_LEN
292 }
293
294 pub fn table_directory_offsets_byte_range(&self) -> Range<usize> {
295 let num_fonts = self.num_fonts();
296 let start = self.num_fonts_byte_range().end;
297 start..start + (num_fonts as usize).saturating_mul(u32::RAW_BYTE_LEN)
298 }
299
300 pub fn dsig_tag_byte_range(&self) -> Range<usize> {
301 let start = self.table_directory_offsets_byte_range().end;
302 start
303 ..(self.version().compatible((2u16, 0u16)))
304 .then(|| start + u32::RAW_BYTE_LEN)
305 .unwrap_or(start)
306 }
307
308 pub fn dsig_length_byte_range(&self) -> Range<usize> {
309 let start = self.dsig_tag_byte_range().end;
310 start
311 ..(self.version().compatible((2u16, 0u16)))
312 .then(|| start + u32::RAW_BYTE_LEN)
313 .unwrap_or(start)
314 }
315
316 pub fn dsig_offset_byte_range(&self) -> Range<usize> {
317 let start = self.dsig_length_byte_range().end;
318 start
319 ..(self.version().compatible((2u16, 0u16)))
320 .then(|| start + u32::RAW_BYTE_LEN)
321 .unwrap_or(start)
322 }
323}
324
325#[cfg(feature = "experimental_traverse")]
326impl<'a> SomeTable<'a> for TTCHeader<'a> {
327 fn type_name(&self) -> &str {
328 "TTCHeader"
329 }
330 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
331 match idx {
332 0usize => Some(Field::new("ttc_tag", self.ttc_tag())),
333 1usize => Some(Field::new("version", self.version())),
334 2usize => Some(Field::new("num_fonts", self.num_fonts())),
335 3usize => Some(Field::new(
336 "table_directory_offsets",
337 self.table_directory_offsets(),
338 )),
339 4usize if self.version().compatible((2u16, 0u16)) => {
340 Some(Field::new("dsig_tag", self.dsig_tag().unwrap()))
341 }
342 5usize if self.version().compatible((2u16, 0u16)) => {
343 Some(Field::new("dsig_length", self.dsig_length().unwrap()))
344 }
345 6usize if self.version().compatible((2u16, 0u16)) => {
346 Some(Field::new("dsig_offset", self.dsig_offset().unwrap()))
347 }
348 _ => None,
349 }
350 }
351}
352
353#[cfg(feature = "experimental_traverse")]
354#[allow(clippy::needless_lifetimes)]
355impl<'a> std::fmt::Debug for TTCHeader<'a> {
356 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357 (self as &dyn SomeTable<'a>).fmt(f)
358 }
359}