]> git.kernelconcepts.de Git - gbdfed.git/blob - bdffnt.c
Fixup several compile faults due to changes in recent distributions,
[gbdfed.git] / bdffnt.c
1 /*
2  * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22
23 #include "bdfP.h"
24
25 /**************************************************************************
26  *
27  * Executable header and font structures.
28  *
29  **************************************************************************/
30
31 typedef struct {
32     unsigned short id;
33     unsigned short count;
34     unsigned int reshandler;
35 } res_typeinfo_t;
36
37 typedef struct {
38     unsigned short offset;
39     unsigned short length;
40     unsigned short flags;
41     unsigned short id;
42     unsigned short handle;
43     unsigned short usage;
44 } res_nameinfo_t;
45
46 typedef struct {
47     unsigned short e_magic;
48     unsigned short e_cblp;
49     unsigned short e_cp;
50     unsigned short e_crlc;
51     unsigned short e_cparhdr;
52     unsigned short e_minalloc;
53     unsigned short e_maxalloc;
54     unsigned short e_ss;
55     unsigned short e_sp;
56     unsigned short e_csum;
57     unsigned short e_ip;
58     unsigned short e_cs;
59     unsigned short e_lfarlc;
60     unsigned short e_ovno;
61     unsigned short e_res[4];
62     unsigned short e_oemid;
63     unsigned short e_oeminfo;
64     unsigned short e_res2[10];
65     unsigned short e_lfanew;
66 } dos_exe_t;
67
68 typedef struct {
69     unsigned short ne_magic;
70     unsigned char  linker_version;
71     unsigned char  linker_revision;
72     unsigned short entry_tab_offset;
73     unsigned short entry_tab_length;
74     unsigned int  reserved1;
75     unsigned short format_flags;
76     unsigned short auto_data_seg;
77     unsigned short local_heap_length;
78     unsigned short stack_length;
79     unsigned short ip;
80     unsigned short cs;
81     unsigned short sp;
82     unsigned short ss;
83     unsigned short n_segment_tab;
84     unsigned short n_mod_ref_tab;
85     unsigned short nrname_tab_length;
86     unsigned short segment_tab_offset;
87     unsigned short resource_tab_offset;
88     unsigned short rname_tab_offset;
89     unsigned short moduleref_tab_offset;
90     unsigned short iname_tab_offset;
91     unsigned int  nrname_tab_offset;
92     unsigned short n_mov_entry_points;
93     unsigned short align_shift_count;
94     unsigned short n_resource_seg;
95     unsigned char  operating_system;
96     unsigned char  additional_flags;
97     unsigned short fastload_offset;
98     unsigned short fastload_length;
99     unsigned short reserved2;
100     unsigned short expect_version;
101 } win_exe_t;
102
103 typedef struct {
104     unsigned short dfVersion;
105     unsigned int  dfSize;
106     unsigned char  dfCopyright[60];
107     unsigned short dfType;
108     unsigned short dfPoints;
109     unsigned short dfVertRes;
110     unsigned short dfHorizRes;
111     unsigned short dfAscent;
112     unsigned short dfInternalLeading;
113     unsigned short dfExternalLeading;
114     unsigned char  dfItalic;
115     unsigned char  dfUnderline;
116     unsigned char  dfStrikeOut;
117     unsigned short dfWeight;
118     unsigned char  dfCharSet;
119     unsigned short dfPixWidth;
120     unsigned short dfPixHeight;
121     unsigned char  dfPitchAndFamily;
122     unsigned short dfAvgWidth;
123     unsigned short dfMaxWidth;
124     unsigned char  dfFirstChar;
125     unsigned char  dfLastChar;
126     unsigned char  dfDefaultChar;
127     unsigned char  dfBreakChar;
128     unsigned short dfWidthBytes;
129     unsigned int  dfDevice;
130     unsigned int  dfFace;
131     unsigned int  dfBitsPointer;
132     unsigned int  dfBitsOffset;
133     unsigned char  dfReserved;
134     unsigned int  dfFlags;
135     unsigned short dfAspace;
136     unsigned short dfBspace;
137     unsigned short dfCspace;
138     unsigned short dfColorPointer;
139     unsigned char  dfReserved1[4];
140 #if 0
141     unsigned int  dfColorPointer;
142     unsigned char  dfReserved1[16];
143 #endif
144 } fntinfo_t;
145
146 /*
147  * A structure used to load the font info data before transfering to the
148  * real font structure.
149  */
150 typedef struct {
151     unsigned char dfVersion[2];
152     unsigned char dfSize[4];
153     unsigned char dfCopyright[60];
154     unsigned char dfType[2];
155     unsigned char dfPoints[2];
156     unsigned char dfVertRes[2];
157     unsigned char dfHorizRes[2];
158     unsigned char dfAscent[2];
159     unsigned char dfInternalLeading[2];
160     unsigned char dfExternalLeading[2];
161     unsigned char dfItalic[1];
162     unsigned char dfUnderline[1];
163     unsigned char dfStrikeOut[1];
164     unsigned char dfWeight[2];
165     unsigned char dfCharSet[1];
166     unsigned char dfPixWidth[2];
167     unsigned char dfPixHeight[2];
168     unsigned char dfPitchAndFamily[1];
169     unsigned char dfAvgWidth[2];
170     unsigned char dfMaxWidth[2];
171     unsigned char dfFirstChar[1];
172     unsigned char dfLastChar[1];
173     unsigned char dfDefaultChar[1];
174     unsigned char dfBreakChar[1];
175     unsigned char dfWidthBytes[2];
176     unsigned char dfDevice[4];
177     unsigned char dfFace[4];
178     unsigned char dfBitsPointer[4];
179     unsigned char dfBitsOffset[4];
180     unsigned char dfReserved[1];
181     unsigned char dfFlags[4];
182     unsigned char dfAspace[2];
183     unsigned char dfBspace[2];
184     unsigned char dfCspace[2];
185 #if 0
186     unsigned char dfColorPointer[4];
187     unsigned char dfReserved1[16];
188 #endif
189     unsigned char dfColorPointer[2];
190     unsigned char dfReserved1[4];
191 } fishadow_t;
192
193 typedef struct {
194     unsigned int width;
195     unsigned int offset;
196 } chrinfo_t;
197
198 /*
199  * Structure used for opening FON/FNT fonts.  Tracks the list of offsets to
200  * the font or fonts in the file.
201  */
202 typedef struct _bdffnt_font_t {
203     FILE *in;
204     unsigned int *fonts;
205     unsigned int allocated;
206     unsigned int nfonts;
207     unsigned int first;
208
209     chrinfo_t *cinfo;
210     unsigned int cinfo_used;
211     unsigned int cinfo_size;
212
213     fntinfo_t info;
214 } _bdffnt_font_t;
215
216 /**************************************************************************
217  *
218  * Local macros and variables.
219  *
220  **************************************************************************/
221
222 /*
223  * Executable signatures.
224  */
225 #define DOS_SIG 0x5a4d
226 #define WIN_SIG 0x454e
227
228 /*
229  * Weight values.
230  */
231 #define BDFFNT_WEIGHT_DONTCARE   0
232 #define BDFFNT_WEIGHT_THIN       100
233 #define BDFFNT_WEIGHT_EXTRALIGHT 200
234 #define BDFFNT_WEIGHT_ULTRALIGHT 200
235 #define BDFFNT_WEIGHT_LIGHT      300
236 #define BDFFNT_WEIGHT_NORMAL     400
237 #define BDFFNT_WEIGHT_REGULAR    400
238 #define BDFFNT_WEIGHT_MEDIUM     500
239 #define BDFFNT_WEIGHT_SEMIBOLD   600
240 #define BDFFNT_WEIGHT_DEMIBOLD   600
241 #define BDFFNT_WEIGHT_BOLD       700
242 #define BDFFNT_WEIGHT_EXTRABOLD  800
243 #define BDFFNT_WEIGHT_ULTRABOLD  800
244 #define BDFFNT_WEIGHT_HEAVY      900
245 #define BDFFNT_WEIGHT_BLACK      900
246
247 /*
248  * Local structures to hold header info.
249  */
250 static dos_exe_t dos;
251 static win_exe_t win;
252
253 /**************************************************************************
254  *
255  * Support functions.
256  *
257  **************************************************************************/
258
259 static void
260 _bdffnt_endian_shorts(unsigned short *sp, unsigned int n)
261 {
262     for (; n > 0; n--, sp++)
263       *sp = ((*sp >> 8) & 0xff) |
264           (((*sp & 0xff) << 8) & 0xff00);
265 }
266
267 static void
268 _bdffnt_endian_ints(unsigned int *lp, unsigned int n)
269 {
270     for (; n > 0; n--, lp++)
271       *lp = (((*lp & 0xff) << 24) & 0xff000000) |
272           (((*lp >> 8) << 16) & 0xff0000) |
273           (((*lp >> 16) << 8) & 0xff00) |
274           ((*lp >> 24) & 0xff);
275 }
276
277 static unsigned short
278 _bdffnt_get_short(unsigned char *field)
279 {
280     int a = 0, b = 1;
281
282     return (field[a] & 0xff) | ((field[b] & 0xff) << 8);
283 }
284
285 static unsigned int
286 _bdffnt_get_int(unsigned char *field)
287 {
288     int a = 0, b = 1, c = 2, d = 3;
289
290     return (field[a] & 0xff) | ((field[b] & 0xff) << 8) |
291         ((field[c] & 0xff) << 16) | ((field[d] & 0xff) << 24);
292 }
293
294 /*
295  * This routine is called when the font header needs some fields adjusted for
296  * the endianess of the machine.
297  */
298 static void
299 _bdffnt_transfer_fntinfo(fntinfo_t *fi, fishadow_t *fis)
300 {
301     fi->dfVersion = _bdffnt_get_short(fis->dfVersion);
302     (void) memcpy(fi->dfCopyright, fis->dfCopyright, 60);
303     fi->dfSize = _bdffnt_get_int(fis->dfSize);
304     fi->dfType = _bdffnt_get_short(fis->dfType);
305     fi->dfPoints = _bdffnt_get_short(fis->dfPoints);
306     fi->dfVertRes = _bdffnt_get_short(fis->dfVertRes);
307     fi->dfHorizRes = _bdffnt_get_short(fis->dfHorizRes);
308     fi->dfAscent = _bdffnt_get_short(fis->dfAscent);
309     fi->dfInternalLeading = _bdffnt_get_short(fis->dfInternalLeading);
310     fi->dfExternalLeading = _bdffnt_get_short(fis->dfExternalLeading);
311     fi->dfItalic = fis->dfItalic[0];
312     fi->dfUnderline = fis->dfUnderline[0];
313     fi->dfStrikeOut = fis->dfStrikeOut[0];
314     fi->dfWeight = _bdffnt_get_short(fis->dfWeight);
315     fi->dfCharSet = fis->dfCharSet[0];
316     fi->dfPixWidth = _bdffnt_get_short(fis->dfPixWidth);
317     fi->dfPixHeight = _bdffnt_get_short(fis->dfPixHeight);
318     fi->dfPitchAndFamily = fis->dfPitchAndFamily[0];
319     fi->dfAvgWidth = _bdffnt_get_short(fis->dfAvgWidth);
320     fi->dfMaxWidth = _bdffnt_get_short(fis->dfMaxWidth);
321     fi->dfFirstChar = fis->dfFirstChar[0];
322     fi->dfLastChar = fis->dfLastChar[0];
323     fi->dfDefaultChar = fis->dfDefaultChar[0];
324     fi->dfBreakChar = fis->dfBreakChar[0];
325     fi->dfWidthBytes = _bdffnt_get_short(fis->dfWidthBytes);
326     fi->dfDevice = _bdffnt_get_int(fis->dfDevice);
327     fi->dfFace = _bdffnt_get_int(fis->dfFace);
328     fi->dfBitsPointer = _bdffnt_get_int(fis->dfBitsPointer);
329     fi->dfBitsOffset = _bdffnt_get_int(fis->dfBitsOffset);
330     fi->dfReserved = fis->dfReserved[0];
331     fi->dfFlags = _bdffnt_get_int(fis->dfFlags);
332     fi->dfAspace = _bdffnt_get_short(fis->dfAspace);
333     fi->dfBspace = _bdffnt_get_short(fis->dfBspace);
334     fi->dfCspace = _bdffnt_get_short(fis->dfCspace);
335 #if 0
336     fi->dfColorPointer = _bdffnt_get_int(fis->dfColorPointer);
337     (void) memcpy(fi->dfReserved1, fis->dfReserved1, 16);
338 #endif
339     fi->dfColorPointer = _bdffnt_get_short(fis->dfColorPointer);
340     (void) memcpy(fi->dfReserved1, fis->dfReserved1, 4);
341 }
342
343 static char *
344 _bdffnt_weight_name(unsigned short weight, int *len)
345 {
346     char *name;
347
348     if (weight == 0) {
349         name = "Medium";
350         *len = 6;
351     } else if (weight <= BDFFNT_WEIGHT_THIN) {
352         name = "Thin";
353         *len = 4;
354     } else if (weight <= BDFFNT_WEIGHT_ULTRALIGHT) {
355         name = "UltraLight";
356         *len = 10;
357     } else if (weight <= BDFFNT_WEIGHT_LIGHT) {
358         name = "Light";
359         *len = 5;
360     } else if (weight <= BDFFNT_WEIGHT_MEDIUM) {
361         name = "Medium";
362         *len = 6;
363     } else if (weight <= BDFFNT_WEIGHT_DEMIBOLD) {
364         name = "DemiBold";
365         *len = 8;
366     } else if (weight <= BDFFNT_WEIGHT_BOLD) {
367         name = "Bold";
368         *len = 4;
369     } else if (weight <= BDFFNT_WEIGHT_ULTRABOLD) {
370         name = "UltraBold";
371         *len = 9;
372     } else {
373         name = "Black";
374         *len = 5;
375     }
376     return name;
377 }
378
379 static char *
380 _bdffnt_cset_name(int cset, int *enc)
381 {
382     *enc = 0;
383     switch (cset) {
384       case 0: *enc = 1; return "ISO8859";
385       case 1: return "WinDefault";
386       case 2: return "Symbol";
387       case 128: return "JISX0208.1983";
388       case 129: return "MSHangul";
389       case 134: return "GB2312.1980";
390       case 136: return "Big5";
391       case 161: *enc = 1; return "CP1253";
392       case 162: *enc = 1; return "CP1254";
393       case 177: *enc = 1; return "CP1255";
394       case 178: *enc = 1; return "CP1256";
395       case 186: *enc = 1; return "CP1257";
396       case 204: *enc = 1; return "CP1251";
397       case 238: *enc = 1; return "CP1250";
398       case 255: return "OEM";
399     }
400     return "Unknown";
401 }
402
403 /**************************************************************************
404  *
405  * API.
406  *
407  **************************************************************************/
408
409 int
410 bdffnt_open_font(char *path, bdffnt_font_t *fnt)
411 {
412     unsigned short sshift, version;
413     int i;
414     unsigned int off;
415     FILE *in;
416     _bdffnt_font_t *f;
417     res_typeinfo_t rtype;
418     res_nameinfo_t ninfo;
419
420     if (path == 0 || *path == 0 || fnt == 0)
421       return 0;
422
423     if ((in = fopen(path, "r")) == 0)
424       return -1;
425
426     *fnt = 0;
427     f = (_bdffnt_font_t *) malloc(sizeof(_bdffnt_font_t));
428     (void) memset((char *) f, 0, sizeof(_bdffnt_font_t));
429
430     f->in = in;
431
432     if (fread((char *) &dos, 1, sizeof(dos_exe_t), in) != sizeof(dos_exe_t)) {
433         fclose(in);
434         free((char *) f);
435         return -1;
436     }
437
438     /*
439      * Endian everything if on a big-endian machine.
440      */
441     if (!bdf_little_endian())
442       _bdffnt_endian_shorts((unsigned short *) &dos,
443                             sizeof(dos_exe_t) / sizeof(unsigned short));
444
445     /*
446      * Check for exe signatures.
447      */
448     if (dos.e_magic == DOS_SIG) {
449         fseek(in, dos.e_lfanew, 0L);
450         if (fread((char *) &win, 1, sizeof(win_exe_t), in) !=
451             sizeof(win_exe_t)) {
452             fclose(in);
453             free((char *) f);
454             return -1;
455         }
456
457         /*
458          * Only endian the fields used.
459          */
460         if (!bdf_little_endian()) {
461             _bdffnt_endian_shorts(&win.ne_magic, 1);
462             _bdffnt_endian_shorts(&win.resource_tab_offset, 1);
463             _bdffnt_endian_shorts(&win.rname_tab_offset, 1);
464         }
465
466         /*
467          * This means the file is either NT 32-bit or something else.
468          */
469         if (win.ne_magic != WIN_SIG) {
470             fclose(in);
471             free((char *) f);
472             return -1;
473         }
474
475         /*
476          * Seek to the beginning of the resources.
477          */
478         off = dos.e_lfanew + win.resource_tab_offset;
479         fseek(in, off, 0L);
480         fread((char *) &sshift, 1, sizeof(unsigned short), in);
481         if (!bdf_little_endian())
482           _bdffnt_endian_shorts(&sshift, 1);
483
484         /*
485          * Search the resources for all the font resources.
486          */
487         if (fread((char *) &rtype, 1, sizeof(res_typeinfo_t), in) !=
488             sizeof(res_typeinfo_t)) {
489             fclose(in);
490             free((char *) f);
491             return -1;
492         }
493         while (rtype.id != 0) {
494             /*
495              * Change the endian order of the first two fields if necessary.
496              */
497             if (!bdf_little_endian())
498               _bdffnt_endian_shorts((unsigned short *) &rtype, 2);
499
500             if (rtype.id == 0x8008)
501               break;
502
503             /*
504              * Seek to the next resource entry and read it.
505              */
506             off = rtype.count * sizeof(res_nameinfo_t);
507             fseek(in, off, 1L);
508
509             if (fread((char *) &rtype, 1, sizeof(res_typeinfo_t), in) !=
510                 sizeof(res_typeinfo_t)) {
511                 fclose(in);
512                 free((char *) f);
513                 return -1;
514             }
515         }
516         if (rtype.id == 0x8008) {
517             /*
518              * Found a font resource, cycle through the entries.
519              */
520             for (i = 0; i < rtype.count; i++) {
521                 if (fread((char *) &ninfo, 1, sizeof(res_nameinfo_t), in) !=
522                     sizeof(res_nameinfo_t)) {
523                     fclose(in);
524                     if (f->allocated > 0)
525                       free((char *) f->fonts);
526                     free((char *) f);
527                     return -1;
528                 }
529
530                 if (!bdf_little_endian())
531                   _bdffnt_endian_shorts((unsigned short *) &ninfo,
532                                         sizeof(res_nameinfo_t) >> 1);
533
534                 /*
535                  * Check to make sure that the indicated offset is really a
536                  * valid font.
537                  */
538                 off = ftell(in);
539                 fseek(in, (ninfo.offset << sshift), 0L);
540                 fread((char *) &version, sizeof(unsigned short), 1, in);
541                 fseek(in, off, 0L);
542                 if (!bdf_little_endian())
543                   _bdffnt_endian_shorts(&version, 1);
544                 if (version != 0x200 && version != 0x300)
545                   continue;
546
547                 if (f->nfonts == 0)
548                   f->first = ninfo.offset << sshift;
549                 else {
550                     if (f->nfonts >= f->allocated) {
551                         if (f->allocated == 0)
552                           f->fonts = (unsigned int *)
553                               malloc(sizeof(unsigned int) << 3);
554                         else
555                           f->fonts = (unsigned int *)
556                               realloc((char *) f->fonts,
557                                       sizeof(unsigned int) *
558                                       (f->allocated + 8));
559                         f->allocated += 8;
560                     }
561                     f->fonts[0] = f->first;
562                     f->fonts[f->nfonts] = ninfo.offset << sshift;
563                 }
564                 f->nfonts++;
565             }
566         }
567     } else if (dos.e_magic == 0x200 || dos.e_magic == 0x300) {
568         /*
569          * Probably have a .FNT file.
570          */
571         f->first = ftell(in);
572         f->nfonts = 1;
573     } else
574       return -1;
575
576     if (f->nfonts == 0) {
577         /*
578          * If no fonts were loaded, free everything up.
579          */
580         free((char *) f);
581         return -1;
582     }
583     *fnt = f;
584     return 1;
585 }
586
587 void
588 bdffnt_close_font(bdffnt_font_t font)
589 {
590     if (font == 0)
591       return;
592
593     fclose(font->in);
594     if (font->cinfo_size > 0)
595       free((char *) font->cinfo);
596     if (font->allocated > 0)
597       free((char *) font->fonts);
598     free((char *) font);
599 }
600
601 int
602 bdffnt_font_count(bdffnt_font_t font)
603 {
604     return (font != 0) ? font->nfonts : 0;
605 }
606
607 int
608 bdffnt_get_copyright(bdffnt_font_t font, unsigned int fontID,
609                      unsigned char *string)
610 {
611     int off;
612     unsigned char *sp;
613     fishadow_t fi;
614
615     off = (font->nfonts == 1) ? font->first : font->fonts[fontID];
616     fseek(font->in, off, 0L);
617
618     if (fread((char *) &fi, 1, sizeof(fishadow_t), font->in) !=
619         sizeof(fishadow_t))
620       return -1;
621
622     for (sp = fi.dfCopyright; (*string = *sp); sp++, string++) ;
623     return sp - fi.dfCopyright;
624 }
625
626 int
627 bdffnt_get_facename(bdffnt_font_t font, unsigned int fontID, int for_xlfd,
628                     unsigned char *string)
629 {
630     int wlen, c;
631     int off;
632     unsigned char *sp, *wname;
633     fishadow_t fi;
634
635     if (font == 0 || fontID >= font->nfonts || string == 0)
636       return 0;
637
638     off = (font->nfonts == 1) ? font->first : font->fonts[fontID];
639     fseek(font->in, off, 0L);
640
641     if (fread((char *) &fi, 1, sizeof(fishadow_t), font->in) !=
642         sizeof(fishadow_t))
643       return -1;
644
645     _bdffnt_transfer_fntinfo(&font->info, &fi);
646
647     /*
648      * Seek to the location of the typeface name.
649      */
650     off = off + font->info.dfFace;
651     fseek(font->in, off, 0L);
652
653     /*
654      * Copy the typeface name into the parameter.
655      *
656      * stops when: -  == 0  -> end of string
657      *             -  <  0  -> end of file
658      */
659     sp = string;
660     while ((c = getc(font->in)) > 0) {
661         *sp = c;
662         if (for_xlfd && *sp == '-')
663           *sp = ' ';
664         sp++;
665     }
666     *sp = 0;
667
668     /*
669      * If the typeface name is not for an XLFD name, then append the style,
670      * weight and point size so the names will be informative.
671      */
672     if (!for_xlfd) {
673         *sp++ = ' ';
674         if (font->info.dfItalic & 1) {
675             (void) strcpy((char *) sp, "Italic ");
676             sp += 7;
677         }
678         wname = (unsigned char *) _bdffnt_weight_name(font->info.dfWeight,
679                                                       &wlen);
680         (void) strcpy((char *) sp, (char *) wname);
681         sp += wlen;
682         *sp++ = ' ';
683         sprintf((char *) sp, "%hdpt", font->info.dfPoints);
684         sp += strlen((char *) sp);
685     }
686
687     return sp - string;
688 }
689
690 int
691 bdffnt_char_count(bdffnt_font_t font, unsigned int fontID)
692 {
693     int off;
694     fishadow_t fi;
695
696     if (font == 0 || fontID >= font->nfonts)
697       return 0;
698
699     off = (font->nfonts == 1) ? font->first : font->fonts[fontID];
700     fseek(font->in, off, 0L);
701
702     if (fread((char *) &fi, 1, sizeof(fishadow_t), font->in) !=
703         sizeof(fishadow_t))
704       return -1;
705
706     _bdffnt_transfer_fntinfo(&font->info, &fi);
707
708     return (font->info.dfLastChar - font->info.dfFirstChar) + 1;
709 }
710
711 int
712 bdffnt_font_pointsize(bdffnt_font_t font, unsigned int fontID)
713 {
714     int off;
715     fishadow_t fi;
716
717     if (font == 0 || fontID >= font->nfonts)
718       return 0;
719
720     off = (font->nfonts == 1) ? font->first : font->fonts[fontID];
721     fseek(font->in, off, 0L);
722
723     if (fread((char *) &fi, 1, sizeof(fishadow_t), font->in) !=
724         sizeof(fishadow_t))
725       return -1;
726
727     _bdffnt_transfer_fntinfo(&font->info, &fi);
728
729     return font->info.dfPoints;
730 }
731
732 int
733 bdffnt_load_font(bdffnt_font_t font, unsigned int fontID,
734                  bdf_callback_t callback, void *data, bdf_font_t **out)
735 {
736     int x, y, i, nchars;
737     unsigned short tmp, bpr;
738     int off;
739     double swscale;
740     chrinfo_t *cp;
741     bdf_font_t *f;
742     bdf_glyph_t *gp;
743     char name[256];
744     bdf_property_t prop;
745     bdf_callback_struct_t cb;
746     fishadow_t fi;
747
748     if (font == 0 || fontID >= font->nfonts || out == 0)
749       return 0;
750
751     off = (font->nfonts == 1) ? font->first : font->fonts[fontID];
752     fseek(font->in, off, 0L);
753
754     if (fread((char *) &fi, 1, sizeof(fishadow_t), font->in) !=
755         sizeof(fishadow_t))
756       return -1;
757
758     _bdffnt_transfer_fntinfo(&font->info, &fi);
759
760     /*
761      * This cheap hack needed to get to the character info because the FNT
762      * docs don't mention that for Win 2.0 fonts, the header was a different
763      * size.  This may be the case for a version 3.* as well, but I have no
764      * version 3.* fonts to test with.
765      */
766     fseek(font->in, off + 118, 0L);
767
768     /*
769      * Determine how many character info records there are and make sure
770      * enough space is allocated in the font structure.
771      */
772     nchars = (font->info.dfLastChar - font->info.dfFirstChar) + 1;
773
774     if (font->cinfo_size < nchars) {
775         if (font->cinfo_size == 0)
776           font->cinfo = (chrinfo_t *) malloc(sizeof(chrinfo_t) * nchars);
777         else
778           font->cinfo = (chrinfo_t *) realloc((char *) font->cinfo,
779                                               sizeof(chrinfo_t) * nchars);
780         font->cinfo_size = nchars;
781     }
782     cp = font->cinfo;
783     for (i = 0, font->cinfo_used = 0; i < nchars; i++, cp++) {
784         fread((char *) &tmp, sizeof(unsigned short), 1, font->in);
785         if (!bdf_little_endian())
786           _bdffnt_endian_shorts(&tmp, 1);
787         cp->width = tmp;
788         if (font->info.dfVersion == 0x300) {
789             fread((char *) &cp->offset, sizeof(unsigned int), 1, font->in);
790             if (!bdf_little_endian())
791               _bdffnt_endian_ints(&cp->offset, 1);
792         } else {
793             fread((char *) &tmp, sizeof(unsigned short), 1, font->in);
794             if (!bdf_little_endian())
795               _bdffnt_endian_shorts(&tmp, 1);
796             cp->offset = tmp;
797         }
798     }
799
800     /*
801      * Create the font.
802      */
803     f = (bdf_font_t *) malloc(sizeof(bdf_font_t));
804     (void) memset((char *) f, 0, sizeof(bdf_font_t));
805
806     /*
807      * Set some defaults.
808      */
809     f->bpp = 1;
810     f->default_glyph = font->info.dfDefaultChar + font->info.dfFirstChar;
811     f->spacing = (font->info.dfFlags & 1) ? BDF_CHARCELL : BDF_PROPORTIONAL;
812     f->glyphs_size = nchars;
813     f->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * nchars);
814     (void) memset((char *) f->glyphs, 0, sizeof(bdf_glyph_t) * nchars);
815     f->point_size = font->info.dfPoints;
816     f->resolution_x = font->info.dfHorizRes;
817     f->resolution_y = font->info.dfVertRes;
818     f->font_ascent = font->info.dfAscent;
819     f->font_descent = f->font_ascent - font->info.dfPixHeight;
820
821     /*
822      * Set the font bounding box.
823      */
824     f->bbx.width = font->info.dfMaxWidth;
825     f->bbx.height = font->info.dfPixHeight;
826     f->bbx.ascent = font->info.dfAscent;
827     f->bbx.descent = f->bbx.height - f->bbx.ascent;
828     f->bbx.y_offset = -f->bbx.descent;
829     f->bbx.x_offset = 0;
830
831     if (f->spacing == BDF_CHARCELL)
832       f->monowidth = f->bbx.width;
833
834     /*
835      * Determine the SWIDTH scale factor.
836      */
837     swscale = ((double) f->resolution_y) * ((double) f->point_size);
838
839     /*
840      * Call the initial callback if one was provided.
841      */
842     if (callback != 0) {
843         cb.reason = BDF_LOAD_START;
844         cb.current = 0;
845         cb.total = nchars;
846         (*callback)(&cb, data);
847     }
848
849     /*
850      * Start collecting glyphs.
851      */
852     for (i = 0, cp = font->cinfo, gp = f->glyphs; i < nchars;
853          i++, cp++, gp++) {
854         /*
855          * Set the glyph encoding.
856          */
857         gp->encoding = font->info.dfFirstChar + i;
858
859         /*
860          * Set the glyph bounding box.
861          */
862         gp->bbx.width = gp->dwidth = cp->width;
863         gp->bbx.height = font->info.dfPixHeight;
864         gp->bbx.ascent = font->info.dfAscent;
865         gp->bbx.descent = gp->bbx.height - gp->bbx.ascent;
866         gp->bbx.y_offset = -gp->bbx.descent;
867         gp->bbx.x_offset = 0;
868         gp->swidth = (unsigned short)
869             (((double) gp->dwidth) * 72000.0) / swscale;
870
871         /*
872          * Allocate the glyph bitmap.
873          */
874         bpr = (cp->width + 7) >> 3;
875         gp->bytes = bpr * font->info.dfPixHeight;
876         gp->bitmap = (unsigned char *) malloc(gp->bytes);
877
878         /*
879          * Seek to the bitmap and read the bytes.
880          */
881         fseek(font->in, off + cp->offset, 0L);
882         if (bpr == 1)
883           fread((char *) gp->bitmap, gp->bytes, 1, font->in);
884         else {
885             /*
886              * Typical MS wierdness.  This awkward section is just to get the
887              * bytes in the right place.
888              */
889             for (x = 0; x < bpr; x++) {
890                 for (y = 0; y < gp->bbx.height; y++)
891                   gp->bitmap[(y * bpr) + x] = getc(font->in);
892             }
893         }
894
895         if (callback != 0) {
896             cb.reason = BDF_LOADING;
897             cb.current = i;
898             cb.total = nchars;
899             (*callback)(&cb, data);
900         }
901     }
902
903     /*
904      * Call the callback one more time to make sure the client knows the
905      * load is done.
906      */
907     if (callback != 0) {
908         cb.reason = BDF_LOADING;
909         cb.current = nchars;
910         cb.total = nchars;
911         (*callback)(&cb, data);
912     }
913
914     /*
915      * Set the number of glyphs used.
916      */
917     f->glyphs_used = gp - f->glyphs;
918
919     /*
920      * Add all the properties.
921      */
922     prop.name = "FOUNDRY";
923     prop.format = BDF_ATOM;
924     prop.value.atom = "Windows";
925     bdf_add_font_property(f, &prop);
926
927     i = bdffnt_get_facename(font, fontID, 1, (unsigned char *) name);
928     prop.name = "FAMILY_NAME";
929     prop.format = BDF_ATOM;
930     prop.value.atom = name;
931     bdf_add_font_property(f, &prop);
932
933     prop.name = "WEIGHT_NAME";
934     prop.format = BDF_ATOM;
935     prop.value.atom = _bdffnt_weight_name(font->info.dfWeight, &i);
936     bdf_add_font_property(f, &prop);
937
938     prop.name = "SLANT";
939     prop.format = BDF_ATOM;
940     if (font->info.dfItalic & 1)
941       prop.value.atom = "I";
942     else
943       prop.value.atom = "R";
944     bdf_add_font_property(f, &prop);
945
946     prop.name = "SETWIDTH_NAME";
947     prop.format = BDF_ATOM;
948     prop.value.atom = "Normal";
949     bdf_add_font_property(f, &prop);
950
951     if (font->info.dfPitchAndFamily & 0xf0) {
952         prop.name = "ADDSTYLE_NAME";
953         prop.format = BDF_ATOM;
954         switch (font->info.dfPitchAndFamily & 0xf0) {
955           case 0x20: prop.value.atom = "Swiss"; break;
956           case 0x30: prop.value.atom = "Modern"; break;
957           case 0x40: prop.value.atom = "Script"; break;
958           case 0x50: prop.value.atom = "Decorative"; break;
959           default: prop.value.atom = 0;
960         }
961         if (prop.value.atom != 0)
962           bdf_add_font_property(f, &prop);
963     }
964
965     prop.name = "PIXEL_SIZE";
966     prop.format = BDF_INTEGER;
967     prop.value.int32 = (int)
968         ((((double) (f->point_size * 10) *
969            (double) f->resolution_y) / 722.7) + 0.5);
970     bdf_add_font_property(f, &prop);
971
972     prop.name = "POINT_SIZE";
973     prop.format = BDF_INTEGER;
974     prop.value.int32 = f->point_size * 10;
975     bdf_add_font_property(f, &prop);
976
977     prop.name = "RESOLUTION_X";
978     prop.format = BDF_CARDINAL;
979     prop.value.card32 = (unsigned int) f->resolution_x;
980     bdf_add_font_property(f, &prop);
981
982     prop.name = "RESOLUTION_Y";
983     prop.format = BDF_CARDINAL;
984     prop.value.card32 = (unsigned int) f->resolution_y;
985     bdf_add_font_property(f, &prop);
986
987     prop.name = "FONT_ASCENT";
988     prop.format = BDF_INTEGER;
989     prop.value.int32 = f->font_ascent;
990     bdf_add_font_property(f, &prop);
991
992     prop.name = "FONT_DESCENT";
993     prop.format = BDF_INTEGER;
994     prop.value.int32 = f->font_descent;
995     bdf_add_font_property(f, &prop);
996
997     prop.name = "AVERAGE_WIDTH";
998     prop.format = BDF_INTEGER;
999     prop.value.int32 = font->info.dfAvgWidth * 10;
1000     bdf_add_font_property(f, &prop);
1001
1002     prop.name = "SPACING";
1003     prop.format = BDF_ATOM;
1004     prop.value.atom = "P";
1005     switch (f->spacing) {
1006       case BDF_PROPORTIONAL: prop.value.atom = "P"; break;
1007       case BDF_MONOWIDTH: prop.value.atom = "M"; break;
1008       case BDF_CHARCELL: prop.value.atom = "C"; break;
1009     }
1010     bdf_add_font_property(f, &prop);
1011
1012     prop.name = "CHARSET_REGISTRY";
1013     prop.format = BDF_ATOM;
1014     prop.value.atom = _bdffnt_cset_name(font->info.dfCharSet, &i);
1015     bdf_add_font_property(f, &prop);
1016
1017     sprintf(name, "%d", i);
1018     prop.name = "CHARSET_ENCODING";
1019     prop.format = BDF_ATOM;
1020     prop.value.atom = name;
1021     bdf_add_font_property(f, &prop);
1022
1023     /*
1024      * Generate the XLFD name.
1025      */
1026     f->name = bdf_make_xlfd_name(f, 0, 0);
1027
1028     /*
1029      * Add messages indicating the font was converted.
1030      */
1031     _bdf_add_comment(f, "Font converted from FNT/FON to BDF.", 35);
1032     _bdf_add_acmsg(f, "Font converted from FNT/FON to BDF.", 35);
1033
1034     /*
1035      * Mark the font as being modified.
1036      */
1037     f->modified = 1;
1038
1039     *out = f;
1040
1041     return 0;
1042 }