1mod language;
10pub mod name;
11pub mod os2;
12mod parser;
13
14pub use language::Language;
15pub use name::{name_id, PlatformId};
16pub use os2::{Style, Width};
17pub use parser::LazyArray16;
18
19use parser::{FromData, NumFrom, Offset, Offset32, Stream};
20
21#[derive(Clone, Copy, PartialEq, Debug)]
25enum Magic {
26 TrueType,
27 OpenType,
28 FontCollection,
29}
30
31impl FromData for Magic {
32 const SIZE: usize = 4;
33
34 #[inline]
35 fn parse(data: &[u8]) -> Option<Self> {
36 match u32::parse(data)? {
37 0x00010000 | 0x74727565 => Some(Magic::TrueType),
38 0x4F54544F => Some(Magic::OpenType),
39 0x74746366 => Some(Magic::FontCollection),
40 _ => None,
41 }
42 }
43}
44
45#[repr(transparent)]
47#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
48pub struct Tag(pub u32);
49
50impl Tag {
51 #[inline]
53 pub const fn from_bytes(bytes: &[u8; 4]) -> Self {
54 Tag(((bytes[0] as u32) << 24)
55 | ((bytes[1] as u32) << 16)
56 | ((bytes[2] as u32) << 8)
57 | (bytes[3] as u32))
58 }
59}
60
61impl FromData for Tag {
62 const SIZE: usize = 4;
63
64 #[inline]
65 fn parse(data: &[u8]) -> Option<Self> {
66 u32::parse(data).map(Tag)
67 }
68}
69
70#[derive(Clone, Copy)]
72struct TableRecord {
73 tag: Tag,
74 offset: u32,
75 length: u32,
76}
77
78impl FromData for TableRecord {
79 const SIZE: usize = 16;
80
81 #[inline]
82 fn parse(data: &[u8]) -> Option<Self> {
83 let mut s = Stream::new(data);
84 let tag = s.read::<Tag>()?;
85 s.skip::<u32>(); Some(TableRecord {
87 tag,
88 offset: s.read::<u32>()?,
89 length: s.read::<u32>()?,
90 })
91 }
92}
93
94#[derive(Clone, Copy, PartialEq, Eq, Debug)]
96pub enum FaceParsingError {
97 MalformedFont,
101
102 UnknownMagic,
104
105 FaceIndexOutOfBounds,
107}
108
109#[derive(Clone, Copy)]
114pub struct RawFace<'a> {
115 pub data: &'a [u8],
117 table_records: LazyArray16<'a, TableRecord>,
119}
120
121impl<'a> RawFace<'a> {
122 pub fn parse(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
128 let mut s = Stream::new(data);
131
132 let magic = s.read::<Magic>().ok_or(FaceParsingError::UnknownMagic)?;
134 if magic == Magic::FontCollection {
135 s.skip::<u32>(); let number_of_faces = s.read::<u32>().ok_or(FaceParsingError::MalformedFont)?;
137 let offsets = s
138 .read_array32::<Offset32>(number_of_faces)
139 .ok_or(FaceParsingError::MalformedFont)?;
140
141 let face_offset = offsets
142 .get(index)
143 .ok_or(FaceParsingError::FaceIndexOutOfBounds)?;
144 let face_offset = face_offset
147 .to_usize()
148 .checked_sub(s.offset())
149 .ok_or(FaceParsingError::MalformedFont)?;
150 s.advance_checked(face_offset)
151 .ok_or(FaceParsingError::MalformedFont)?;
152
153 let magic = s.read::<Magic>().ok_or(FaceParsingError::UnknownMagic)?;
156 if magic == Magic::FontCollection {
158 return Err(FaceParsingError::UnknownMagic);
159 }
160 } else {
161 if index != 0 {
164 return Err(FaceParsingError::FaceIndexOutOfBounds);
165 }
166 }
167
168 let num_tables = s.read::<u16>().ok_or(FaceParsingError::MalformedFont)?;
169 s.advance(6); let table_records = s
171 .read_array16::<TableRecord>(num_tables)
172 .ok_or(FaceParsingError::MalformedFont)?;
173
174 Ok(RawFace {
175 data,
176 table_records,
177 })
178 }
179
180 pub fn table(&self, tag: Tag) -> Option<&'a [u8]> {
182 let (_, table) = self
183 .table_records
184 .binary_search_by(|record| record.tag.cmp(&tag))?;
185 let offset = usize::num_from(table.offset);
186 let length = usize::num_from(table.length);
187 let end = offset.checked_add(length)?;
188 self.data.get(offset..end)
189 }
190}
191
192impl core::fmt::Debug for RawFace<'_> {
193 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
194 write!(f, "RawFace {{ ... }}")
195 }
196}
197
198#[inline]
202pub fn fonts_in_collection(data: &[u8]) -> Option<u32> {
203 let mut s = Stream::new(data);
204 if s.read::<Magic>()? != Magic::FontCollection {
205 return None;
206 }
207
208 s.skip::<u32>(); s.read::<u32>()
210}