blob: 3c87df691e80383732da2547fc81b1c339e7ad2e [file] [log] [blame]
Daniel Stenberg8dda6682002-09-18 15:38:49 +00001/*
2 * Convert BDF files to C source and/or Rockbox .fnt file format
3 *
4 * Copyright (c) 2002 by Greg Haerr <greg@censoft.com>
5 *
6 * What fun it is converting font data...
7 *
8 * 09/17/02 Version 1.0
9 */
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <time.h>
14
15/* BEGIN font.h*/
16/* loadable font magic and version #*/
17#define VERSION "RB11"
18
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000019/* bitmap_t helper macros*/
20#define BITMAP_WORDS(x) (((x)+15)/16) /* image size in words*/
21#define BITMAP_BYTES(x) (BITMAP_WORDS(x)*sizeof(bitmap_t))
22#define BITMAP_BITSPERIMAGE (sizeof(bitmap_t) * 8)
23#define BITMAP_BITVALUE(n) ((bitmap_t) (((bitmap_t) 1) << (n)))
24#define BITMAP_FIRSTBIT (BITMAP_BITVALUE(BITMAP_BITSPERIMAGE - 1))
25#define BITMAP_TESTBIT(m) ((m) & BITMAP_FIRSTBIT)
26#define BITMAP_SHIFTBIT(m) ((bitmap_t) ((m) << 1))
Daniel Stenberg8dda6682002-09-18 15:38:49 +000027
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000028typedef unsigned short bitmap_t; /* bitmap image unit size*/
Daniel Stenberg8dda6682002-09-18 15:38:49 +000029
30/* builtin C-based proportional/fixed font structure */
31/* based on The Microwindows Project http://microwindows.org */
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000032struct font {
Daniel Stenberg8dda6682002-09-18 15:38:49 +000033 char * name; /* font name*/
34 int maxwidth; /* max width in pixels*/
35 int height; /* height in pixels*/
36 int ascent; /* ascent (baseline) height*/
37 int firstchar; /* first character in bitmap*/
38 int size; /* font size in glyphs*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000039 bitmap_t* bits; /* 16-bit right-padded bitmap data*/
40 unsigned long* offset; /* offsets into bitmap data*/
41 unsigned char* width; /* character widths or NULL if fixed*/
Daniel Stenberg8dda6682002-09-18 15:38:49 +000042 int defaultchar; /* default char (not glyph index)*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000043 long bits_size; /* # words of bitmap_t bits*/
Daniel Stenberg8dda6682002-09-18 15:38:49 +000044
45 /* unused by runtime system, read in by convbdf*/
46 char * facename; /* facename of font*/
47 char * copyright; /* copyright info for loadable fonts*/
48 int pixel_size;
49 int descent;
50 int fbbw, fbbh, fbbx, fbby;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000051};
Daniel Stenberg8dda6682002-09-18 15:38:49 +000052/* END font.h*/
53
54#define isprefix(buf,str) (!strncmp(buf, str, strlen(str)))
55#define strequal(s1,s2) (!strcmp(s1, s2))
56
57#define EXTRA 300 /* # bytes extra allocation for buggy .bdf files*/
58
59int gen_c = 0;
60int gen_fnt = 0;
61int gen_map = 1;
62int start_char = 0;
63int limit_char = 65535;
64int oflag = 0;
65char outfile[256];
66
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000067void usage(void);
68void getopts(int *pac, char ***pav);
69int convbdf(char *path);
Daniel Stenberg8dda6682002-09-18 15:38:49 +000070
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000071void free_font(struct font* pf);
72struct font* bdf_read_font(char *path);
73int bdf_read_header(FILE *fp, struct font* pf);
74int bdf_read_bitmaps(FILE *fp, struct font* pf);
75char * bdf_getline(FILE *fp, char *buf, int len);
76bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2);
Daniel Stenberg8dda6682002-09-18 15:38:49 +000077
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000078int gen_c_source(struct font* pf, char *path);
79int gen_fnt_file(struct font* pf, char *path);
Daniel Stenberg8dda6682002-09-18 15:38:49 +000080
81void
82usage(void)
83{
84 char help[] = {
85 "Usage: convbdf [options] [input-files]\n"
86 " convbdf [options] [-o output-file] [single-input-file]\n"
87 "Options:\n"
88 " -c Convert .bdf to .c source file\n"
89 " -f Convert .bdf to .fnt font file\n"
90 " -s N Start output at character encodings >= N\n"
91 " -l N Limit output to character encodings <= N\n"
92 " -n Don't generate bitmaps as comments in .c file\n"
93 };
94
95 fprintf(stderr, help);
96}
97
98/* parse command line options*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000099void getopts(int *pac, char ***pav)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000100{
101 char *p;
102 char **av;
103 int ac;
104
105 ac = *pac;
106 av = *pav;
107 while (ac > 0 && av[0][0] == '-') {
108 p = &av[0][1];
109 while( *p)
110 switch(*p++) {
111 case ' ': /* multiple -args on av[]*/
112 while( *p && *p == ' ')
113 p++;
114 if( *p++ != '-') /* next option must have dash*/
115 p = "";
116 break; /* proceed to next option*/
117 case 'c': /* generate .c output*/
118 gen_c = 1;
119 break;
120 case 'f': /* generate .fnt output*/
121 gen_fnt = 1;
122 break;
123 case 'n': /* don't gen bitmap comments*/
124 gen_map = 0;
125 break;
126 case 'o': /* set output file*/
127 oflag = 1;
128 if (*p) {
129 strcpy(outfile, p);
130 while (*p && *p != ' ')
131 p++;
132 }
133 else {
134 av++; ac--;
135 if (ac > 0)
136 strcpy(outfile, av[0]);
137 }
138 break;
139 case 'l': /* set encoding limit*/
140 if (*p) {
141 limit_char = atoi(p);
142 while (*p && *p != ' ')
143 p++;
144 }
145 else {
146 av++; ac--;
147 if (ac > 0)
148 limit_char = atoi(av[0]);
149 }
150 break;
151 case 's': /* set encoding start*/
152 if (*p) {
153 start_char = atoi(p);
154 while (*p && *p != ' ')
155 p++;
156 }
157 else {
158 av++; ac--;
159 if (ac > 0)
160 start_char = atoi(av[0]);
161 }
162 break;
163 default:
164 fprintf(stderr, "Unknown option ignored: %c\r\n", *(p-1));
165 }
166 ++av; --ac;
167 }
168 *pac = ac;
169 *pav = av;
170}
171
172/* remove directory prefix and file suffix from full path*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000173char *basename(char *path)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000174{
175 char *p, *b;
176 static char base[256];
177
178 /* remove prepended path and extension*/
179 b = path;
180 for (p=path; *p; ++p) {
181 if (*p == '/')
182 b = p + 1;
183 }
184 strcpy(base, b);
185 for (p=base; *p; ++p) {
186 if (*p == '.') {
187 *p = 0;
188 break;
189 }
190 }
191 return base;
192}
193
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000194int convbdf(char *path)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000195{
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000196 struct font* pf;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000197 int ret = 0;
198
199 pf = bdf_read_font(path);
200 if (!pf)
201 exit(1);
202
203 if (gen_c) {
204 if (!oflag) {
205 strcpy(outfile, basename(path));
206 strcat(outfile, ".c");
207 }
208 ret |= gen_c_source(pf, outfile);
209 }
210
211 if (gen_fnt) {
212 if (!oflag) {
213 strcpy(outfile, basename(path));
214 strcat(outfile, ".fnt");
215 }
216 ret |= gen_fnt_file(pf, outfile);
217 }
218
219 free_font(pf);
220 return ret;
221}
222
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000223int main(int ac, char **av)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000224{
225 int ret = 0;
226
227 ++av; --ac; /* skip av[0]*/
228 getopts(&ac, &av); /* read command line options*/
229
230 if (ac < 1 || (!gen_c && !gen_fnt)) {
231 usage();
232 exit(1);
233 }
234 if (oflag) {
235 if (ac > 1 || (gen_c && gen_fnt)) {
236 usage();
237 exit(1);
238 }
239 }
240
241 while (ac > 0) {
242 ret |= convbdf(av[0]);
243 ++av; --ac;
244 }
245
246 exit(ret);
247}
248
249/* free font structure*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000250void free_font(struct font* pf)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000251{
252 if (!pf)
253 return;
254 if (pf->name)
255 free(pf->name);
256 if (pf->facename)
257 free(pf->facename);
258 if (pf->bits)
259 free(pf->bits);
260 if (pf->offset)
261 free(pf->offset);
262 if (pf->width)
263 free(pf->width);
264 free(pf);
265}
266
267/* build incore structure from .bdf file*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000268struct font* bdf_read_font(char *path)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000269{
270 FILE *fp;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000271 struct font* pf;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000272
273 fp = fopen(path, "rb");
274 if (!fp) {
275 fprintf(stderr, "Error opening file: %s\n", path);
276 return NULL;
277 }
278
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000279 pf = (struct font*)calloc(1, sizeof(struct font));
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000280 if (!pf)
281 goto errout;
282
283 pf->name = strdup(basename(path));
284
285 if (!bdf_read_header(fp, pf)) {
286 fprintf(stderr, "Error reading font header\n");
287 goto errout;
288 }
289
290 if (!bdf_read_bitmaps(fp, pf)) {
291 fprintf(stderr, "Error reading font bitmaps\n");
292 goto errout;
293 }
294
295 fclose(fp);
296 return pf;
297
298 errout:
299 fclose(fp);
300 free_font(pf);
301 return NULL;
302}
303
304/* read bdf font header information, return 0 on error*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000305int bdf_read_header(FILE *fp, struct font* pf)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000306{
307 int encoding;
308 int nchars, maxwidth;
309 int firstchar = 65535;
310 int lastchar = -1;
311 char buf[256];
312 char facename[256];
313 char copyright[256];
314
315 /* set certain values to errors for later error checking*/
316 pf->defaultchar = -1;
317 pf->ascent = -1;
318 pf->descent = -1;
319
320 for (;;) {
321 if (!bdf_getline(fp, buf, sizeof(buf))) {
322 fprintf(stderr, "Error: EOF on file\n");
323 return 0;
324 }
325 if (isprefix(buf, "FONT ")) { /* not required*/
326 if (sscanf(buf, "FONT %[^\n]", facename) != 1) {
327 fprintf(stderr, "Error: bad 'FONT'\n");
328 return 0;
329 }
330 pf->facename = strdup(facename);
331 continue;
332 }
333 if (isprefix(buf, "COPYRIGHT ")) { /* not required*/
334 if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) {
335 fprintf(stderr, "Error: bad 'COPYRIGHT'\n");
336 return 0;
337 }
338 pf->copyright = strdup(copyright);
339 continue;
340 }
341 if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required*/
342 if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) {
343 fprintf(stderr, "Error: bad 'DEFAULT_CHAR'\n");
344 return 0;
345 }
346 }
347 if (isprefix(buf, "FONT_DESCENT ")) {
348 if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) {
349 fprintf(stderr, "Error: bad 'FONT_DESCENT'\n");
350 return 0;
351 }
352 continue;
353 }
354 if (isprefix(buf, "FONT_ASCENT ")) {
355 if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) {
356 fprintf(stderr, "Error: bad 'FONT_ASCENT'\n");
357 return 0;
358 }
359 continue;
360 }
361 if (isprefix(buf, "FONTBOUNDINGBOX ")) {
362 if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d",
363 &pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) {
364 fprintf(stderr, "Error: bad 'FONTBOUNDINGBOX'\n");
365 return 0;
366 }
367 continue;
368 }
369 if (isprefix(buf, "CHARS ")) {
370 if (sscanf(buf, "CHARS %d", &nchars) != 1) {
371 fprintf(stderr, "Error: bad 'CHARS'\n");
372 return 0;
373 }
374 continue;
375 }
376
377 /*
378 * Reading ENCODING is necessary to get firstchar/lastchar
379 * which is needed to pre-calculate our offset and widths
380 * array sizes.
381 */
382 if (isprefix(buf, "ENCODING ")) {
383 if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
384 fprintf(stderr, "Error: bad 'ENCODING'\n");
385 return 0;
386 }
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000387 if (encoding >= 0 &&
388 encoding <= limit_char &&
389 encoding >= start_char) {
390
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000391 if (firstchar > encoding)
392 firstchar = encoding;
393 if (lastchar < encoding)
394 lastchar = encoding;
395 }
396 continue;
397 }
398 if (strequal(buf, "ENDFONT"))
399 break;
400 }
401
402 /* calc font height*/
403 if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) {
404 fprintf(stderr, "Error: Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING\n");
405 return 0;
406 }
407 pf->height = pf->ascent + pf->descent;
408
409 /* calc default char*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000410 if (pf->defaultchar < 0 ||
411 pf->defaultchar < firstchar ||
412 pf->defaultchar > limit_char )
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000413 pf->defaultchar = firstchar;
414
415 /* calc font size (offset/width entries)*/
416 pf->firstchar = firstchar;
417 pf->size = lastchar - firstchar + 1;
418
419 /* use the font boundingbox to get initial maxwidth*/
420 /*maxwidth = pf->fbbw - pf->fbbx;*/
421 maxwidth = pf->fbbw;
422
423 /* initially use font maxwidth * height for bits allocation*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000424 pf->bits_size = nchars * BITMAP_WORDS(maxwidth) * pf->height;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000425
426 /* allocate bits, offset, and width arrays*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000427 pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t) + EXTRA);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000428 pf->offset = (unsigned long *)malloc(pf->size * sizeof(unsigned long));
429 pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
430
431 if (!pf->bits || !pf->offset || !pf->width) {
432 fprintf(stderr, "Error: no memory for font load\n");
433 return 0;
434 }
435
436 return 1;
437}
438
439/* read bdf font bitmaps, return 0 on error*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000440int bdf_read_bitmaps(FILE *fp, struct font* pf)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000441{
442 long ofs = 0;
443 int maxwidth = 0;
444 int i, k, encoding, width;
445 int bbw, bbh, bbx, bby;
446 int proportional = 0;
447 int encodetable = 0;
448 long l;
449 char buf[256];
450
451 /* reset file pointer*/
452 fseek(fp, 0L, SEEK_SET);
453
454 /* initially mark offsets as not used*/
455 for (i=0; i<pf->size; ++i)
456 pf->offset[i] = -1;
457
458 for (;;) {
459 if (!bdf_getline(fp, buf, sizeof(buf))) {
460 fprintf(stderr, "Error: EOF on file\n");
461 return 0;
462 }
463 if (isprefix(buf, "STARTCHAR")) {
464 encoding = width = bbw = bbh = bbx = bby = -1;
465 continue;
466 }
467 if (isprefix(buf, "ENCODING ")) {
468 if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
469 fprintf(stderr, "Error: bad 'ENCODING'\n");
470 return 0;
471 }
472 if (encoding < start_char || encoding > limit_char)
473 encoding = -1;
474 continue;
475 }
476 if (isprefix(buf, "DWIDTH ")) {
477 if (sscanf(buf, "DWIDTH %d", &width) != 1) {
478 fprintf(stderr, "Error: bad 'DWIDTH'\n");
479 return 0;
480 }
481 /* use font boundingbox width if DWIDTH <= 0*/
482 if (width <= 0)
483 width = pf->fbbw - pf->fbbx;
484 continue;
485 }
486 if (isprefix(buf, "BBX ")) {
487 if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) {
488 fprintf(stderr, "Error: bad 'BBX'\n");
489 return 0;
490 }
491 continue;
492 }
493 if (strequal(buf, "BITMAP")) {
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000494 bitmap_t *ch_bitmap = pf->bits + ofs;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000495 int ch_words;
496
497 if (encoding < 0)
498 continue;
499
500 /* set bits offset in encode map*/
501 if (pf->offset[encoding-pf->firstchar] != (unsigned long)-1) {
502 fprintf(stderr, "Error: duplicate encoding for character %d (0x%02x), ignoring duplicate\n",
503 encoding, encoding);
504 continue;
505 }
506 pf->offset[encoding-pf->firstchar] = ofs;
507
508 /* calc char width*/
509 if (bbx < 0) {
510 width -= bbx;
511 /*if (width > maxwidth)
512 width = maxwidth;*/
513 bbx = 0;
514 }
515 if (width > maxwidth)
516 maxwidth = width;
517 pf->width[encoding-pf->firstchar] = width;
518
519 /* clear bitmap*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000520 memset(ch_bitmap, 0, BITMAP_BYTES(width) * pf->height);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000521
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000522 ch_words = BITMAP_WORDS(width);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000523#define BM(row,col) (*(ch_bitmap + ((row)*ch_words) + (col)))
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000524#define BITMAP_NIBBLES (BITMAP_BITSPERIMAGE/4)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000525
526 /* read bitmaps*/
527 for (i=0; ; ++i) {
528 int hexnibbles;
529
530 if (!bdf_getline(fp, buf, sizeof(buf))) {
531 fprintf(stderr, "Error: EOF reading BITMAP data\n");
532 return 0;
533 }
534 if (isprefix(buf, "ENDCHAR"))
535 break;
536
537 hexnibbles = strlen(buf);
538 for (k=0; k<ch_words; ++k) {
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000539 int ndx = k * BITMAP_NIBBLES;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000540 int padnibbles = hexnibbles - ndx;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000541 bitmap_t value;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000542
543 if (padnibbles <= 0)
544 break;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000545 if (padnibbles >= BITMAP_NIBBLES)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000546 padnibbles = 0;
547
548 value = bdf_hexval((unsigned char *)buf,
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000549 ndx, ndx+BITMAP_NIBBLES-1-padnibbles);
550 value <<= padnibbles * BITMAP_NIBBLES;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000551
552 BM(pf->height - pf->descent - bby - bbh + i, k) |=
553 value >> bbx;
554 /* handle overflow into next image word*/
555 if (bbx) {
556 BM(pf->height - pf->descent - bby - bbh + i, k+1) =
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000557 value << (BITMAP_BITSPERIMAGE - bbx);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000558 }
559 }
560 }
561
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000562 ofs += BITMAP_WORDS(width) * pf->height;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000563
564 continue;
565 }
566 if (strequal(buf, "ENDFONT"))
567 break;
568 }
569
570 /* set max width*/
571 pf->maxwidth = maxwidth;
572
573 /* change unused offset/width values to default char values*/
574 for (i=0; i<pf->size; ++i) {
575 int defchar = pf->defaultchar - pf->firstchar;
576
577 if (pf->offset[i] == (unsigned long)-1) {
578 pf->offset[i] = pf->offset[defchar];
579 pf->width[i] = pf->width[defchar];
580 }
581 }
582
583 /* determine whether font doesn't require encode table*/
584 l = 0;
585 for (i=0; i<pf->size; ++i) {
586 if (pf->offset[i] != l) {
587 encodetable = 1;
588 break;
589 }
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000590 l += BITMAP_WORDS(pf->width[i]) * pf->height;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000591 }
592 if (!encodetable) {
593 free(pf->offset);
594 pf->offset = NULL;
595 }
596
597 /* determine whether font is fixed-width*/
598 for (i=0; i<pf->size; ++i) {
599 if (pf->width[i] != maxwidth) {
600 proportional = 1;
601 break;
602 }
603 }
604 if (!proportional) {
605 free(pf->width);
606 pf->width = NULL;
607 }
608
609 /* reallocate bits array to actual bits used*/
610 if (ofs < pf->bits_size) {
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000611 pf->bits = realloc(pf->bits, ofs * sizeof(bitmap_t));
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000612 pf->bits_size = ofs;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000613 }
614 else {
615 if (ofs > pf->bits_size) {
616 fprintf(stderr, "Warning: DWIDTH spec > max FONTBOUNDINGBOX\n");
617 if (ofs > pf->bits_size+EXTRA) {
618 fprintf(stderr, "Error: Not enough bits initially allocated\n");
619 return 0;
620 }
621 pf->bits_size = ofs;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000622 }
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000623 }
624
625 return 1;
626}
627
628/* read the next non-comment line, returns buf or NULL if EOF*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000629char *bdf_getline(FILE *fp, char *buf, int len)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000630{
631 int c;
632 char *b;
633
634 for (;;) {
635 b = buf;
636 while ((c = getc(fp)) != EOF) {
637 if (c == '\r')
638 continue;
639 if (c == '\n')
640 break;
641 if (b - buf >= (len - 1))
642 break;
643 *b++ = c;
644 }
645 *b = '\0';
Björn Stenberg55e25b12002-09-20 10:20:13 +0000646 if (c == EOF && b == buf)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000647 return NULL;
648 if (b != buf && !isprefix(buf, "COMMENT"))
649 break;
650 }
651 return buf;
652}
653
654/* return hex value of portion of buffer*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000655bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000656{
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000657 bitmap_t val = 0;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000658 int i, c;
659
660 for (i=ndx1; i<=ndx2; ++i) {
661 c = buf[i];
662 if (c >= '0' && c <= '9')
663 c -= '0';
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000664 else
665 if (c >= 'A' && c <= 'F')
666 c = c - 'A' + 10;
667 else
668 if (c >= 'a' && c <= 'f')
669 c = c - 'a' + 10;
670 else
671 c = 0;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000672 val = (val << 4) | c;
673 }
674 return val;
675}
676
677/* generate C source from in-core font*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000678int gen_c_source(struct font* pf, char *path)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000679{
680 FILE *ofp;
681 int i;
682 int did_defaultchar = 0;
683 int did_syncmsg = 0;
684 time_t t = time(0);
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000685 bitmap_t *ofs = pf->bits;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000686 char buf[256];
687 char obuf[256];
688 char hdr1[] = {
689 "/* Generated by convbdf on %s. */\n"
690 "#include \"font.h\"\n"
691 "\n"
692 "/* Font information:\n"
693 " name: %s\n"
694 " facename: %s\n"
695 " w x h: %dx%d\n"
696 " size: %d\n"
697 " ascent: %d\n"
698 " descent: %d\n"
699 " first char: %d (0x%02x)\n"
700 " last char: %d (0x%02x)\n"
701 " default char: %d (0x%02x)\n"
702 " proportional: %s\n"
703 " %s\n"
704 "*/\n"
705 "\n"
706 "/* Font character bitmap data. */\n"
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000707 "static bitmap_t _font_bits[] = {\n"
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000708 };
709
710 ofp = fopen(path, "w");
711 if (!ofp) {
712 fprintf(stderr, "Can't create %s\n", path);
713 return 1;
714 }
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000715
716 strcpy(buf, ctime(&t));
717 buf[strlen(buf)-1] = 0;
718
719 fprintf(ofp, hdr1, buf,
720 pf->name,
721 pf->facename? pf->facename: "",
722 pf->maxwidth, pf->height,
723 pf->size,
724 pf->ascent, pf->descent,
725 pf->firstchar, pf->firstchar,
726 pf->firstchar+pf->size-1, pf->firstchar+pf->size-1,
727 pf->defaultchar, pf->defaultchar,
728 pf->width? "yes": "no",
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000729 pf->copyright? pf->copyright: "");
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000730
731 /* generate bitmaps*/
732 for (i=0; i<pf->size; ++i) {
733 int x;
734 int bitcount = 0;
735 int width = pf->width ? pf->width[i] : pf->maxwidth;
736 int height = pf->height;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000737 bitmap_t *bits = pf->bits + (pf->offset? pf->offset[i]: (height * i));
738 bitmap_t bitvalue;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000739
740 /*
741 * Generate bitmap bits only if not this index isn't
742 * the default character in encode map, or the default
743 * character hasn't been generated yet.
744 */
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000745 if (pf->offset &&
746 (pf->offset[i] == pf->offset[pf->defaultchar-pf->firstchar])) {
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000747 if (did_defaultchar)
748 continue;
749 did_defaultchar = 1;
750 }
751
752 fprintf(ofp, "\n/* Character %d (0x%02x):\n width %d",
753 i+pf->firstchar, i+pf->firstchar, width);
754
755 if (gen_map) {
756 fprintf(ofp, "\n +");
757 for (x=0; x<width; ++x) fprintf(ofp, "-");
758 fprintf(ofp, "+\n");
759
760 x = 0;
761 while (height > 0) {
762 if (x == 0) fprintf(ofp, " |");
763
764 if (bitcount <= 0) {
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000765 bitcount = BITMAP_BITSPERIMAGE;
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000766 bitvalue = *bits++;
767 }
768
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000769 fprintf(ofp, BITMAP_TESTBIT(bitvalue)? "*": " ");
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000770
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000771 bitvalue = BITMAP_SHIFTBIT(bitvalue);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000772 --bitcount;
773 if (++x == width) {
774 fprintf(ofp, "|\n");
775 --height;
776 x = 0;
777 bitcount = 0;
778 }
779 }
780 fprintf(ofp, " +");
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000781 for (x=0; x<width; ++x)
782 fprintf(ofp, "-");
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000783 fprintf(ofp, "+ */\n");
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000784 }
785 else
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000786 fprintf(ofp, " */\n");
787
788 bits = pf->bits + (pf->offset? pf->offset[i]: (pf->height * i));
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000789 for (x=BITMAP_WORDS(width)*pf->height; x>0; --x) {
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000790 fprintf(ofp, "0x%04x,\n", *bits);
791 if (!did_syncmsg && *bits++ != *ofs++) {
792 fprintf(stderr, "Warning: found encoding values in non-sorted order (not an error).\n");
793 did_syncmsg = 1;
794 }
795 }
796 }
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000797 fprintf(ofp, "};\n\n");
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000798
799 if (pf->offset) {
800 /* output offset table*/
801 fprintf(ofp, "/* Character->glyph mapping. */\n"
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000802 "static unsigned long _sysfont_offset[] = {\n");
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000803
804 for (i=0; i<pf->size; ++i)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000805 fprintf(ofp, " %ld,\t/* (0x%02x) */\n",
806 pf->offset[i], i+pf->firstchar);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000807 fprintf(ofp, "};\n\n");
808 }
809
810 /* output width table for proportional fonts*/
811 if (pf->width) {
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000812 fprintf(ofp, "/* Character width data. */\n"
813 "static unsigned char _sysfont_width[] = {\n");
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000814
815 for (i=0; i<pf->size; ++i)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000816 fprintf(ofp, " %d,\t/* (0x%02x) */\n",
817 pf->width[i], i+pf->firstchar);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000818 fprintf(ofp, "};\n\n");
819 }
820
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000821 /* output struct font struct*/
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000822 if (pf->offset)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000823 sprintf(obuf, "_sysfont_offset,");
824 else
825 sprintf(obuf, "0, /* no encode table*/");
826
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000827 if (pf->width)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000828 sprintf(buf, "_sysfont_width,");
829 else
830 sprintf(buf, "0, /* fixed width*/");
831
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000832 fprintf(ofp, "/* Exported structure definition. */\n"
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000833 "struct font sysfont = {\n"
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000834 " \"%s\",\n"
835 " %d,\n"
836 " %d,\n"
837 " %d,\n"
838 " %d,\n"
839 " %d,\n"
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000840 " _font_bits,\n"
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000841 " %s\n"
842 " %s\n"
843 " %d,\n"
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000844 " sizeof(_font_bits)/sizeof(bitmap_t),\n"
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000845 "};\n",
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000846 pf->name,
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000847 pf->maxwidth, pf->height,
848 pf->ascent,
849 pf->firstchar,
850 pf->size,
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000851 obuf,
852 buf,
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000853 pf->defaultchar);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000854
855 return 0;
856}
857
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000858static int writebyte(FILE *fp, unsigned char c)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000859{
860 return putc(c, fp) != EOF;
861}
862
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000863static int writeshort(FILE *fp, unsigned short s)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000864{
865 putc(s, fp);
866 return putc(s>>8, fp) != EOF;
867}
868
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000869static int writelong(FILE *fp, unsigned long l)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000870{
871 putc(l, fp);
872 putc(l>>8, fp);
873 putc(l>>16, fp);
874 return putc(l>>24, fp) != EOF;
875}
876
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000877static int writestr(FILE *fp, char *str, int count)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000878{
879 return fwrite(str, 1, count, fp) == count;
880}
881
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000882static int writestrpad(FILE *fp, char *str, int totlen)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000883{
884 int ret;
885
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000886 while (str && *str && totlen > 0) {
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000887 if (*str) {
888 ret = putc(*str++, fp);
889 --totlen;
890 }
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000891 }
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000892 while (--totlen >= 0)
893 ret = putc(' ', fp);
894 return ret;
895}
896
897/* generate .fnt format file from in-core font*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000898int gen_fnt_file(struct font* pf, char *path)
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000899{
900 FILE *ofp;
901 int i;
902
903 ofp = fopen(path, "wb");
904 if (!ofp) {
905 fprintf(stderr, "Can't create %s\n", path);
906 return 1;
907 }
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000908
909 /* write magic and version #*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000910 writestr(ofp, VERSION, 4);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000911
912 /* internal font name*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000913 writestrpad(ofp, pf->name, 64);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000914
915 /* copyright*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000916 writestrpad(ofp, pf->copyright, 256);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000917
918 /* font info*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000919 writeshort(ofp, pf->maxwidth);
920 writeshort(ofp, pf->height);
921 writeshort(ofp, pf->ascent);
922 writeshort(ofp, 0);
923 writelong(ofp, pf->firstchar);
924 writelong(ofp, pf->defaultchar);
925 writelong(ofp, pf->size);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000926
927 /* variable font data sizes*/
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000928 writelong(ofp, pf->bits_size); /* # words of bitmap_t*/
929 writelong(ofp, pf->offset? pf->size: 0); /* # longs of offset*/
930 writelong(ofp, pf->width? pf->size: 0); /* # bytes of width*/
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000931
932 /* variable font data*/
933 for (i=0; i<pf->bits_size; ++i)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000934 writeshort(ofp, pf->bits[i]);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000935 if (ftell(ofp) & 2)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000936 writeshort(ofp, 0); /* pad to 32-bit boundary*/
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000937
938 if (pf->offset)
939 for (i=0; i<pf->size; ++i)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000940 writelong(ofp, pf->offset[i]);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000941
942 if (pf->width)
943 for (i=0; i<pf->size; ++i)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000944 writebyte(ofp, pf->width[i]);
Daniel Stenberg8dda6682002-09-18 15:38:49 +0000945
946 fclose(ofp);
947 return 0;
948}
949
950/* -----------------------------------------------------------------
951 * local variables:
952 * eval: (load-file "../firmware/rockbox-mode.el")
953 * end:
954 */