13 |
#include <sys/kd.h> |
#include <sys/kd.h> |
14 |
|
|
15 |
#ifndef KDFONTOP |
#ifndef KDFONTOP |
16 |
#define KDFONTOP 0x4B72 |
# define KDFONTOP 0x4B72 |
17 |
struct console_font_op { |
struct console_font_op { |
18 |
unsigned op; /* KD_FONT_OP_* */ |
unsigned op; /* KD_FONT_OP_* */ |
19 |
unsigned flags; /* KD_FONT_FLAG_* */ |
unsigned flags; /* KD_FONT_FLAG_* */ |
21 |
unsigned charcount; |
unsigned charcount; |
22 |
unsigned char *data; /* font data with height fixed to 32 */ |
unsigned char *data; /* font data with height fixed to 32 */ |
23 |
}; |
}; |
24 |
|
# define KD_FONT_OP_SET 0 /* Set font */ |
25 |
#define KD_FONT_OP_SET 0 /* Set font */ |
# define KD_FONT_OP_GET 1 /* Get font */ |
26 |
#define KD_FONT_OP_GET 1 /* Get font */ |
# define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default, data points to name / NULL */ |
27 |
#define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default, |
# define KD_FONT_OP_COPY 3 /* Copy from another console */ |
28 |
data points to name / NULL */ |
# define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */ |
29 |
#define KD_FONT_OP_COPY 3 /* Copy from another console */ |
# define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */ |
|
|
|
|
#define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */ |
|
|
#define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */ |
|
30 |
/* (Used internally for PIO_FONT support) */ |
/* (Used internally for PIO_FONT support) */ |
31 |
#endif /* KDFONTOP */ |
#endif /* KDFONTOP */ |
32 |
|
|
33 |
|
|
34 |
enum { |
enum { |
35 |
PSF_MAGIC1 = 0x36, |
PSF1_MAGIC0 = 0x36, |
36 |
PSF_MAGIC2 = 0x04, |
PSF1_MAGIC1 = 0x04, |
37 |
|
PSF1_MODE512 = 0x01, |
38 |
PSF_MODE512 = 0x01, |
PSF1_MODEHASTAB = 0x02, |
39 |
PSF_MODEHASTAB = 0x02, |
PSF1_MODEHASSEQ = 0x04, |
40 |
PSF_MAXMODE = 0x03, |
PSF1_MAXMODE = 0x05, |
41 |
PSF_SEPARATOR = 0xffff |
PSF1_STARTSEQ = 0xfffe, |
42 |
|
PSF1_SEPARATOR = 0xffff, |
43 |
}; |
}; |
44 |
|
|
45 |
struct psf_header { |
struct psf1_header { |
46 |
unsigned char magic1, magic2; /* Magic number */ |
unsigned char magic[2]; /* Magic number */ |
47 |
unsigned char mode; /* PSF font mode */ |
unsigned char mode; /* PSF font mode */ |
48 |
unsigned char charsize; /* Character size */ |
unsigned char charsize; /* Character size */ |
49 |
}; |
}; |
50 |
|
|
51 |
#define PSF_MAGIC_OK(x) ((x)->magic1 == PSF_MAGIC1 && (x)->magic2 == PSF_MAGIC2) |
#define psf1h(x) ((struct psf1_header*)(x)) |
52 |
|
|
53 |
|
#define PSF1_MAGIC_OK(x) ( \ |
54 |
|
(x)->magic[0] == PSF1_MAGIC0 \ |
55 |
|
&& (x)->magic[1] == PSF1_MAGIC1 \ |
56 |
|
) |
57 |
|
|
58 |
|
#if ENABLE_FEATURE_LOADFONT_PSF2 |
59 |
|
enum { |
60 |
|
PSF2_MAGIC0 = 0x72, |
61 |
|
PSF2_MAGIC1 = 0xb5, |
62 |
|
PSF2_MAGIC2 = 0x4a, |
63 |
|
PSF2_MAGIC3 = 0x86, |
64 |
|
PSF2_HAS_UNICODE_TABLE = 0x01, |
65 |
|
PSF2_MAXVERSION = 0, |
66 |
|
PSF2_STARTSEQ = 0xfe, |
67 |
|
PSF2_SEPARATOR = 0xff |
68 |
|
}; |
69 |
|
|
70 |
|
struct psf2_header { |
71 |
|
unsigned char magic[4]; |
72 |
|
unsigned int version; |
73 |
|
unsigned int headersize; /* offset of bitmaps in file */ |
74 |
|
unsigned int flags; |
75 |
|
unsigned int length; /* number of glyphs */ |
76 |
|
unsigned int charsize; /* number of bytes for each character */ |
77 |
|
unsigned int height; /* max dimensions of glyphs */ |
78 |
|
unsigned int width; /* charsize = height * ((width + 7) / 8) */ |
79 |
|
}; |
80 |
|
|
81 |
|
#define psf2h(x) ((struct psf2_header*)(x)) |
82 |
|
|
83 |
static void do_loadfont(int fd, unsigned char *inbuf, int unit, int fontsize) |
#define PSF2_MAGIC_OK(x) ( \ |
84 |
|
(x)->magic[0] == PSF2_MAGIC0 \ |
85 |
|
&& (x)->magic[1] == PSF2_MAGIC1 \ |
86 |
|
&& (x)->magic[2] == PSF2_MAGIC2 \ |
87 |
|
&& (x)->magic[3] == PSF2_MAGIC3 \ |
88 |
|
) |
89 |
|
#endif /* ENABLE_FEATURE_LOADFONT_PSF2 */ |
90 |
|
|
91 |
|
|
92 |
|
static void do_loadfont(int fd, unsigned char *inbuf, int height, int width, int charsize, int fontsize) |
93 |
{ |
{ |
94 |
char *buf; |
unsigned char *buf; |
95 |
|
int charwidth = 32 * ((width+7)/8); |
96 |
int i; |
int i; |
97 |
|
|
98 |
if (unit < 1 || unit > 32) |
if (height < 1 || height > 32 || width < 1 || width > 32) |
99 |
bb_error_msg_and_die("bad character size %d", unit); |
bb_error_msg_and_die("bad character size %dx%d", height, width); |
100 |
|
|
101 |
buf = xzalloc(16 * 1024); |
buf = xzalloc(charwidth * ((fontsize < 128) ? 128 : fontsize)); |
102 |
for (i = 0; i < fontsize; i++) |
for (i = 0; i < fontsize; i++) |
103 |
memcpy(buf + (32 * i), inbuf + (unit * i), unit); |
memcpy(buf + (i*charwidth), inbuf + (i*charsize), charsize); |
104 |
|
|
105 |
{ /* KDFONTOP */ |
{ /* KDFONTOP */ |
106 |
struct console_font_op cfo; |
struct console_font_op cfo; |
|
|
|
107 |
cfo.op = KD_FONT_OP_SET; |
cfo.op = KD_FONT_OP_SET; |
108 |
cfo.flags = 0; |
cfo.flags = 0; |
109 |
cfo.width = 8; |
cfo.width = width; |
110 |
cfo.height = unit; |
cfo.height = height; |
111 |
cfo.charcount = fontsize; |
cfo.charcount = fontsize; |
112 |
cfo.data = (void*)buf; |
cfo.data = buf; |
|
#if 0 |
|
|
if (!ioctl_or_perror(fd, KDFONTOP, &cfo, "KDFONTOP ioctl failed (will try PIO_FONTX)")) |
|
|
goto ret; /* success */ |
|
|
#else |
|
113 |
xioctl(fd, KDFONTOP, &cfo); |
xioctl(fd, KDFONTOP, &cfo); |
|
#endif |
|
114 |
} |
} |
115 |
|
|
|
#if 0 |
|
|
/* These ones do not honour -C tty (they set font on current tty regardless) |
|
|
* On x86, this distinction is visible on framebuffer consoles |
|
|
* (regular character consoles may have only one shared font anyway) |
|
|
*/ |
|
|
#if defined(PIO_FONTX) && !defined(__sparc__) |
|
|
{ |
|
|
struct consolefontdesc cfd; |
|
|
|
|
|
cfd.charcount = fontsize; |
|
|
cfd.charheight = unit; |
|
|
cfd.chardata = buf; |
|
|
|
|
|
if (!ioctl_or_perror(fd, PIO_FONTX, &cfd, "PIO_FONTX ioctl failed (will try PIO_FONT)")) |
|
|
goto ret; /* success */ |
|
|
} |
|
|
#endif |
|
|
xioctl(fd, PIO_FONT, buf); |
|
|
ret: |
|
|
#endif /* 0 */ |
|
116 |
free(buf); |
free(buf); |
117 |
} |
} |
118 |
|
|
119 |
static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize) |
/* |
120 |
|
* Format of the Unicode information: |
121 |
|
* |
122 |
|
* For each font position <uc>*<seq>*<term> |
123 |
|
* where <uc> is a 2-byte little endian Unicode value (PSF1) |
124 |
|
* or an UTF-8 coded value (PSF2), |
125 |
|
* <seq> = <ss><uc><uc>*, <ss> = psf1 ? 0xFFFE : 0xFE, |
126 |
|
* <term> = psf1 ? 0xFFFF : 0xFF. |
127 |
|
* and * denotes zero or more occurrences of the preceding item. |
128 |
|
* |
129 |
|
* Semantics: |
130 |
|
* The leading <uc>* part gives Unicode symbols that are all |
131 |
|
* represented by this font position. The following sequences |
132 |
|
* are sequences of Unicode symbols - probably a symbol |
133 |
|
* together with combining accents - also represented by |
134 |
|
* this font position. |
135 |
|
* |
136 |
|
* Example: |
137 |
|
* At the font position for a capital A-ring glyph, we |
138 |
|
* may have: |
139 |
|
* 00C5,212B,FFFE,0041,030A,FFFF |
140 |
|
* Some font positions may be described by sequences only, |
141 |
|
* namely when there is no precomposed Unicode value for the glyph. |
142 |
|
*/ |
143 |
|
#if !ENABLE_FEATURE_LOADFONT_PSF2 |
144 |
|
#define do_loadtable(fd, inbuf, tailsz, fontsize, psf2) \ |
145 |
|
do_loadtable(fd, inbuf, tailsz, fontsize) |
146 |
|
#endif |
147 |
|
static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize, int psf2) |
148 |
{ |
{ |
149 |
|
#if !ENABLE_FEATURE_LOADFONT_PSF2 |
150 |
|
/* gcc 4.3.1 code size: */ |
151 |
|
# define psf2 0 /* +0 bytes */ |
152 |
|
// const int psf2 = 0; /* +8 bytes */ |
153 |
|
// enum { psf2 = 0 }; /* +13 bytes */ |
154 |
|
#endif |
155 |
struct unimapinit advice; |
struct unimapinit advice; |
156 |
struct unimapdesc ud; |
struct unimapdesc ud; |
157 |
struct unipair *up; |
struct unipair *up; |
160 |
uint16_t unicode; |
uint16_t unicode; |
161 |
|
|
162 |
maxct = tailsz; /* more than enough */ |
maxct = tailsz; /* more than enough */ |
163 |
up = xmalloc(maxct * sizeof(struct unipair)); |
up = xmalloc(maxct * sizeof(*up)); |
164 |
|
|
165 |
for (glyph = 0; glyph < fontsize; glyph++) { |
for (glyph = 0; glyph < fontsize; glyph++) { |
166 |
while (tailsz >= 2) { |
while (tailsz > 0) { |
167 |
unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0]; |
if (!psf2) { /* PSF1 */ |
168 |
tailsz -= 2; |
unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0]; |
169 |
inbuf += 2; |
tailsz -= 2; |
170 |
if (unicode == PSF_SEPARATOR) |
inbuf += 2; |
171 |
break; |
if (unicode == PSF1_SEPARATOR) |
172 |
|
break; |
173 |
|
} else { /* PSF2 */ |
174 |
|
#if ENABLE_FEATURE_LOADFONT_PSF2 |
175 |
|
--tailsz; |
176 |
|
unicode = *inbuf++; |
177 |
|
if (unicode == PSF2_SEPARATOR) { |
178 |
|
break; |
179 |
|
} else if (unicode == PSF2_STARTSEQ) { |
180 |
|
bb_error_msg_and_die("unicode sequences not implemented"); |
181 |
|
} else if (unicode >= 0xC0) { |
182 |
|
if (unicode >= 0xFC) |
183 |
|
unicode &= 0x01, maxct = 5; |
184 |
|
else if (unicode >= 0xF8) |
185 |
|
unicode &= 0x03, maxct = 4; |
186 |
|
else if (unicode >= 0xF0) |
187 |
|
unicode &= 0x07, maxct = 3; |
188 |
|
else if (unicode >= 0xE0) |
189 |
|
unicode &= 0x0F, maxct = 2; |
190 |
|
else |
191 |
|
unicode &= 0x1F, maxct = 1; |
192 |
|
do { |
193 |
|
if (tailsz <= 0 || *inbuf < 0x80 || *inbuf > 0xBF) |
194 |
|
bb_error_msg_and_die("illegal UTF-8 character"); |
195 |
|
--tailsz; |
196 |
|
unicode = (unicode << 6) + (*inbuf++ & 0x3F); |
197 |
|
} while (--maxct > 0); |
198 |
|
} else if (unicode >= 0x80) { |
199 |
|
bb_error_msg_and_die("illegal UTF-8 character"); |
200 |
|
} |
201 |
|
#else |
202 |
|
return; |
203 |
|
#endif |
204 |
|
} |
205 |
up[ct].unicode = unicode; |
up[ct].unicode = unicode; |
206 |
up[ct].fontpos = glyph; |
up[ct].fontpos = glyph; |
207 |
ct++; |
ct++; |
218 |
ud.entry_ct = ct; |
ud.entry_ct = ct; |
219 |
ud.entries = up; |
ud.entries = up; |
220 |
xioctl(fd, PIO_UNIMAP, &ud); |
xioctl(fd, PIO_UNIMAP, &ud); |
221 |
|
#undef psf2 |
222 |
} |
} |
223 |
|
|
224 |
static void do_load(int fd, struct psf_header *psfhdr, size_t len) |
static void do_load(int fd, unsigned char *buffer, size_t len) |
225 |
{ |
{ |
226 |
int unit; |
int height; |
227 |
int fontsize; |
int width = 8; |
228 |
int hastable; |
int charsize; |
229 |
unsigned head0, head = head; |
int fontsize = 256; |
230 |
|
int has_table = 0; |
231 |
/* test for psf first */ |
unsigned char *font = buffer; |
232 |
if (len >= sizeof(struct psf_header) && PSF_MAGIC_OK(psfhdr)) { |
unsigned char *table; |
233 |
if (psfhdr->mode > PSF_MAXMODE) |
|
234 |
|
if (len >= sizeof(struct psf1_header) && PSF1_MAGIC_OK(psf1h(buffer))) { |
235 |
|
if (psf1h(buffer)->mode > PSF1_MAXMODE) |
236 |
bb_error_msg_and_die("unsupported psf file mode"); |
bb_error_msg_and_die("unsupported psf file mode"); |
237 |
fontsize = ((psfhdr->mode & PSF_MODE512) ? 512 : 256); |
if (psf1h(buffer)->mode & PSF1_MODE512) |
238 |
#if !defined(PIO_FONTX) || defined(__sparc__) |
fontsize = 512; |
239 |
if (fontsize != 256) |
if (psf1h(buffer)->mode & PSF1_MODEHASTAB) |
240 |
bb_error_msg_and_die("only fontsize 256 supported"); |
has_table = 1; |
241 |
|
height = charsize = psf1h(buffer)->charsize; |
242 |
|
font += sizeof(struct psf1_header); |
243 |
|
} else |
244 |
|
#if ENABLE_FEATURE_LOADFONT_PSF2 |
245 |
|
if (len >= sizeof(struct psf2_header) && PSF2_MAGIC_OK(psf2h(buffer))) { |
246 |
|
if (psf2h(buffer)->version > PSF2_MAXVERSION) |
247 |
|
bb_error_msg_and_die("unsupported psf file version"); |
248 |
|
fontsize = psf2h(buffer)->length; |
249 |
|
if (psf2h(buffer)->flags & PSF2_HAS_UNICODE_TABLE) |
250 |
|
has_table = 2; |
251 |
|
charsize = psf2h(buffer)->charsize; |
252 |
|
height = psf2h(buffer)->height; |
253 |
|
width = psf2h(buffer)->width; |
254 |
|
font += psf2h(buffer)->headersize; |
255 |
|
} else |
256 |
#endif |
#endif |
257 |
hastable = (psfhdr->mode & PSF_MODEHASTAB); |
#if ENABLE_FEATURE_LOADFONT_RAW |
258 |
unit = psfhdr->charsize; |
if (len == 9780) { /* file with three code pages? */ |
259 |
head0 = sizeof(struct psf_header); |
charsize = height = 16; |
260 |
|
font += 40; |
261 |
head = head0 + fontsize * unit; |
} else if ((len & 0377) == 0) { /* bare font */ |
262 |
if (head > len || (!hastable && head != len)) |
charsize = height = len / 256; |
263 |
bb_error_msg_and_die("input file: bad length"); |
} else |
264 |
} else { |
#endif |
265 |
/* file with three code pages? */ |
{ |
266 |
if (len == 9780) { |
bb_error_msg_and_die("input file: bad length or unsupported font type"); |
|
head0 = 40; |
|
|
unit = 16; |
|
|
} else { |
|
|
/* bare font */ |
|
|
if (len & 0377) |
|
|
bb_error_msg_and_die("input file: bad length"); |
|
|
head0 = 0; |
|
|
unit = len / 256; |
|
|
} |
|
|
fontsize = 256; |
|
|
hastable = 0; |
|
267 |
} |
} |
268 |
|
|
269 |
do_loadfont(fd, (unsigned char *)psfhdr + head0, unit, fontsize); |
#if !defined(PIO_FONTX) || defined(__sparc__) |
270 |
if (hastable) |
if (fontsize != 256) |
271 |
do_loadtable(fd, (unsigned char *)psfhdr + head, len - head, fontsize); |
bb_error_msg_and_die("only fontsize 256 supported"); |
272 |
|
#endif |
273 |
|
|
274 |
|
table = font + fontsize * charsize; |
275 |
|
buffer += len; |
276 |
|
|
277 |
|
if (table > buffer || (!has_table && table != buffer)) |
278 |
|
bb_error_msg_and_die("input file: bad length"); |
279 |
|
|
280 |
|
do_loadfont(fd, font, height, width, charsize, fontsize); |
281 |
|
|
282 |
|
if (has_table) |
283 |
|
do_loadtable(fd, table, buffer - table, fontsize, has_table - 1); |
284 |
} |
} |
285 |
|
|
286 |
|
|
287 |
#if ENABLE_LOADFONT |
#if ENABLE_LOADFONT |
288 |
int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
289 |
int loadfont_main(int argc UNUSED_PARAM, char **argv) |
int loadfont_main(int argc UNUSED_PARAM, char **argv) |
290 |
{ |
{ |
291 |
size_t len; |
size_t len; |
292 |
struct psf_header *psfhdr; |
unsigned char *buffer; |
293 |
|
|
294 |
// no arguments allowed! |
// no arguments allowed! |
295 |
opt_complementary = "=0"; |
opt_complementary = "=0"; |
301 |
* just read the entire file. |
* just read the entire file. |
302 |
*/ |
*/ |
303 |
len = 32*1024; // can't be larger |
len = 32*1024; // can't be larger |
304 |
psfhdr = xmalloc_read(STDIN_FILENO, &len); |
buffer = xmalloc_read(STDIN_FILENO, &len); |
305 |
// xmalloc_open_zipped_read_close(filename, &len); |
// xmalloc_open_zipped_read_close(filename, &len); |
306 |
if (!psfhdr) |
if (!buffer) |
307 |
bb_perror_msg_and_die("error reading input font"); |
bb_perror_msg_and_die("error reading input font"); |
308 |
do_load(get_console_fd_or_die(), psfhdr, len); |
do_load(get_console_fd_or_die(), buffer, len); |
309 |
|
|
310 |
return EXIT_SUCCESS; |
return EXIT_SUCCESS; |
311 |
} |
} |
368 |
size_t len; |
size_t len; |
369 |
unsigned opts; |
unsigned opts; |
370 |
int fd; |
int fd; |
371 |
struct psf_header *psfhdr; |
unsigned char *buffer; |
372 |
char *mapfilename; |
char *mapfilename; |
373 |
const char *tty_name = CURRENT_TTY; |
const char *tty_name = CURRENT_TTY; |
374 |
|
|
386 |
} |
} |
387 |
// load font |
// load font |
388 |
len = 32*1024; // can't be larger |
len = 32*1024; // can't be larger |
389 |
psfhdr = xmalloc_open_zipped_read_close(*argv, &len); |
buffer = xmalloc_open_zipped_read_close(*argv, &len); |
390 |
if (!psfhdr) |
if (!buffer) |
391 |
bb_simple_perror_msg_and_die(*argv); |
bb_simple_perror_msg_and_die(*argv); |
392 |
do_load(fd, psfhdr, len); |
do_load(fd, buffer, len); |
393 |
|
|
394 |
// load the screen map, if any |
// load the screen map, if any |
395 |
if (opts & 1) { // -m |
if (opts & 1) { // -m |