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