Ticket #2337: listpsf.c

File listpsf.c, 8.1 KB (added by ken@…, 16 years ago)
Line 
1/* list a psf font, to see what the mapping is (if present).
2 * Works on amd64, ppc, ppc64 so I guess it is endian-safe.
3 * Output to stderr is very noisy, particuarly for type 2, but then it has
4 * only been tested for 2 and 3 byte UTF-8 sequences so far, so it could
5 * still fail.
6 * © 2007 Ken Moffat <ken at linuxfromscratch dot org>
7 * LICENSE: GPL v2 or, at your choice, any later version.
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#define _GNU_SOURCE /* we want the gnu version of basename */
13#include <string.h>
14#include <utils.h>
15/* for int32_t le32_to_cpu(int32_t x)
16 * and le16_to_cpu */
17#include <sys/types.h>
18
19FILE *fp;
20unsigned char first4[4];
21/* type 2 header has an extra 7 le32 fields */
22unsigned char type2[28];
23unsigned char *p;
24unsigned char mode, height;
25unsigned char last; /* for type2, which holds UTF-8 separated by xff, last byte we have read*/
26int bytes_per_char;
27int fontsize, headersize;
28int psftype=0;
29int table;
30unsigned char *filename, *fullname;
31unsigned char *prog;
32
33/* from psf.h in kbd */
34#define PSF1_MAGIC0 0x36
35#define PSF1_MAGIC1 0x04
36
37#define PSF1_MODE512 0x01
38#define PSF1_MODEHASTAB 0x02
39#define PSF1_MODEHASSEQ 0x04
40#define PSF1_MAXMODE 0x05
41
42#define PSF2_MAGIC0 0x72
43#define PSF2_MAGIC1 0xb5
44#define PSF2_MAGIC2 0x4a
45#define PSF2_MAGIC3 0x86
46
47unsigned int decode(unsigned char first, int num){
48/* for ascii (num==1) c is already the value, just need to copy it to u.
49 * otherwise use an array of 6 chars, put c at [0] and read the rest
50 * for each of the rest, if it doesn't start 10 it is bad UTF-8, so range is
51 * 80 to bf. Then, decode it.
52 *
53 */
54
55 unsigned char bytes[6],c;
56 unsigned int decoded;
57 int i,j;
58 if (num==1) {
59 decoded=first;
60 return decoded;
61 }
62 bytes[0]=c;
63 for (j=1;j<num;j++) {
64 /* read one byte, and validate it as a trailing byte */
65 i=fread(&bytes[j], 1, 1, fp);
66 if(i!=1) {
67 fprintf(stderr, "file i/o error (truncated table) at %#04x\n", table);
68 exit(1);
69 }
70 last=bytes[j];
71 if ( bytes[j]<0x80 ) {
72 fprintf(stderr, "invalid UTF-8 trailing byte %02x at sequence %d\n",
73 bytes[j], j);
74 exit(1);
75 }
76 if ( bytes[j]>0xbf ) {
77 fprintf(stderr, "invalid UTF-8 trailing byte %02x at sequence %d\n",
78 bytes[j], j);
79 exit(1);
80 }
81 fprintf(stderr,"successful read of %02x at sequence%d\n", bytes[j], j);
82 }
83 /* ok, we have the unicode in bytes, need to decode it.
84 * assume the result will fit into 32 bits because fe and ff are special
85 */
86 /* we already analysed the first byte, to get num:
87 * two 110..... c0-df
88 * three 1110.... e0-ef
89 * four 11110... f0-f7
90 * five 111110.. f8-fb
91 * six 1111110. fc-fd
92 */
93 if (first<0xe0) decoded=(first & 0x1f);
94 else if(first<0xf0) decoded=(first & 0x0f);
95 else if(first<0xf8) decoded=(first & 0x07);
96 else if(first<0xfc) decoded=(first & 0x03);
97 else decoded=(first & 0x01);
98
99 /* for remaining bytes, shift decoded left by 6,
100 * and the byte with 0x3f to drop initial 'b10',
101 * add the result to decoded.
102 */
103 for(j=1;j<num;j++) {
104 fprintf(stderr,"decoded was %04x and byte is %02x\n",decoded,c);
105 decoded=(decoded <<6);
106 c=(bytes[j] & 0x3f);
107 decoded=decoded+c;
108 fprintf(stderr,"decoded now %04x\n",decoded);
109 }
110 return decoded;
111
112}
113
114int openpsf(char *filename) {
115 int bytes;
116 int i, *iptr;
117 unsigned char c; int count;
118 /* open it here for reading */
119 fprintf(stderr,"Trying to open %s\n", fullname);
120 fp=fopen(fullname, "r");
121 if (fp == NULL) {
122 fprintf(stderr, "file open failed for %s\n", fullname);
123 exit(1);
124 }
125 fprintf(stderr, "it exists\n");
126 /* now check that it really is a psf, and set the details */
127 bytes=fread(first4, 1, 4, fp);
128 if (bytes != 4) {
129 fprintf(stderr, "failed to read first 4 bytes of header\n");
130 exit(1);
131 }
132 if( (first4[0]==PSF1_MAGIC0) && (first4[1]==PSF1_MAGIC1) ) {
133 fprintf(stderr,"it is type 1\n");
134 psftype=1;
135 mode=first4[2];
136 height=first4[3];
137 if(mode > 5) {
138 fprintf(stderr,"psf file with mode %02x is unsupported\n");
139 exit(1);
140 }
141 if (! (mode & 0x02)) {
142 fprintf(stderr,"psf1 file with mode %02x - no unicode table\n");
143 exit(1);
144 }
145 if (mode & 0x01) fontsize=512;
146 else fontsize=256;
147 fprintf(stderr,"font size is %d from mode %02x\n", fontsize, mode);
148 bytes_per_char=height;
149 fprintf(stderr,"bytes per character is %d\n", bytes_per_char);
150 headersize=4;
151 return psftype;
152 }
153 if( (first4[0]==PSF2_MAGIC0) && (first4[1]==PSF2_MAGIC1)
154 && (first4[2]==PSF2_MAGIC2) && (first4[3]==PSF2_MAGIC3) ) {
155 /* read the extended header */
156 bytes=fread(type2, 1, 28, fp);
157 if (bytes != 28) {
158 fprintf(stderr, "failed to read next 28 bytes of header\n");
159 exit(1);
160 }
161 iptr=&type2[4];
162 headersize=le32_to_cpu(*iptr);
163 fprintf(stderr,"header size is %d\n", headersize);
164
165 iptr=&type2[8];
166 if(! (le32_to_cpu(*iptr) & 0x01)) {
167 fprintf(stderr, "file mode is %02x, no unicode table\n",
168 le32_to_cpu(*iptr));
169 }
170 iptr=&type2[12];
171 fontsize=le32_to_cpu(*iptr);
172 fprintf(stderr, "file contains %d glyphs\n", fontsize);
173 iptr=&type2[16];
174 bytes_per_char=le32_to_cpu(*iptr);
175 fprintf(stderr, "bytes per character is %d\n", bytes_per_char);
176 psftype=2;
177 return psftype;
178 }
179 fprintf(stderr,"%s is not a psf file\n",fullname);
180 exit(1);
181}
182
183void usage() {
184 fprintf(stderr,"%s : list the contents of a unicode psf file\n", prog);
185 fprintf(stderr,"Usage: %s /path/to/file \n", prog);
186 exit(1);
187}
188
189void validate(int argc, char *argv[]) {
190 char *f, *p, *dirc, *basec, *dname, *bname;
191 p=argv[0];
192 fprintf(stderr, "running %s\n", p);
193 dirc=strdup(p);
194 basec=strdup(p);
195 dname=dirname(dirc);
196 bname=basename(basec);
197 prog=bname;
198 if (argc != 2) {
199 usage();
200 }
201 f=argv[1];
202 basec=strdup(f);
203 bname=basename(basec);
204 filename=bname;
205 fullname=f;
206}
207
208process_type1(int glyphnum) {
209 /* read values, if any, for one position */
210 u_int16_t i,u,r;
211 fprintf(stdout, "%#04x", glyphnum);
212 do {
213 i=fread(&r, 2, 1, fp);
214 if(i!=1) {
215 fprintf(stderr, "file i/o error (truncated table) at %#04x\n", table);
216 exit(1);
217 }
218 table+=2;
219 u=le16_to_cpu(r);
220 if(u!=0xFFFF) {
221 fprintf(stdout,"\tU+%04x",u);
222 }
223 } while (u!=0xFFFF);
224 fprintf(stdout, "\n");
225}
226
227process_type2(int glyphnum) {
228/* read values, if any, for one position:
229 * type 2 is composed of UTF-8, so detect xff, xfe, ascii
230 * or otherwise determine how many bytes are needed.
231 */
232 unsigned char c,k; int i,j; unsigned int u; int cnt=0;
233 fprintf(stdout, "%#04x", glyphnum);
234 do {
235 i=fread(&c, 1, 1, fp);
236 if(i!=1) {
237 fprintf(stderr, "file i/o error (truncated table) at %#04x\n", table);
238 exit(1);
239 }
240 last=c;
241 table++;
242 if(c==0xfe) {
243 fprintf(stderr,"Found combining sequence in type2\n");
244 exit(3);
245 }
246 if (c!=0xff) {
247 /* determine how many bytes in this UTF-8 character */
248 /* two 110..... c0-df
249 * three 1110.... e0-ef
250 * four 11110... f0-f7
251 * five 111110.. f8-fb
252 * six 1111110. fc-fd
253 * fe already assumed to start a combining sequence */
254 j=0;
255 if(c>0xfb) j=6;
256 else if(c>0xf7) j=5;
257 else if(c>0xef) j=4;
258 else if(c>0xdf) j=3;
259 else if(c>0xbf) j=2;
260 else if(c<0x80) j=1;
261 if (j==0) {
262 fprintf(stderr,"invalid UTF-8 byte %x\n",c);
263 exit(2);
264 }
265 fprintf(stderr,"decided that UTF-8 beginning %02x will be %d bytes\n", c,j);
266 u=decode(c,j);
267 fprintf(stdout,"\tU+%04x",u);
268 cnt++;
269 } else {
270 c=u;
271 fprintf(stdout,"\n");
272 }
273 } while (last != 0xff);
274 fprintf(stderr,"found %d mappings at position %02x\n", cnt, glyphnum);
275}
276
277main(int argc, char *argv[])
278{
279 int i,k;
280 validate(argc, argv);
281 psftype=openpsf(fullname);
282 if((psftype <1) || (psftype>2)) {
283 fprintf(stderr, "Internal error, openpsf returned type %d\n", psftype);
284 exit(1);
285 }
286 fprintf(stderr,"file opened, psftype is %d\n", psftype);
287
288 /* calculate where the table starts */
289 table=headersize+(fontsize*bytes_per_char);
290 fprintf(stderr,"table starts at offset %#04x\n",table);
291
292 /* position for reading at ts */
293 i=fseek(fp, table, SEEK_SET);
294 if(i!=0) {
295 fprintf(stderr, "Unable to seek to %#04x\n", table);
296 exit(1);
297 }
298
299 /* main loop to read the table - each pass is a new position
300 * any failure to read means table is short
301 */
302 fprintf(stdout, "Character mapping for type %d psf file %s\n\n", psftype, filename);
303 for(k=0;k<fontsize;k++) {
304 if(psftype==1) process_type1(k);
305 else process_type2(k);
306 }
307 exit(0);
308}
309