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#include "libbb.h"
33#include <sys/kd.h>
34
35#ifndef KDFONTOP
36# define KDFONTOP 0x4B72
37struct console_font_op {
38 unsigned op;
39 unsigned flags;
40 unsigned width, height;
41 unsigned charcount;
42 unsigned char *data;
43};
44# define KD_FONT_OP_SET 0
45# define KD_FONT_OP_GET 1
46# define KD_FONT_OP_SET_DEFAULT 2
47# define KD_FONT_OP_COPY 3
48# define KD_FONT_FLAG_OLD 0x80000000
49# define KD_FONT_FLAG_DONT_RECALC 1
50
51#endif
52
53
54enum {
55 PSF1_MAGIC0 = 0x36,
56 PSF1_MAGIC1 = 0x04,
57 PSF1_MODE512 = 0x01,
58 PSF1_MODEHASTAB = 0x02,
59 PSF1_MODEHASSEQ = 0x04,
60 PSF1_MAXMODE = 0x05,
61 PSF1_STARTSEQ = 0xfffe,
62 PSF1_SEPARATOR = 0xffff,
63};
64
65struct psf1_header {
66 unsigned char magic[2];
67 unsigned char mode;
68 unsigned char charsize;
69};
70
71#define psf1h(x) ((struct psf1_header*)(x))
72
73#define PSF1_MAGIC_OK(x) ( \
74 (x)->magic[0] == PSF1_MAGIC0 \
75 && (x)->magic[1] == PSF1_MAGIC1 \
76)
77
78#if ENABLE_FEATURE_LOADFONT_PSF2
79enum {
80 PSF2_MAGIC0 = 0x72,
81 PSF2_MAGIC1 = 0xb5,
82 PSF2_MAGIC2 = 0x4a,
83 PSF2_MAGIC3 = 0x86,
84 PSF2_HAS_UNICODE_TABLE = 0x01,
85 PSF2_MAXVERSION = 0,
86 PSF2_STARTSEQ = 0xfe,
87 PSF2_SEPARATOR = 0xff
88};
89
90struct psf2_header {
91 unsigned char magic[4];
92 unsigned int version;
93 unsigned int headersize;
94 unsigned int flags;
95 unsigned int length;
96 unsigned int charsize;
97 unsigned int height;
98 unsigned int width;
99};
100
101#define psf2h(x) ((struct psf2_header*)(x))
102
103#define PSF2_MAGIC_OK(x) ( \
104 (x)->magic[0] == PSF2_MAGIC0 \
105 && (x)->magic[1] == PSF2_MAGIC1 \
106 && (x)->magic[2] == PSF2_MAGIC2 \
107 && (x)->magic[3] == PSF2_MAGIC3 \
108)
109#endif
110
111
112static void do_loadfont(int fd, unsigned char *inbuf, int height, int width, int charsize, int fontsize)
113{
114 unsigned char *buf;
115 int charwidth = 32 * ((width+7)/8);
116 int i;
117
118 if (height < 1 || height > 32 || width < 1 || width > 32)
119 bb_error_msg_and_die("bad character size %dx%d", height, width);
120
121 buf = xzalloc(charwidth * ((fontsize < 128) ? 128 : fontsize));
122 for (i = 0; i < fontsize; i++)
123 memcpy(buf + (i*charwidth), inbuf + (i*charsize), charsize);
124
125 {
126 struct console_font_op cfo;
127 cfo.op = KD_FONT_OP_SET;
128 cfo.flags = 0;
129 cfo.width = width;
130 cfo.height = height;
131 cfo.charcount = fontsize;
132 cfo.data = buf;
133 xioctl(fd, KDFONTOP, &cfo);
134 }
135
136 free(buf);
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#if !ENABLE_FEATURE_LOADFONT_PSF2
164#define do_loadtable(fd, inbuf, tailsz, fontsize, psf2) \
165 do_loadtable(fd, inbuf, tailsz, fontsize)
166#endif
167static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize, int psf2)
168{
169#if !ENABLE_FEATURE_LOADFONT_PSF2
170
171# define psf2 0
172
173
174#endif
175 struct unimapinit advice;
176 struct unimapdesc ud;
177 struct unipair *up;
178 int ct = 0, maxct;
179 int glyph;
180 uint16_t unicode;
181
182 maxct = tailsz;
183 up = xmalloc(maxct * sizeof(*up));
184
185 for (glyph = 0; glyph < fontsize; glyph++) {
186 while (tailsz > 0) {
187 if (!psf2) {
188 unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0];
189 tailsz -= 2;
190 inbuf += 2;
191 if (unicode == PSF1_SEPARATOR)
192 break;
193 } else {
194#if ENABLE_FEATURE_LOADFONT_PSF2
195 --tailsz;
196 unicode = *inbuf++;
197 if (unicode == PSF2_SEPARATOR) {
198 break;
199 } else if (unicode == PSF2_STARTSEQ) {
200 bb_error_msg_and_die("unicode sequences not implemented");
201 } else if (unicode >= 0xC0) {
202 if (unicode >= 0xFC)
203 unicode &= 0x01, maxct = 5;
204 else if (unicode >= 0xF8)
205 unicode &= 0x03, maxct = 4;
206 else if (unicode >= 0xF0)
207 unicode &= 0x07, maxct = 3;
208 else if (unicode >= 0xE0)
209 unicode &= 0x0F, maxct = 2;
210 else
211 unicode &= 0x1F, maxct = 1;
212 do {
213 if (tailsz <= 0 || *inbuf < 0x80 || *inbuf > 0xBF)
214 bb_error_msg_and_die("illegal UTF-8 character");
215 --tailsz;
216 unicode = (unicode << 6) + (*inbuf++ & 0x3F);
217 } while (--maxct > 0);
218 } else if (unicode >= 0x80) {
219 bb_error_msg_and_die("illegal UTF-8 character");
220 }
221#else
222 return;
223#endif
224 }
225 up[ct].unicode = unicode;
226 up[ct].fontpos = glyph;
227 ct++;
228 }
229 }
230
231
232
233
234 advice.advised_hashsize = 0;
235 advice.advised_hashstep = 0;
236 advice.advised_hashlevel = 0;
237 xioctl(fd, PIO_UNIMAPCLR, &advice);
238 ud.entry_ct = ct;
239 ud.entries = up;
240 xioctl(fd, PIO_UNIMAP, &ud);
241#undef psf2
242}
243
244static void do_load(int fd, unsigned char *buffer, size_t len)
245{
246 int height;
247 int width = 8;
248 int charsize;
249 int fontsize = 256;
250 int has_table = 0;
251 unsigned char *font = buffer;
252 unsigned char *table;
253
254 if (len >= sizeof(struct psf1_header) && PSF1_MAGIC_OK(psf1h(buffer))) {
255 if (psf1h(buffer)->mode > PSF1_MAXMODE)
256 bb_error_msg_and_die("unsupported psf file mode");
257 if (psf1h(buffer)->mode & PSF1_MODE512)
258 fontsize = 512;
259 if (psf1h(buffer)->mode & PSF1_MODEHASTAB)
260 has_table = 1;
261 height = charsize = psf1h(buffer)->charsize;
262 font += sizeof(struct psf1_header);
263 } else
264#if ENABLE_FEATURE_LOADFONT_PSF2
265 if (len >= sizeof(struct psf2_header) && PSF2_MAGIC_OK(psf2h(buffer))) {
266 if (psf2h(buffer)->version > PSF2_MAXVERSION)
267 bb_error_msg_and_die("unsupported psf file version");
268 fontsize = psf2h(buffer)->length;
269 if (psf2h(buffer)->flags & PSF2_HAS_UNICODE_TABLE)
270 has_table = 2;
271 charsize = psf2h(buffer)->charsize;
272 height = psf2h(buffer)->height;
273 width = psf2h(buffer)->width;
274 font += psf2h(buffer)->headersize;
275 } else
276#endif
277#if ENABLE_FEATURE_LOADFONT_RAW
278 if (len == 9780) {
279 charsize = height = 16;
280 font += 40;
281 } else if ((len & 0377) == 0) {
282 charsize = height = len / 256;
283 } else
284#endif
285 {
286 bb_error_msg_and_die("input file: bad length or unsupported font type");
287 }
288
289#if !defined(PIO_FONTX) || defined(__sparc__)
290 if (fontsize != 256)
291 bb_error_msg_and_die("only fontsize 256 supported");
292#endif
293
294 table = font + fontsize * charsize;
295 buffer += len;
296
297 if (table > buffer || (!has_table && table != buffer))
298 bb_error_msg_and_die("input file: bad length");
299
300 do_loadfont(fd, font, height, width, charsize, fontsize);
301
302 if (has_table)
303 do_loadtable(fd, table, buffer - table, fontsize, has_table - 1);
304}
305
306
307#if ENABLE_LOADFONT
308int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
309int loadfont_main(int argc UNUSED_PARAM, char **argv)
310{
311 size_t len;
312 unsigned char *buffer;
313
314
315 opt_complementary = "=0";
316 getopt32(argv, "");
317
318
319
320
321
322
323 len = 32*1024;
324 buffer = xmalloc_read(STDIN_FILENO, &len);
325
326 if (!buffer)
327 bb_perror_msg_and_die("error reading input font");
328 do_load(get_console_fd_or_die(), buffer, len);
329
330 return EXIT_SUCCESS;
331}
332#endif
333
334#if ENABLE_SETFONT
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369#if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
370static int ctoi(char *s)
371{
372 if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0')
373 return s[1];
374
375 if (s[0] == 'U' && s[1] == '+') {
376 s[0] = '0';
377 s[1] = 'x';
378 }
379 if (!isdigit(s[0]))
380 return -1;
381 return xstrtoul(s, 0);
382}
383#endif
384
385int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
386int setfont_main(int argc UNUSED_PARAM, char **argv)
387{
388 size_t len;
389 unsigned opts;
390 int fd;
391 unsigned char *buffer;
392 char *mapfilename;
393 const char *tty_name = CURRENT_TTY;
394
395 opt_complementary = "=1";
396 opts = getopt32(argv, "m:C:", &mapfilename, &tty_name);
397 argv += optind;
398
399 fd = xopen_nonblocking(tty_name);
400
401 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) {
402 if (*argv[0] != '/') {
403
404 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consolefonts");
405 }
406 }
407
408 len = 32*1024;
409 buffer = xmalloc_open_zipped_read_close(*argv, &len);
410 if (!buffer)
411 bb_simple_perror_msg_and_die(*argv);
412 do_load(fd, buffer, len);
413
414
415 if (opts & 1) {
416 unsigned mode = PIO_SCRNMAP;
417 void *map;
418
419 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) {
420 if (mapfilename[0] != '/') {
421
422 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consoletrans");
423 }
424 }
425
426 map = xmalloc_open_zipped_read_close(mapfilename, &len);
427 if (!map)
428 bb_simple_perror_msg_and_die(mapfilename);
429
430 if (len == E_TABSZ || len == 2*E_TABSZ) {
431 if (len == 2*E_TABSZ)
432 mode = PIO_UNISCRNMAP;
433 }
434#if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
435
436
437
438
439
440 else {
441 int i;
442 char *token[2];
443 parser_t *parser;
444
445 if (ENABLE_FEATURE_CLEAN_UP)
446 free(map);
447 map = xmalloc(E_TABSZ * sizeof(unsigned short));
448
449#define unicodes ((unsigned short *)map)
450
451 for (i = 0; i < E_TABSZ; i++)
452 unicodes[i] = 0xf000 + i;
453
454 parser = config_open(mapfilename);
455 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) {
456
457 int a = ctoi(token[0]);
458 int b = ctoi(token[1]);
459 if (a < 0 || a >= E_TABSZ
460 || b < 0 || b > 65535
461 ) {
462 bb_error_msg_and_die("map format");
463 }
464
465 unicodes[a] = b;
466
467 if (b > 255)
468 mode = PIO_UNISCRNMAP;
469 }
470 if (ENABLE_FEATURE_CLEAN_UP)
471 config_close(parser);
472
473 if (mode != PIO_UNISCRNMAP) {
474#define asciis ((unsigned char *)map)
475 for (i = 0; i < E_TABSZ; i++)
476 asciis[i] = unicodes[i];
477#undef asciis
478 }
479#undef unicodes
480 }
481#endif
482
483
484 xioctl(fd, mode, map);
485
486 if (ENABLE_FEATURE_CLEAN_UP)
487 free(map);
488 }
489
490 return EXIT_SUCCESS;
491}
492#endif
493