forked from Bill-Gray/PDCursesMod
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpsf.c
244 lines (211 loc) · 7.47 KB
/
psf.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "psf.h"
/* Code for the PSF font format, both psf1 and psf2, as
described at
https://www.win.tue.nl/~aeb/linux/kbd/font-formats-1.html
and for the (much simpler) 'vgafont' font format; see _load_vgafont()
below. The PSF fonts can contain Unicode information, a table basically
saying "Unicode point x corresponds to glyph y". This code reads that
information (if it's provided) and sorts it by Unicode point, so that
when the glyph for a given Unicode point is desired, we can
binary-search for it. */
#define PSF1_MAGIC0 0x36
#define PSF1_MAGIC1 0x04
#define PSF1_MODE512 0x01
#define PSF1_MODEHASTAB 0x02
#define PSF1_MODEHASSEQ 0x04
#define PSF1_MAXMODE 0x05
#define PSF1_SEPARATOR 0xFFFF
#define PSF1_STARTSEQ 0xFFFE
struct psf1_header {
unsigned char magic[2]; /* Magic number */
unsigned char mode; /* PSF font mode */
unsigned char charsize; /* Character size */
};
static int _compare_unicode_info( const void *a, const void *b)
{
const int32_t diff = *(int32_t *)a - *(int32_t *)b;
return( (int)diff);
}
static int _load_psf1( struct font_info *f, const uint8_t *buff, const long filelen)
{
struct psf1_header hdr;
int n_references_found = 0;
if( buff[0] != PSF1_MAGIC0 && buff[1] != PSF1_MAGIC1)
return( -1);
memcpy( &hdr, buff, sizeof( hdr));
f->font_type = 1;
f->n_glyphs = ((hdr.mode & PSF1_MODE512) ? 512 : 256);
f->headersize = 4;
f->charsize = f->height = hdr.charsize;
f->width = 8;
f->glyphs = buff + f->headersize;
if( hdr.mode & PSF1_MODEHASTAB)
{
size_t i = (size_t) 4 + f->n_glyphs * hdr.charsize;
unsigned glyph_num = 0;
unsigned max_info_size = (unsigned)( (filelen - i) / 2 - f->n_glyphs);
uint32_t *tptr = (uint32_t *)malloc( max_info_size * 2 * sizeof( uint32_t));
f->unicode_info = tptr;
for( ; i < (size_t)filelen; i += 2)
{
const unsigned ival = buff[i] | ((unsigned)buff[i + 1] << 8);
if( ival == PSF1_SEPARATOR)
glyph_num++;
else if( ival != PSF1_STARTSEQ)
{
assert( n_references_found < (int)max_info_size);
*tptr++ = (uint32_t)ival;
*tptr++ = glyph_num;
n_references_found++;
}
}
qsort( f->unicode_info, n_references_found, 2 * sizeof( uint32_t),
_compare_unicode_info);
}
else
f->unicode_info = NULL;
f->unicode_info_size = n_references_found;
return( 0);
}
#define PSF2_MAGIC0 0x72
#define PSF2_MAGIC1 0xb5
#define PSF2_MAGIC2 0x4a
#define PSF2_MAGIC3 0x86
/* bits used in flags */
#define PSF2_HAS_UNICODE_TABLE 0x01
/* max version recognized so far */
#define PSF2_MAXVERSION 0
/* UTF8 separators */
#define PSF2_SEPARATOR 0xFF
#define PSF2_STARTSEQ 0xFE
struct psf2_header {
uint8_t magic[4];
uint32_t version;
uint32_t headersize; /* offset of bitmaps in file */
uint32_t flags;
uint32_t length; /* number of glyphs */
uint32_t charsize; /* number of bytes for each character */
uint32_t height, width; /* max dimensions of glyphs */
/* charsize = height * ((width + 7) / 8) */
};
#define IS_UTF8_STARTING_BYTE( c) (!((c) & 0x80) || ((c) > 0xc1 && (c) < 0xf5))
static uint32_t *_decipher_psf2_unicode_table( const uint8_t *buff, const size_t info_len,
uint32_t *unicode_info_size)
{
unsigned glyph_num = 0;
size_t i, n1 = 0;
uint32_t n_references_found = 0;
uint32_t *unicode_info, *tptr;
for( i = 0; i < info_len; i++)
if( IS_UTF8_STARTING_BYTE( buff[i]))
n1++;
unicode_info = tptr = (uint32_t *)malloc( n1 * 2 * sizeof( uint32_t));
for( i = 0; i < info_len; i++)
if( buff[i] == PSF2_SEPARATOR)
glyph_num++;
else if( buff[i] != PSF2_STARTSEQ)
{
unsigned cval; /* decipher UTF8 value */
if( !(buff[i] & 0x80)) /* plain ASCII */
cval = (unsigned)buff[i];
else if( (buff[i] & 0xe0) == 0xc0) /* two-byte UTF8 : code */
{ /* points U+80 to U+7FF */
cval = ((buff[i] & 0x1f) << 6) | (buff[i + 1] & 0x3f);
i++;
}
else
{ /* three-byte UTF: U+800 to U+FFFF */
cval = ((buff[i] & 0x0f) << 12) | ((buff[i + 1] & 0x3f) << 6) | (buff[i + 2] & 0x3f);
if( (buff[i] & 0xf0) == 0xf0) /* Four-byte UTF: */
{ /* U+10000 and beyond (SMP) */
cval = (cval << 6) | (buff[i + 3] & 0x3f);
i++;
}
i += 2;
}
*tptr++ = cval;
*tptr++ = glyph_num;
n_references_found++;
}
qsort( unicode_info, n_references_found, 2 * sizeof( uint32_t),
_compare_unicode_info);
*unicode_info_size = n_references_found;
return( unicode_info);
}
static int _load_psf2( struct font_info *f, const uint8_t *buff, const long filelen)
{
struct psf2_header hdr;
if( buff[0] != PSF2_MAGIC0 || buff[1] != PSF2_MAGIC1
|| buff[2] != PSF2_MAGIC2 || buff[3] != PSF2_MAGIC3)
return( -1);
memcpy( &hdr, buff, sizeof( hdr));
f->font_type = 2;
f->n_glyphs = hdr.length;
f->headersize = hdr.headersize;
f->charsize = hdr.charsize;
f->height = hdr.height;
f->width = hdr.width;
f->glyphs = buff + f->headersize;
if( hdr.flags & PSF2_HAS_UNICODE_TABLE)
{
uint32_t start_of_unicode_data = hdr.headersize + hdr.length * hdr.charsize;
f->unicode_info = _decipher_psf2_unicode_table( buff + start_of_unicode_data,
(size_t)( filelen - start_of_unicode_data), &f->unicode_info_size);
}
else
{
f->unicode_info = NULL;
f->unicode_info_size = 0;
}
return( 0);
}
/* The 'vgafont' format is about as simple as you can get and
still call it a font format. There are 256 glyphs, each
(filesize/256) pixels high by eight pixels wide. Each byte
contains exactly one line of eight pixels. There are no magic
numbers, so I have adopted the expedient of saying that if
the buffer is a multiple of 256 bytes and 6 <= font height <= 20,
assume it's a vgafont. */
static int _load_vgafont( struct font_info *f, const uint8_t *buff, const long filelen)
{
if( filelen % 256 || filelen < 6 * 256 || filelen > 20 * 256)
return( -1);
else
{
f->unicode_info = NULL;
f->unicode_info_size = 0;
f->font_type = 0;
f->n_glyphs = 256;
f->headersize = 0;
f->charsize = f->height = (uint32_t)( filelen / 256);
f->width = 8;
f->glyphs = buff;
return( 0);
}
}
int load_psf_or_vgafont( struct font_info *f, const uint8_t *buff, const long filelen)
{
if( _load_psf1( f, buff, filelen) && _load_psf2( f, buff, filelen)
&& _load_vgafont( f, buff, filelen))
return( -1);
else
return( 0);
}
int find_psf_or_vgafont_glyph( struct font_info *f, const uint32_t unicode_point)
{
int rval = -1;
if( f->unicode_info)
{
const uint32_t *tptr = (const uint32_t *)bsearch( &unicode_point, f->unicode_info,
f->unicode_info_size, 2 * sizeof( uint32_t), _compare_unicode_info);
if( tptr)
rval = (int)( tptr[1]);
}
else if( unicode_point < f->n_glyphs)
rval = (int)unicode_point;
return( rval);
}