diff options
author | Harald Becker <ralda@gmx.de> | 2010-02-21 13:10:26 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-02-21 13:10:26 +0100 |
commit | 8ce1dc03c1b2b61e51527b987579c09c991cc4b2 (patch) | |
tree | 45bfbf7c7c84b81a9797c636e8965be097e50f0a /console-tools/loadfont.c | |
parent | bef5711dab5b78dcaafb33a7f0071dfd90188fe1 (diff) | |
download | busybox-w32-8ce1dc03c1b2b61e51527b987579c09c991cc4b2.tar.gz busybox-w32-8ce1dc03c1b2b61e51527b987579c09c991cc4b2.tar.bz2 busybox-w32-8ce1dc03c1b2b61e51527b987579c09c991cc4b2.zip |
loadfont/setfont: optional PSF2 font support
Signed-off-by: Harald Becker <ralda@gmx.de>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'console-tools/loadfont.c')
-rw-r--r-- | console-tools/loadfont.c | 315 |
1 files changed, 207 insertions, 108 deletions
diff --git a/console-tools/loadfont.c b/console-tools/loadfont.c index e83347432..e51142c8e 100644 --- a/console-tools/loadfont.c +++ b/console-tools/loadfont.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <sys/kd.h> | 13 | #include <sys/kd.h> |
14 | 14 | ||
15 | #ifndef KDFONTOP | 15 | #ifndef KDFONTOP |
16 | #define KDFONTOP 0x4B72 | 16 | # define KDFONTOP 0x4B72 |
17 | struct console_font_op { | 17 | struct console_font_op { |
18 | unsigned op; /* KD_FONT_OP_* */ | 18 | unsigned op; /* KD_FONT_OP_* */ |
19 | unsigned flags; /* KD_FONT_FLAG_* */ | 19 | unsigned flags; /* KD_FONT_FLAG_* */ |
@@ -21,91 +21,137 @@ struct console_font_op { | |||
21 | unsigned charcount; | 21 | unsigned charcount; |
22 | unsigned char *data; /* font data with height fixed to 32 */ | 22 | unsigned char *data; /* font data with height fixed to 32 */ |
23 | }; | 23 | }; |
24 | 24 | # define KD_FONT_OP_SET 0 /* Set font */ | |
25 | #define KD_FONT_OP_SET 0 /* Set font */ | 25 | # define KD_FONT_OP_GET 1 /* Get font */ |
26 | #define KD_FONT_OP_GET 1 /* Get font */ | 26 | # 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, | 27 | # define KD_FONT_OP_COPY 3 /* Copy from another console */ |
28 | data points to name / NULL */ | 28 | # define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */ |
29 | #define KD_FONT_OP_COPY 3 /* Copy from another console */ | 29 | # define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */ |
30 | |||
31 | #define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */ | ||
32 | #define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */ | ||
33 | /* (Used internally for PIO_FONT support) */ | 30 | /* (Used internally for PIO_FONT support) */ |
34 | #endif /* KDFONTOP */ | 31 | #endif /* KDFONTOP */ |
35 | 32 | ||
36 | 33 | ||
37 | enum { | 34 | enum { |
38 | PSF_MAGIC1 = 0x36, | 35 | PSF1_MAGIC0 = 0x36, |
39 | PSF_MAGIC2 = 0x04, | 36 | PSF1_MAGIC1 = 0x04, |
40 | 37 | PSF1_MODE512 = 0x01, | |
41 | PSF_MODE512 = 0x01, | 38 | PSF1_MODEHASTAB = 0x02, |
42 | PSF_MODEHASTAB = 0x02, | 39 | PSF1_MODEHASSEQ = 0x04, |
43 | PSF_MAXMODE = 0x03, | 40 | PSF1_MAXMODE = 0x05, |
44 | PSF_SEPARATOR = 0xffff | 41 | PSF1_STARTSEQ = 0xfffe, |
42 | PSF1_SEPARATOR = 0xffff, | ||
45 | }; | 43 | }; |
46 | 44 | ||
47 | struct psf_header { | 45 | struct psf1_header { |
48 | unsigned char magic1, magic2; /* Magic number */ | 46 | unsigned char magic[2]; /* Magic number */ |
49 | unsigned char mode; /* PSF font mode */ | 47 | unsigned char mode; /* PSF font mode */ |
50 | unsigned char charsize; /* Character size */ | 48 | unsigned char charsize; /* Character size */ |
51 | }; | 49 | }; |
52 | 50 | ||
53 | #define PSF_MAGIC_OK(x) ((x)->magic1 == PSF_MAGIC1 && (x)->magic2 == PSF_MAGIC2) | 51 | #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 | #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 */ | ||
54 | 90 | ||
55 | static void do_loadfont(int fd, unsigned char *inbuf, int unit, int fontsize) | 91 | |
92 | static void do_loadfont(int fd, unsigned char *inbuf, int height, int width, int charsize, int fontsize) | ||
56 | { | 93 | { |
57 | char *buf; | 94 | unsigned char *buf; |
95 | int charwidth = 32 * ((width+7)/8); | ||
58 | int i; | 96 | int i; |
59 | 97 | ||
60 | if (unit < 1 || unit > 32) | 98 | if (height < 1 || height > 32 || width < 1 || width > 32) |
61 | bb_error_msg_and_die("bad character size %d", unit); | 99 | bb_error_msg_and_die("bad character size %dx%d", height, width); |
62 | 100 | ||
63 | buf = xzalloc(16 * 1024); | 101 | buf = xzalloc(charwidth * ((fontsize < 128) ? 128 : fontsize)); |
64 | for (i = 0; i < fontsize; i++) | 102 | for (i = 0; i < fontsize; i++) |
65 | memcpy(buf + (32 * i), inbuf + (unit * i), unit); | 103 | memcpy(buf + (i*charwidth), inbuf + (i*charsize), charsize); |
66 | 104 | ||
67 | { /* KDFONTOP */ | 105 | { /* KDFONTOP */ |
68 | struct console_font_op cfo; | 106 | struct console_font_op cfo; |
69 | |||
70 | cfo.op = KD_FONT_OP_SET; | 107 | cfo.op = KD_FONT_OP_SET; |
71 | cfo.flags = 0; | 108 | cfo.flags = 0; |
72 | cfo.width = 8; | 109 | cfo.width = width; |
73 | cfo.height = unit; | 110 | cfo.height = height; |
74 | cfo.charcount = fontsize; | 111 | cfo.charcount = fontsize; |
75 | cfo.data = (void*)buf; | 112 | cfo.data = buf; |
76 | #if 0 | ||
77 | if (!ioctl_or_perror(fd, KDFONTOP, &cfo, "KDFONTOP ioctl failed (will try PIO_FONTX)")) | ||
78 | goto ret; /* success */ | ||
79 | #else | ||
80 | xioctl(fd, KDFONTOP, &cfo); | 113 | xioctl(fd, KDFONTOP, &cfo); |
81 | #endif | ||
82 | } | 114 | } |
83 | 115 | ||
84 | #if 0 | ||
85 | /* These ones do not honour -C tty (they set font on current tty regardless) | ||
86 | * On x86, this distinction is visible on framebuffer consoles | ||
87 | * (regular character consoles may have only one shared font anyway) | ||
88 | */ | ||
89 | #if defined(PIO_FONTX) && !defined(__sparc__) | ||
90 | { | ||
91 | struct consolefontdesc cfd; | ||
92 | |||
93 | cfd.charcount = fontsize; | ||
94 | cfd.charheight = unit; | ||
95 | cfd.chardata = buf; | ||
96 | |||
97 | if (!ioctl_or_perror(fd, PIO_FONTX, &cfd, "PIO_FONTX ioctl failed (will try PIO_FONT)")) | ||
98 | goto ret; /* success */ | ||
99 | } | ||
100 | #endif | ||
101 | xioctl(fd, PIO_FONT, buf); | ||
102 | ret: | ||
103 | #endif /* 0 */ | ||
104 | free(buf); | 116 | free(buf); |
105 | } | 117 | } |
106 | 118 | ||
107 | static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize) | 119 | /* |
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) | ||
108 | { | 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 | ||
109 | struct unimapinit advice; | 155 | struct unimapinit advice; |
110 | struct unimapdesc ud; | 156 | struct unimapdesc ud; |
111 | struct unipair *up; | 157 | struct unipair *up; |
@@ -114,15 +160,48 @@ static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize) | |||
114 | uint16_t unicode; | 160 | uint16_t unicode; |
115 | 161 | ||
116 | maxct = tailsz; /* more than enough */ | 162 | maxct = tailsz; /* more than enough */ |
117 | up = xmalloc(maxct * sizeof(struct unipair)); | 163 | up = xmalloc(maxct * sizeof(*up)); |
118 | 164 | ||
119 | for (glyph = 0; glyph < fontsize; glyph++) { | 165 | for (glyph = 0; glyph < fontsize; glyph++) { |
120 | while (tailsz >= 2) { | 166 | while (tailsz > 0) { |
121 | unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0]; | 167 | if (!psf2) { /* PSF1 */ |
122 | tailsz -= 2; | 168 | unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0]; |
123 | inbuf += 2; | 169 | tailsz -= 2; |
124 | if (unicode == PSF_SEPARATOR) | 170 | inbuf += 2; |
125 | break; | 171 | 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 | } | ||
126 | up[ct].unicode = unicode; | 205 | up[ct].unicode = unicode; |
127 | up[ct].fontpos = glyph; | 206 | up[ct].fontpos = glyph; |
128 | ct++; | 207 | ct++; |
@@ -139,58 +218,78 @@ static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize) | |||
139 | ud.entry_ct = ct; | 218 | ud.entry_ct = ct; |
140 | ud.entries = up; | 219 | ud.entries = up; |
141 | xioctl(fd, PIO_UNIMAP, &ud); | 220 | xioctl(fd, PIO_UNIMAP, &ud); |
221 | #undef psf2 | ||
142 | } | 222 | } |
143 | 223 | ||
144 | static void do_load(int fd, struct psf_header *psfhdr, size_t len) | 224 | static void do_load(int fd, unsigned char *buffer, size_t len) |
145 | { | 225 | { |
146 | int unit; | 226 | int height; |
147 | int fontsize; | 227 | int width = 8; |
148 | int hastable; | 228 | int charsize; |
149 | unsigned head0, head = head; | 229 | int fontsize = 256; |
150 | 230 | int has_table = 0; | |
151 | /* test for psf first */ | 231 | unsigned char *font = buffer; |
152 | if (len >= sizeof(struct psf_header) && PSF_MAGIC_OK(psfhdr)) { | 232 | unsigned char *table; |
153 | if (psfhdr->mode > PSF_MAXMODE) | 233 | |
234 | if (len >= sizeof(struct psf1_header) && PSF1_MAGIC_OK(psf1h(buffer))) { | ||
235 | if (psf1h(buffer)->mode > PSF1_MAXMODE) | ||
154 | bb_error_msg_and_die("unsupported psf file mode"); | 236 | bb_error_msg_and_die("unsupported psf file mode"); |
155 | fontsize = ((psfhdr->mode & PSF_MODE512) ? 512 : 256); | 237 | if (psf1h(buffer)->mode & PSF1_MODE512) |
156 | #if !defined(PIO_FONTX) || defined(__sparc__) | 238 | fontsize = 512; |
157 | if (fontsize != 256) | 239 | if (psf1h(buffer)->mode & PSF1_MODEHASTAB) |
158 | bb_error_msg_and_die("only fontsize 256 supported"); | 240 | 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 | ||
159 | #endif | 256 | #endif |
160 | hastable = (psfhdr->mode & PSF_MODEHASTAB); | 257 | #if ENABLE_FEATURE_LOADFONT_RAW |
161 | unit = psfhdr->charsize; | 258 | if (len == 9780) { /* file with three code pages? */ |
162 | head0 = sizeof(struct psf_header); | 259 | charsize = height = 16; |
163 | 260 | font += 40; | |
164 | head = head0 + fontsize * unit; | 261 | } else if ((len & 0377) == 0) { /* bare font */ |
165 | if (head > len || (!hastable && head != len)) | 262 | charsize = height = len / 256; |
166 | bb_error_msg_and_die("input file: bad length"); | 263 | } else |
167 | } else { | 264 | #endif |
168 | /* file with three code pages? */ | 265 | { |
169 | if (len == 9780) { | 266 | bb_error_msg_and_die("input file: bad length or unsupported font type"); |
170 | head0 = 40; | ||
171 | unit = 16; | ||
172 | } else { | ||
173 | /* bare font */ | ||
174 | if (len & 0377) | ||
175 | bb_error_msg_and_die("input file: bad length"); | ||
176 | head0 = 0; | ||
177 | unit = len / 256; | ||
178 | } | ||
179 | fontsize = 256; | ||
180 | hastable = 0; | ||
181 | } | 267 | } |
182 | 268 | ||
183 | do_loadfont(fd, (unsigned char *)psfhdr + head0, unit, fontsize); | 269 | #if !defined(PIO_FONTX) || defined(__sparc__) |
184 | if (hastable) | 270 | if (fontsize != 256) |
185 | do_loadtable(fd, (unsigned char *)psfhdr + head, len - head, fontsize); | 271 | 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); | ||
186 | } | 284 | } |
187 | 285 | ||
286 | |||
188 | #if ENABLE_LOADFONT | 287 | #if ENABLE_LOADFONT |
189 | int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 288 | int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
190 | int loadfont_main(int argc UNUSED_PARAM, char **argv) | 289 | int loadfont_main(int argc UNUSED_PARAM, char **argv) |
191 | { | 290 | { |
192 | size_t len; | 291 | size_t len; |
193 | struct psf_header *psfhdr; | 292 | unsigned char *buffer; |
194 | 293 | ||
195 | // no arguments allowed! | 294 | // no arguments allowed! |
196 | opt_complementary = "=0"; | 295 | opt_complementary = "=0"; |
@@ -202,11 +301,11 @@ int loadfont_main(int argc UNUSED_PARAM, char **argv) | |||
202 | * just read the entire file. | 301 | * just read the entire file. |
203 | */ | 302 | */ |
204 | len = 32*1024; // can't be larger | 303 | len = 32*1024; // can't be larger |
205 | psfhdr = xmalloc_read(STDIN_FILENO, &len); | 304 | buffer = xmalloc_read(STDIN_FILENO, &len); |
206 | // xmalloc_open_zipped_read_close(filename, &len); | 305 | // xmalloc_open_zipped_read_close(filename, &len); |
207 | if (!psfhdr) | 306 | if (!buffer) |
208 | bb_perror_msg_and_die("error reading input font"); | 307 | bb_perror_msg_and_die("error reading input font"); |
209 | do_load(get_console_fd_or_die(), psfhdr, len); | 308 | do_load(get_console_fd_or_die(), buffer, len); |
210 | 309 | ||
211 | return EXIT_SUCCESS; | 310 | return EXIT_SUCCESS; |
212 | } | 311 | } |
@@ -269,7 +368,7 @@ int setfont_main(int argc UNUSED_PARAM, char **argv) | |||
269 | size_t len; | 368 | size_t len; |
270 | unsigned opts; | 369 | unsigned opts; |
271 | int fd; | 370 | int fd; |
272 | struct psf_header *psfhdr; | 371 | unsigned char *buffer; |
273 | char *mapfilename; | 372 | char *mapfilename; |
274 | const char *tty_name = CURRENT_TTY; | 373 | const char *tty_name = CURRENT_TTY; |
275 | 374 | ||
@@ -287,10 +386,10 @@ int setfont_main(int argc UNUSED_PARAM, char **argv) | |||
287 | } | 386 | } |
288 | // load font | 387 | // load font |
289 | len = 32*1024; // can't be larger | 388 | len = 32*1024; // can't be larger |
290 | psfhdr = xmalloc_open_zipped_read_close(*argv, &len); | 389 | buffer = xmalloc_open_zipped_read_close(*argv, &len); |
291 | if (!psfhdr) | 390 | if (!buffer) |
292 | bb_simple_perror_msg_and_die(*argv); | 391 | bb_simple_perror_msg_and_die(*argv); |
293 | do_load(fd, psfhdr, len); | 392 | do_load(fd, buffer, len); |
294 | 393 | ||
295 | // load the screen map, if any | 394 | // load the screen map, if any |
296 | if (opts & 1) { // -m | 395 | if (opts & 1) { // -m |