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 let end = start + u32::RAW_BYTE_LEN;
79 start..end
80 }
81
82 pub fn num_tables_byte_range(&self) -> Range<usize> {
83 let start = self.sfnt_version_byte_range().end;
84 let end = start + u16::RAW_BYTE_LEN;
85 start..end
86 }
87
88 pub fn search_range_byte_range(&self) -> Range<usize> {
89 let start = self.num_tables_byte_range().end;
90 let end = start + u16::RAW_BYTE_LEN;
91 start..end
92 }
93
94 pub fn entry_selector_byte_range(&self) -> Range<usize> {
95 let start = self.search_range_byte_range().end;
96 let end = start + u16::RAW_BYTE_LEN;
97 start..end
98 }
99
100 pub fn range_shift_byte_range(&self) -> Range<usize> {
101 let start = self.entry_selector_byte_range().end;
102 let end = start + u16::RAW_BYTE_LEN;
103 start..end
104 }
105
106 pub fn table_records_byte_range(&self) -> Range<usize> {
107 let num_tables = self.num_tables();
108 let start = self.range_shift_byte_range().end;
109 let end =
110 start + (transforms::to_usize(num_tables)).saturating_mul(TableRecord::RAW_BYTE_LEN);
111 start..end
112 }
113}
114
115const _: () = assert!(FontData::default_data_long_enough(TableDirectory::MIN_SIZE));
116
117impl Default for TableDirectory<'_> {
118 fn default() -> Self {
119 Self {
120 data: FontData::default_table_data(),
121 }
122 }
123}
124
125#[cfg(feature = "experimental_traverse")]
126impl<'a> SomeTable<'a> for TableDirectory<'a> {
127 fn type_name(&self) -> &str {
128 "TableDirectory"
129 }
130 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
131 match idx {
132 0usize => Some(Field::new("sfnt_version", self.sfnt_version())),
133 1usize => Some(Field::new("num_tables", self.num_tables())),
134 2usize => Some(Field::new("search_range", self.search_range())),
135 3usize => Some(Field::new("entry_selector", self.entry_selector())),
136 4usize => Some(Field::new("range_shift", self.range_shift())),
137 5usize => Some(Field::new(
138 "table_records",
139 traversal::FieldType::array_of_records(
140 stringify!(TableRecord),
141 self.table_records(),
142 self.offset_data(),
143 ),
144 )),
145 _ => None,
146 }
147 }
148}
149
150#[cfg(feature = "experimental_traverse")]
151#[allow(clippy::needless_lifetimes)]
152impl<'a> std::fmt::Debug for TableDirectory<'a> {
153 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154 (self as &dyn SomeTable<'a>).fmt(f)
155 }
156}
157
158#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
160#[repr(C)]
161#[repr(packed)]
162pub struct TableRecord {
163 pub tag: BigEndian<Tag>,
165 pub checksum: BigEndian<u32>,
167 pub offset: BigEndian<u32>,
169 pub length: BigEndian<u32>,
171}
172
173impl TableRecord {
174 pub fn tag(&self) -> Tag {
176 self.tag.get()
177 }
178
179 pub fn checksum(&self) -> u32 {
181 self.checksum.get()
182 }
183
184 pub fn offset(&self) -> u32 {
186 self.offset.get()
187 }
188
189 pub fn length(&self) -> u32 {
191 self.length.get()
192 }
193}
194
195impl FixedSize for TableRecord {
196 const RAW_BYTE_LEN: usize =
197 Tag::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
198}
199
200#[cfg(feature = "experimental_traverse")]
201impl<'a> SomeRecord<'a> for TableRecord {
202 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
203 RecordResolver {
204 name: "TableRecord",
205 get_field: Box::new(move |idx, _data| match idx {
206 0usize => Some(Field::new("tag", self.tag())),
207 1usize => Some(Field::new("checksum", self.checksum())),
208 2usize => Some(Field::new("offset", self.offset())),
209 3usize => Some(Field::new("length", self.length())),
210 _ => None,
211 }),
212 data,
213 }
214 }
215}
216
217impl<'a> MinByteRange<'a> for TTCHeader<'a> {
218 fn min_byte_range(&self) -> Range<usize> {
219 0..self.table_directory_offsets_byte_range().end
220 }
221 fn min_table_bytes(&self) -> &'a [u8] {
222 let range = self.min_byte_range();
223 self.data.as_bytes().get(range).unwrap_or_default()
224 }
225}
226
227impl<'a> FontRead<'a> for TTCHeader<'a> {
228 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
229 #[allow(clippy::absurd_extreme_comparisons)]
230 if data.len() < Self::MIN_SIZE {
231 return Err(ReadError::OutOfBounds);
232 }
233 Ok(Self { data })
234 }
235}
236
237#[derive(Clone)]
239pub struct TTCHeader<'a> {
240 data: FontData<'a>,
241}
242
243#[allow(clippy::needless_lifetimes)]
244impl<'a> TTCHeader<'a> {
245 pub const MIN_SIZE: usize = (Tag::RAW_BYTE_LEN + MajorMinor::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
246 basic_table_impls!(impl_the_methods);
247
248 pub fn ttc_tag(&self) -> Tag {
250 let range = self.ttc_tag_byte_range();
251 self.data.read_at(range.start).ok().unwrap()
252 }
253
254 pub fn version(&self) -> MajorMinor {
256 let range = self.version_byte_range();
257 self.data.read_at(range.start).ok().unwrap()
258 }
259
260 pub fn num_fonts(&self) -> u32 {
262 let range = self.num_fonts_byte_range();
263 self.data.read_at(range.start).ok().unwrap()
264 }
265
266 pub fn table_directory_offsets(&self) -> &'a [BigEndian<u32>] {
268 let range = self.table_directory_offsets_byte_range();
269 self.data.read_array(range).ok().unwrap_or_default()
270 }
271
272 pub fn dsig_tag(&self) -> Option<u32> {
274 let range = self.dsig_tag_byte_range();
275 (!range.is_empty())
276 .then(|| self.data.read_at(range.start).ok())
277 .flatten()
278 }
279
280 pub fn dsig_length(&self) -> Option<u32> {
282 let range = self.dsig_length_byte_range();
283 (!range.is_empty())
284 .then(|| self.data.read_at(range.start).ok())
285 .flatten()
286 }
287
288 pub fn dsig_offset(&self) -> Option<u32> {
290 let range = self.dsig_offset_byte_range();
291 (!range.is_empty())
292 .then(|| self.data.read_at(range.start).ok())
293 .flatten()
294 }
295
296 pub fn ttc_tag_byte_range(&self) -> Range<usize> {
297 let start = 0;
298 let end = start + Tag::RAW_BYTE_LEN;
299 start..end
300 }
301
302 pub fn version_byte_range(&self) -> Range<usize> {
303 let start = self.ttc_tag_byte_range().end;
304 let end = start + MajorMinor::RAW_BYTE_LEN;
305 start..end
306 }
307
308 pub fn num_fonts_byte_range(&self) -> Range<usize> {
309 let start = self.version_byte_range().end;
310 let end = start + u32::RAW_BYTE_LEN;
311 start..end
312 }
313
314 pub fn table_directory_offsets_byte_range(&self) -> Range<usize> {
315 let num_fonts = self.num_fonts();
316 let start = self.num_fonts_byte_range().end;
317 let end = start + (transforms::to_usize(num_fonts)).saturating_mul(u32::RAW_BYTE_LEN);
318 start..end
319 }
320
321 pub fn dsig_tag_byte_range(&self) -> Range<usize> {
322 let start = self.table_directory_offsets_byte_range().end;
323 let end = if self.version().compatible((2u16, 0u16)) {
324 start + u32::RAW_BYTE_LEN
325 } else {
326 start
327 };
328 start..end
329 }
330
331 pub fn dsig_length_byte_range(&self) -> Range<usize> {
332 let start = self.dsig_tag_byte_range().end;
333 let end = if self.version().compatible((2u16, 0u16)) {
334 start + u32::RAW_BYTE_LEN
335 } else {
336 start
337 };
338 start..end
339 }
340
341 pub fn dsig_offset_byte_range(&self) -> Range<usize> {
342 let start = self.dsig_length_byte_range().end;
343 let end = if self.version().compatible((2u16, 0u16)) {
344 start + u32::RAW_BYTE_LEN
345 } else {
346 start
347 };
348 start..end
349 }
350}
351
352const _: () = assert!(FontData::default_data_long_enough(TTCHeader::MIN_SIZE));
353
354impl Default for TTCHeader<'_> {
355 fn default() -> Self {
356 Self {
357 data: FontData::default_table_data(),
358 }
359 }
360}
361
362#[cfg(feature = "experimental_traverse")]
363impl<'a> SomeTable<'a> for TTCHeader<'a> {
364 fn type_name(&self) -> &str {
365 "TTCHeader"
366 }
367 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
368 match idx {
369 0usize => Some(Field::new("ttc_tag", self.ttc_tag())),
370 1usize => Some(Field::new("version", self.version())),
371 2usize => Some(Field::new("num_fonts", self.num_fonts())),
372 3usize => Some(Field::new(
373 "table_directory_offsets",
374 self.table_directory_offsets(),
375 )),
376 4usize if self.version().compatible((2u16, 0u16)) => {
377 Some(Field::new("dsig_tag", self.dsig_tag().unwrap()))
378 }
379 5usize if self.version().compatible((2u16, 0u16)) => {
380 Some(Field::new("dsig_length", self.dsig_length().unwrap()))
381 }
382 6usize if self.version().compatible((2u16, 0u16)) => {
383 Some(Field::new("dsig_offset", self.dsig_offset().unwrap()))
384 }
385 _ => None,
386 }
387 }
388}
389
390#[cfg(feature = "experimental_traverse")]
391#[allow(clippy::needless_lifetimes)]
392impl<'a> std::fmt::Debug for TTCHeader<'a> {
393 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394 (self as &dyn SomeTable<'a>).fmt(f)
395 }
396}