1#![no_std]
2#![doc = include_str!("../README.md")]
3
4
5pub struct Psf<'a> {
14 pub glyph_byte_length: usize,
15 pub glyph_width: usize,
16 pub glyph_height: usize,
17 pub glyphs: &'a [u8],
18 pub unicode_table: Option<&'a [u8]>,
19}
20
21
22impl<'a> Psf<'a> {
23 pub const fn parse(data: &[u8]) -> Result<Psf, ParseError> {
37 if data.len() < 32 {
38 return Err(ParseError::HeaderMissing);
39 }
40
41 if u32_at(data, 0) == 0x864ab572 {
42 Self::parse_psf2(data)
43 } else if u32_at(data, 0) & 0xffff == 0x0436 {
44 Self::parse_psf1(data)
45 } else {
46 Err(ParseError::InvalidMagicBytes)
47 }
48 }
49
50 const fn parse_psf1(data: &[u8]) -> Result<Psf, ParseError> {
51 let mode = data[2];
52 let has_512_glyphs = 0 != (mode & 0x1);
53 let has_unicode_table = 0 != (mode & 0x2);
54
55 let glyph_count =
56 if has_512_glyphs {
57 256
58 } else {
59 512
60 };
61
62 let glyph_height = data[3] as usize;
63
64 let glyphs = slice_len(data, 4, glyph_count * glyph_height);
65
66 let unicode_entries =
67 if has_unicode_table {
68 let (unicode_entries, _) = data.split_at(4 + glyph_count * glyph_height);
69 Some(unicode_entries)
70 } else {
71 None
72 };
73
74 let psf =
75 Psf {
76 glyph_byte_length: glyph_height,
77 glyph_width: 8,
78 glyph_height: glyph_height,
79 glyphs: glyphs,
80 unicode_table: unicode_entries,
81 };
82
83 Ok(psf)
84 }
85
86 const fn parse_psf2(data: &[u8]) -> Result<Psf, ParseError> {
87 let version = u32_at(data, 4);
88 if 0 != version {
89 return Err(ParseError::UnknownVersion(version));
90 }
91
92 let header_size = u32_at(data, 8) as usize;
93 let flags = u32_at(data, 12);
94 let has_unicode_table = 1 == (flags & 0x00000001);
95 let glyph_count = u32_at(data, 16) as usize;
96 let glyph_byte_length = u32_at(data, 20) as usize;
97 let glyph_height = u32_at(data, 24) as usize;
98 let glyph_width = u32_at(data, 28) as usize;
99
100 let expected_byte_count = header_size + (glyph_count * glyph_byte_length);
101 if data.len() < expected_byte_count {
102 return Err(ParseError::GlyphTableTruncated { expected_byte_count: expected_byte_count });
103 }
104
105 let glyphs = slice_len(data, header_size, glyph_byte_length * glyph_count);
106
107 let unicode_table =
108 if has_unicode_table {
109 Some(data.split_at(expected_byte_count).1)
110 } else {
111 None
112 };
113
114 let psf = Psf {
115 glyph_byte_length: glyph_byte_length,
116 glyph_width: glyph_width,
117 glyph_height: glyph_height,
118 glyphs,
119 unicode_table,
120 };
121
122 Ok(psf)
123 }
124
125 pub fn get_glyph_bits(&self, glyph_index: usize) -> Option<&[u8]> {
134 let start = self.glyph_byte_length * glyph_index;
135 let end = start + self.glyph_byte_length;
136 self.glyphs.get(start..end)
137 }
138
139 pub fn get_glyph_pixels<'b>(&'b self, glyph_index: usize) -> Option<impl Iterator<Item=bool> + 'b> {
151 let glyph_bits = self.get_glyph_bits(glyph_index)?;
152 let bytes_per_row = (self.glyph_width + 7) / 8;
153
154 let iterator =
155 (0..self.glyph_height).flat_map(move |y| {
156 (0..self.glyph_width).map(move |x| {
157 let byte_index = (x / 8) + (y * bytes_per_row);
158 let byte = glyph_bits[byte_index];
159 let bit_offset = 7 - (x % 8);
160 let bit = (byte >> bit_offset) & 1;
161 bit == 1
162 })
163 });
164
165 Some(iterator)
166 }
167
168 pub fn iter_unicode_entries<'b>(&'b self) -> Option<impl Iterator<Item=(usize, Result<&'b str, core::str::Utf8Error>)> + 'b> {
190 let table = self.unicode_table?;
191
192 let iterator = table.split(|&x| x == 0xff).enumerate().flat_map(move |(glyph_index, unicode_entries)| {
193 unicode_entries.split(|&x| x == 0xfe).map(move |unicode_string| {
194 (glyph_index, core::str::from_utf8(unicode_string))
195 })
196 });
197
198 Some(iterator)
199 }
200}
201
202
203#[derive(Copy, Clone, Debug, Eq, PartialEq)]
205pub enum ParseError {
206 HeaderMissing,
208
209 InvalidMagicBytes,
211
212 UnknownVersion(u32),
215
216 GlyphTableTruncated { expected_byte_count: usize, },
219}
220
221
222const fn slice_len(data: &[u8], start: usize, len: usize) -> &[u8] {
224 let (_, rest) = data.split_at(start);
225 let (segment, _) = rest.split_at(len);
226 segment
227}
228
229const fn u32_at(data: &[u8], at: usize) -> u32 {
231 let bytes = slice_len(data, at, 4);
232 u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
233}