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