1 /* Copyright (C) 2002-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "winfonts.h"
31 
32 #include "bvedit.h"
33 #include "encoding.h"
34 #include "fontforge.h"
35 #include "fontforgevw.h"
36 #include "gfile.h"
37 #include "mem.h"
38 #include "splinefill.h"
39 #include "splinefont.h"
40 #include "splineutil.h"
41 #include "splineutil2.h"
42 #include "tottf.h"
43 #include "ustring.h"
44 #include "utype.h"
45 
46 #include <math.h>
47 #include <stdio.h>
48 #include <string.h>
49 
50 /* Look for
51 Source: Microsoft Windows 2.0 SDK Programmer's Refrence, pages 639 through 645
52         Microsoft Windows Device Driver Kit, Device Driver Adaptaion Guide, pages 13-1-13-15
53 
54 This is quoted directly from "The PC Programmer's Sourcebook, 2nd Edition", by
55 Thom Hogan, pages 6-18 through 6-19.  You need this book.  ISBN 1-55615-321-X.
56 */
57 
58 /* The information herein is derived from Windows 3 Developer's Notes summary */
59 /* Spec for v3 */
60 /*   http://support.microsoft.com/default.aspx?scid=KB;en-us;q65123	      */
61 /*    http://www.csdn.net/Dev/Format/text/font.htm			      */
62 /* Spec for v2 */
63 /*   http://www.technoir.nu/hplx/hplx-l/9708/msg00404.html		      */
64 /* Spec for FontDirEntry */
65 /*   http://www.sxlist.com/techref/os/win/api/win32/struc/src/str08_9.htm     */
66 /* Spec for ?FON? file? */
67 /*   http://www.csn.ul.ie/~caolan/publink/winresdump/winresdump/doc/resfmt.txt*/
68 /*  and from the freetype source code (particularly:			      */
69 /*  ~freetype/src/winfonts/winfnt.c and ~freetype/include/freetype/internal/fntypes.h */
70 /* Algorithm for generating .fon files taken from the wine distribution:      */
71 /*  wine/tools/fnt2fon.c written by Huw Davies of codeweavers and included    */
72 /*  here with his permission.						      */
73 
74 /* Windows FNT header. A FON file may contain several FNTs */
75 struct fntheader {
76     uint16	version;		/* Either 0x200 or 0x300 */
77     uint32	filesize;
78     char	copyright[60+1];
79     uint16	type;
80 #define FNT_TYPE_VECTOR	0x0001		/* If set a vector FNT, else raster (we only parse rasters) */
81 /* not used, mbz	0x0002 */
82 #define FNT_TYPE_MEMORY	0x0004		/* If set font is in ROM */
83 /* not used, mbz	0x0078 */
84 #define FNT_TYPE_DEVICE	0x0080		/* If set font is "realized by a device" whatever that means */
85 /* reserved for device	0xff00 */
86     uint16	pointsize;		/* design pointsize */
87     uint16	vertres;		/* Vertical resolution of font */
88     uint16	hortres;		/* Horizontal resolution of font */
89     uint16	ascent;
90     uint16	internal_leading;
91     uint16	external_leading;
92     uint8	italic;			/* set to 1 for italic fonts */
93     uint8	underline;		/* set to 1 for underlined fonts */
94     uint8	strikeout;		/* set to 1 for struckout fonts */
95     uint16	weight;			/* 1-1000 windows weight value */
96     uint8	charset;		/* ??? */
97     uint16	width;			/* non-0 => fixed width font, width of all chars */
98     uint16	height;			/* height of font bounding box */
99     uint8	pitchfamily;
100 #define FNT_PITCH_VARIABLE	0x01	/* Variable width font */
101 #define FNT_FAMILY_MASK		0xf0
102 #define  FNT_FAMILY_DONTCARE	0x00
103 #define  FNT_FAMILY_SERIF	0x10
104 #define  FNT_FAMILY_SANSSERIF	0x20
105 #define  FNT_FAMILY_FIXED	0x30
106 #define  FNT_FAMILY_SCRIPT	0x40
107 #define  FNT_FAMILY_DECORATIVE	0x50
108     uint16	avgwidth;		/* Width of "X" */
109     uint16	maxwidth;
110     uint8	firstchar;
111     uint8	lastchar;
112     uint8	defchar;		/* ?-firstchar */
113     uint8	breakchar;		/* 32-firstchar */
114     uint16	widthbytes;		/* Number of bytes in a row */
115     uint32	deviceoffset;		/* set to 0 */
116     uint32	faceoffset;		/* Offset from start of file to face name (C string) */
117     uint32	bitspointer;		/* set to 0 */
118     uint32	bitsoffset;		/* Offset from start of file to start of bitmap info */
119     uint8	mbz1;
120 /* These fields are not present in 2.0 and are not meaningful in 3.0 */
121 /*  they are there for future expansion */
122     uint32	flags;
123 #define FNT_FLAGS_FIXED		0x0001
124 #define FNT_FLAGS_PROPORTIONAL	0x0002
125 #define FNT_FLAGS_ABCFIXED	0x0004
126 #define FNT_FLAGS_ABCPROP	0x0008
127 #define FNT_FLAGS_1COLOR	0x0010
128 #define FNT_FLAGS_16COLOR	0x0020
129 #define FNT_FLAGS_256COLOR	0x0040
130 #define FNT_FLAGS_RGBCOLOR	0x0080
131     uint16	aspace;
132     uint16	bspace;
133     uint16	cspace;
134     uint32	coloroffset;		/* Offset to color table */
135     uint8	mbz2[16];		/* Freetype says 4. Online docs say 16 & earlier versions were wrong... */
136 };
137 
138 
139 struct v2chars { uint16 width; uint16 offset; };
140     /* In v2 I get the impression that characters are stored as they are on the */
141     /*  ie. one huge bitmap. The offset gives the location in each row */
142 struct v3chars { uint16 width; uint32 offset; };
143     /* The offset gives the offset to the entire character (stored in a weird */
144     /*  format but basically contiguously) from the bitsoffset */
145 
146 struct winmz_header {
147     uint16 magic;
148 #define FON_MZ_MAGIC	0x5A4D
149     uint16 skip[29];
150     uint32 lfanew;
151 };
152 
153 struct winne_header {
154     uint16 magic;
155 #define FON_NE_MAGIC	0x454E
156     uint8 skip[34];
157     uint16 resource_tab_offset;
158     uint16 rname_tab_offset;
159 };
160 
161 /* Little-endian routines. I hate eggs anyway. */
lgetushort(FILE * f)162 static int lgetushort(FILE *f) {
163     int ch1, ch2;
164     ch1 = getc(f);
165     ch2 = getc(f);
166 return( (ch2<<8)|ch1 );
167 }
168 
lgetlong(FILE * f)169 static int lgetlong(FILE *f) {
170     int ch1, ch2, ch3, ch4;
171     ch1 = getc(f);
172     ch2 = getc(f);
173     ch3 = getc(f);
174     ch4 = getc(f);
175 return( (ch4<<24)|(ch3<<16)|(ch2<<8)|ch1 );
176 }
177 
lputshort(FILE * f,int val)178 static void lputshort(FILE *f,int val) {
179     putc(val&0xff,f);
180     putc((val>>8)&0xff,f);
181 }
182 
lputlong(FILE * f,int val)183 static void lputlong(FILE *f,int val) {
184     putc(val&0xff,f);
185     putc((val>>8),f);
186     putc((val>>16),f);
187     putc((val>>24)&0xff,f);
188 }
189 
FNT_Load(FILE * fnt,SplineFont * sf)190 static int FNT_Load(FILE *fnt,SplineFont *sf) {
191     struct fntheader fntheader;
192     struct v3chars charinfo[258];	/* Max size */
193     int i, j, k, ch;
194     uint32 base = ftell(fnt);
195     char *pt, *spt, *temp;
196     BDFFont *bdf;
197     BDFChar *bdfc;
198 
199     memset(&fntheader,0,sizeof(fntheader));
200     fntheader.version = lgetushort(fnt);
201     if ( fntheader.version != 0x200 && fntheader.version != 0x300 )
202 return( false );
203     fntheader.filesize = lgetlong(fnt);
204     for ( i=0; i<60; ++i )
205 	fntheader.copyright[i] = getc(fnt);
206     fntheader.copyright[i] = '\0';
207     for ( --i; i>=0 && fntheader.copyright[i]==' '; --i )
208 	fntheader.copyright[i] = '\0';
209     fntheader.type = lgetushort(fnt);
210     if ( fntheader.type & (FNT_TYPE_VECTOR|FNT_TYPE_MEMORY|FNT_TYPE_DEVICE))
211 return( false );
212     fntheader.pointsize = lgetushort(fnt);
213     fntheader.vertres = lgetushort(fnt);
214     fntheader.hortres = lgetushort(fnt);
215     fntheader.ascent = lgetushort(fnt);
216     fntheader.internal_leading = lgetushort(fnt);
217     fntheader.external_leading = lgetushort(fnt);
218     fntheader.italic = getc(fnt);
219     fntheader.underline = getc(fnt);
220     fntheader.strikeout = getc(fnt);
221     fntheader.weight = lgetushort(fnt);
222     fntheader.charset = getc(fnt);
223     fntheader.width = lgetushort(fnt);
224     fntheader.height = lgetushort(fnt);
225     fntheader.pitchfamily = getc(fnt);
226     fntheader.avgwidth = lgetushort(fnt);
227     fntheader.maxwidth = lgetushort(fnt);
228     fntheader.firstchar = getc(fnt);
229     fntheader.lastchar = getc(fnt);
230     fntheader.defchar = getc(fnt);
231     fntheader.breakchar = getc(fnt);
232     fntheader.widthbytes = lgetushort(fnt);
233     fntheader.deviceoffset = lgetlong(fnt);
234     fntheader.faceoffset = lgetlong(fnt);
235     fntheader.bitspointer = lgetlong(fnt);
236     fntheader.bitsoffset = lgetlong(fnt);
237     (void) getc(fnt);		/* Not documented in the v2 spec but seems to be present */
238     if ( fntheader.version == 0x300 ) {
239 	fntheader.flags = lgetlong(fnt);
240 	if ( fntheader.flags & (FNT_FLAGS_ABCFIXED|FNT_FLAGS_ABCPROP|FNT_FLAGS_16COLOR|FNT_FLAGS_256COLOR|FNT_FLAGS_RGBCOLOR))
241 return( false );
242 	fntheader.aspace = lgetushort(fnt);
243 	fntheader.bspace = lgetushort(fnt);
244 	fntheader.cspace = lgetushort(fnt);
245 	fntheader.coloroffset = lgetlong(fnt);
246 	for ( i=0; i<16; ++i )		/* Freetype thinks this is 4 */
247 	    (void) getc(fnt);
248     }
249 
250     memset(charinfo,0,sizeof(charinfo));
251     for ( i=fntheader.firstchar; i<=fntheader.lastchar+2; ++i ) {
252 	charinfo[i].width = lgetushort(fnt);
253 	if ( fntheader.version==0x200 )
254 	    charinfo[i].offset = lgetushort(fnt);
255 	else
256 	    charinfo[i].offset = lgetlong(fnt);
257     }
258 
259     /* Set the font names and the pfminfo structure */
260     sf->pfminfo.pfmset = true;
261     if ( fntheader.copyright[0]!='\0' ) {
262 	free(sf->copyright);
263 	sf->copyright = copy(fntheader.copyright);
264     }
265     free(sf->weight);
266     sf->weight = copy( fntheader.weight<=100 ? "Thin" :
267 			fntheader.weight<=200 ? "Extralight" :
268 			fntheader.weight<=300 ? "Light" :
269 			fntheader.weight<=400 ? "Normal" :
270 			fntheader.weight<=500 ? "Medium" :
271 			fntheader.weight<=600 ? "Demibold" :
272 			fntheader.weight<=700 ? "Bold" :
273 			fntheader.weight<=800 ? "Heavy" :
274 			fntheader.weight<=900 ? "Black" : "Nord" );
275     sf->pfminfo.weight = fntheader.weight;
276     sf->pfminfo.panose[2] = fntheader.weight/100 + 1;
277     fseek(fnt,base+fntheader.faceoffset,SEEK_SET);
278     for ( i=0; (ch=getc(fnt))!=EOF && ch!=0; ++i );
279     free(sf->familyname);
280     sf->familyname = malloc(i+2);
281     fseek(fnt,base+fntheader.faceoffset,SEEK_SET);
282     for ( i=0; (ch=getc(fnt))!=EOF && ch!=0; ++i )
283 	sf->familyname[i] = ch;
284     sf->familyname[i] = '\0';
285     temp = malloc(i+50);
286     strcpy(temp,sf->familyname);
287     if ( fntheader.weight<=300 || fntheader.weight>500 ) {
288 	strcat(temp," ");
289 	strcat(temp,sf->weight);
290     }
291     if ( fntheader.italic )
292 	strcat(temp," Italic");
293     free(sf->fullname);
294     sf->fullname = temp;
295     free(sf->fontname);
296     sf->fontname = copy(sf->fullname);
297     for ( pt=spt=sf->fontname; *spt; ++spt )
298 	if ( *spt!=' ' )
299 	    *pt++ = *spt;
300     *pt = '\0';
301     sf->pfminfo.pfmfamily = fntheader.pitchfamily;
302     sf->pfminfo.panose[0] = 2;
303     if ( (fntheader.pitchfamily&FNT_FAMILY_MASK)==FNT_FAMILY_SCRIPT )
304 	sf->pfminfo.panose[0] = 3;
305     sf->pfminfo.width = 5;		/* No info about condensed/extended */
306     sf->pfminfo.panose[3] = 3;
307     if ( !(fntheader.pitchfamily&FNT_PITCH_VARIABLE ) )
308 	sf->pfminfo.panose[3] = 9;
309     sf->pfminfo.linegap = (sf->ascent+sf->descent)*fntheader.external_leading/fntheader.height;
310     if ( fntheader.italic )
311 	sf->italicangle = 11.25;
312 
313     bdf = calloc(1,sizeof(BDFFont));
314     bdf->sf = sf;
315     bdf->glyphcnt = sf->glyphcnt;
316     bdf->glyphmax = sf->glyphmax;
317     bdf->res = fntheader.vertres;
318     bdf->pixelsize = rint(fntheader.pointsize*fntheader.vertres/72.27);
319     bdf->glyphs = calloc(sf->glyphmax,sizeof(BDFChar *));
320     bdf->ascent = rint(.8*bdf->pixelsize);		/* shouldn't use typographical ascent */
321     bdf->descent = bdf->pixelsize-bdf->ascent;
322     for ( i=fntheader.firstchar; i<=fntheader.lastchar; ++i ) if ( charinfo[i].width!=0 ) {
323 	int gid = SFMakeChar(sf,sf->map,i)->orig_pos;
324 
325 	if ( gid>=bdf->glyphcnt ) {
326 	    if ( gid>=bdf->glyphmax )
327 		bdf->glyphs = realloc(bdf->glyphs,(bdf->glyphmax=sf->glyphmax)*sizeof(BDFChar *));
328 	    memset(bdf->glyphs+bdf->glyphcnt,0,(sf->glyphcnt-bdf->glyphcnt)*sizeof(BDFChar *));
329 	    bdf->glyphcnt = sf->glyphcnt;
330 	}
331 
332 	bdf->glyphs[gid] = bdfc = chunkalloc(sizeof(BDFChar));
333 	memset( bdfc,'\0',sizeof( BDFChar ));
334 	bdfc->xmin = 0;
335 	bdfc->xmax = charinfo[i].width-1;
336 	bdfc->ymin = fntheader.ascent-fntheader.height;
337 	bdfc->ymax = fntheader.ascent-1;
338 	bdfc->width = charinfo[i].width;
339 	bdfc->vwidth = bdf->pixelsize;
340 	bdfc->bytes_per_line = (bdfc->xmax>>3)+1;
341 	bdfc->bitmap = calloc(bdfc->bytes_per_line*fntheader.height,sizeof(uint8));
342 	bdfc->orig_pos = gid;
343 	bdfc->sc = sf->glyphs[gid];
344 	bdfc->sc->widthset = true;
345 
346 	fseek(fnt,base+charinfo[i].offset,SEEK_SET);
347 	for ( j=0; j<bdfc->bytes_per_line; ++j ) {
348 	    for ( k=0; k<fntheader.height; ++k )
349 		bdfc->bitmap[k*bdfc->bytes_per_line+j] = getc(fnt);
350 	}
351 	BCCompressBitmap(bdfc);
352 
353 	if ( feof(fnt) ) {
354 	    BDFFontFree(bdf);
355 return( false );
356 	}
357     }
358 
359     bdf->next = sf->bitmaps;
360     sf->bitmaps = bdf;
361 return( true );
362 }
363 
SFReadWinFON(char * filename,int toback)364 SplineFont *SFReadWinFON(char *filename,int toback) {
365     FILE *fon;
366     int magic, i, shift_size;
367     SplineFont *sf;
368     uint32 neoffset, recoffset, recend;
369     int font_count;
370     BDFFont *bdf, *next;
371 
372     fon = fopen(filename,"rb");
373     if ( fon==NULL )
374 return( NULL );
375     magic = lgetushort(fon);
376     fseek(fon,0,SEEK_SET);
377     if ( magic!=0x200 && magic!=0x300 && magic!=FON_MZ_MAGIC ) {
378 	fclose(fon);
379 	ff_post_error(_("Bad magic number"), _("This does not appear to be a Windows FNT for FON file"));
380 return( NULL );
381     }
382     sf = SplineFontBlank(256);
383     sf->map = EncMapNew(256,256,FindOrMakeEncoding("win"));
384 
385     if ( magic == 0x200 || magic==0x300 )
386 	FNT_Load(fon,sf);
387     else {
388 	/* Ok, we know it begins with a mz header (whatever that is) */
389 	/* all we care about is the offset to the ne header (whatever that is) */
390 	fseek(fon,30*sizeof(uint16),SEEK_SET);
391 	neoffset = lgetlong(fon);
392 	fseek(fon,neoffset,SEEK_SET);
393 	if ( lgetushort(fon)!=FON_NE_MAGIC ) {
394 	    EncMapFree(sf->map);
395 	    SplineFontFree(sf);
396 	    fclose(fon);
397 return( NULL );
398 	}
399 	for ( i=0; i<34; ++i ) getc(fon);
400 	recoffset = neoffset + lgetushort(fon);
401 	recend = neoffset + lgetushort(fon);
402 
403 	fseek(fon,recoffset,SEEK_SET);
404 	shift_size = lgetushort(fon);
405 	font_count = 0;
406 	while ( ftell(fon)<recend ) {
407 	    int id, count;
408 	    id = lgetushort(fon);
409 	    if ( id==0 )
410 	break;
411 	    count = lgetushort(fon);
412 	    if ( id==0x8008 ) {
413 		/* id==0x8007 seems to point to a Font Dir Entry which is almost */
414 		/*  a copy of the fntheader */
415 		font_count = count;
416 		lgetlong(fon);
417 	break;
418 	    }
419 	    fseek(fon,4+count*12,SEEK_CUR);
420 	}
421 	for ( i=0; i<font_count; ++i ) {
422 	    uint32 here = ftell(fon);
423 	    uint32 offset = lgetushort(fon)<<shift_size;
424 	    fseek(fon,offset,SEEK_SET);		/* FontDirEntries need a +4 here */
425 	    FNT_Load(fon,sf);
426 	    fseek(fon,here+12,SEEK_SET);
427 	}
428     }
429     fclose(fon);
430     if ( sf->bitmaps==NULL ) {
431 	EncMapFree(sf->map);
432 	SplineFontFree(sf);
433 return( NULL );
434     }
435 
436     SFOrderBitmapList(sf);
437     if ( sf->bitmaps->next!=NULL && toback ) {
438 	for ( bdf = sf->bitmaps; bdf->next!=NULL; bdf = next ) {
439 	    next = bdf->next;
440 	    BDFFontFree(bdf);
441 	}
442 	sf->bitmaps = bdf;
443     }
444     /* Find the biggest font, and adjust the metrics to match */
445     for ( bdf = sf->bitmaps; bdf->next!=NULL; bdf = bdf->next );
446     for ( i=0; i<sf->glyphcnt ; ++i ) if ( sf->glyphs[i]!=NULL && bdf->glyphs[i]!=NULL ) {
447 	sf->glyphs[i]->width = rint(bdf->glyphs[i]->width*1000.0/bdf->pixelsize);
448 	sf->glyphs[i]->widthset = true;
449     }
450     sf->onlybitmaps = true;
451 return( sf );
452 }
453 
454 /* ************************************************************************** */
455 /*  ******************************** Output ********************************  */
456 /* ************************************************************************** */
457 
_FntFontDump(FILE * file,BDFFont * font,EncMap * map,int res)458 static int _FntFontDump(FILE *file,BDFFont *font, EncMap *map, int res) {
459     uint32 startpos, endpos, namelocpos, datapos, namepos;
460     int i, j, k, l;
461     int ch;
462     int cnt, badch, defch;
463     int first, last, avgwid, maxwid, samewid, maxy, miny, widbytes, spacesize;
464     struct pfminfo pfminfo;
465     int complained=false;
466     int gid;
467     BDFChar *bdfc;
468 
469     if ( font->clut!=NULL )
470 return( false );
471 
472     for ( i=0; i<map->enccount; i++ ) if (( gid=map->map[i])!=-1 && ( bdfc = font->glyphs[gid] ) != NULL )
473 	BCPrepareForOutput( bdfc,true );
474     avgwid = widbytes = maxwid = maxy = last = cnt = 0;
475     miny = first = 999999;
476     samewid = -1;
477     badch = -1;
478     defch = -1;
479     for ( i=0; i<map->enccount && i<256; ++i ) if ( (gid=map->map[i])!=-1 && font->glyphs[gid]!=NULL && font->glyphs[gid]->width>0 ) {
480 	if ( i==0 || (i==0x80 && defch!=0) ) defch=i;
481 	else if ( i!=' ' ) defch = i;
482 	if ( i<first ) first = i;
483 	last = i;
484 	++cnt;
485 	avgwid += font->glyphs[gid]->width;
486 	widbytes += (font->glyphs[gid]->width+7)>>3;
487 	if ( font->glyphs[gid]->ymax>maxy ) maxy = font->glyphs[gid]->ymax;
488 	if ( font->glyphs[gid]->ymin<miny ) miny = font->glyphs[gid]->ymin;
489 	if ( font->glyphs[gid]->width>maxwid ) maxwid = font->glyphs[gid]->width;
490 	if ( font->glyphs[gid]->width<font->glyphs[gid]->xmax || font->glyphs[gid]->xmin<0 )
491 	    badch = gid;
492 	if ( samewid==-1 ) samewid = font->glyphs[gid]->width;
493 	else if ( samewid!=font->glyphs[gid]->width ) samewid = -2;
494     }
495     if (( spacesize = font->pixelsize/4 )==0 ) spacesize=1;
496     gid = map->map[' '];
497     if ( gid!=-1 && font->glyphs[gid]!=NULL && font->glyphs[gid]->sc!=NULL &&
498 	    font->glyphs[gid]->sc->unicodeenc == ' ' )
499 	spacesize = font->glyphs[gid]->width;
500     if ( badch!=-1 )
501 	LogError( _("At pixelsize %d the character %s either starts before the origin or extends beyond the advance width.\n"),
502 		font->pixelsize, font->glyphs[badch]->sc->name );
503     memset(&pfminfo,'\0',sizeof(pfminfo));
504     SFDefaultOS2Info(&pfminfo,font->sf,font->sf->fontname);
505     widbytes = avgwid+spacesize;
506     if ( cnt!=0 ) avgwid = rint(avgwid/(bigreal) cnt);
507     gid = map->map['X'];
508     if ( gid!=-1 && font->glyphs[gid]!=NULL && font->glyphs[gid]->sc!=NULL &&
509 	    font->glyphs[gid]->sc->unicodeenc == 'X' )
510 	avgwid = font->glyphs[gid]->width;
511 
512     if ( res<0 ) {
513 	switch ( font->pixelsize ) {
514 	  case 13: case 16: case 32:
515 	    res = 96;
516 	  break;
517 	  default:
518 	    res = 120;
519 	  break;
520 	}
521     }
522 
523     startpos = ftell(file);
524     lputshort(file,0x200);
525     lputlong(file,0);		/* Fix file size up later */
526     i = 0;
527     if ( font->sf->copyright ) {
528 	for ( i=0; i<59 && font->sf->copyright[i]!='\0'; ++i )
529 	    putc(font->sf->copyright[i],file);
530     }
531     while ( i<60 ) {
532 	putc('\0',file);
533 	++i;
534     }
535     lputshort(file,0);					/* flags */
536     lputshort(file,rint(font->pixelsize*72.0/res));	/* pointsize */
537     lputshort(file,res);				/* vertical res */
538     lputshort(file,res);				/* horizontal res */
539     lputshort(file,maxy+1);				/* ascent */
540     lputshort(file,0);					/* internal_leading */
541     lputshort(file,					/* external_leading */
542 		    rint(pfminfo.linegap*font->pixelsize/(bigreal)(font->sf->ascent+font->sf->descent)) );
543     if ( font->sf->italicangle!=0 ||
544 	    strstrmatch(font->sf->fontname,"ital")!=NULL ||
545 	    strstrmatch(font->sf->fontname,"kurs")!=NULL ||
546 	    strstrmatch(font->sf->fontname,"slanted")!=NULL ||
547 	    strstrmatch(font->sf->fontname,"obli")!=NULL )
548 	putc('\1',file);
549     else
550 	putc('\0',file);				/* italic */
551     putc('\0',file);					/* underline */
552     putc('\0',file);					/* strikeout */
553     lputshort(file,pfminfo.weight);			/* weight */
554     putc('\0',file);					/* charset */ /* ??? */
555     lputshort(file,samewid>0?samewid:0);		/* fixed width */
556     lputshort(file,maxy-miny+1);			/* bounding box height */
557     putc(pfminfo.pfmfamily,file);			/* pitchfamily */
558     lputshort(file,avgwid);				/* average width */
559     lputshort(file,maxwid);				/* max width */
560     putc(first,file);
561     putc(last,file);
562     putc(defch-first,file);
563     putc(' '-first,file);
564     lputshort(file,widbytes);				/* bytes per row */
565     lputlong(file,0);					/* device name */
566     namelocpos = ftell(file);
567     lputlong(file,0);					/* face name, fill in later */
568     lputlong(file,0);					/* location in ROM */
569     datapos = 118+(last-first+3)*4;
570     lputlong(file,datapos);				/* bitmap data pointer */
571     putc('\0',file);
572 /* End of FNT header */
573 
574     widbytes = 0;
575     for ( i=first; i<=last; ++i ) {
576 	if ( (gid=map->map[i])!=-1 && font->glyphs[gid]!=NULL && font->glyphs[gid]->width>0 )
577 	    lputshort(file,font->glyphs[gid]->width);
578 	else
579 	    lputshort(file,0);
580 	lputshort(file,datapos+widbytes);
581 	if ( gid!=-1 && font->glyphs[gid]!=NULL && font->glyphs[gid]->width>0 )
582 	    widbytes += ((font->glyphs[gid]->width+7)>>3) * (maxy-miny+1);
583     }
584     /* And a space */
585     lputshort(file,spacesize );
586     lputshort(file,widbytes);
587     widbytes += spacesize;
588     /* And an end marker */
589     lputshort(file,0);
590     lputshort(file,widbytes);
591 
592     if ( ftell(file)-startpos != datapos ) {
593 	LogError( _("Internal error in creating FNT. File offset wrong\n") );
594 	complained = true;
595     }
596 
597     /* And finally the character data */
598     widbytes = 0;
599     for ( i=first; i<=last; ++i ) {
600 	int gid = map->map[i];
601 	BDFChar *bdfc = gid==-1 ? NULL : font->glyphs[gid];
602 	if ( bdfc!=NULL && bdfc->width>0 ) {
603 	    widbytes += ((bdfc->width+7)>>3) * (maxy-miny+1);
604 	    for ( k=0 ; k< bdfc->width; k+= 8 ) {
605 		for ( j=maxy; j>=miny; --j ) {
606 		    if ( j>bdfc->ymax || j<bdfc->ymin )
607 			putc('\0',file);
608 		    else {
609 			ch = 0;
610 			for ( l=0; l<8; ++l ) {
611 			    if ( k+l>=bdfc->xmin && k+l<=bdfc->xmax &&
612 				    (bdfc->bitmap[(bdfc->ymax-j)*bdfc->bytes_per_line+((k+l-bdfc->xmin)>>3)]
613 					&(0x80>>((k+l-bdfc->xmin)&7))) )
614 				ch |= (0x80>>l);
615 			}
616 			putc(ch,file);
617 		    }
618 		}
619 	    }
620 	    if ( ftell(file)-startpos != datapos+widbytes && !complained ) {
621 		LogError( _("Internal error in creating FNT. File offset wrong in bitmap data\n") );
622 		complained = true;
623 	    }
624 	}
625     }
626     /* And the space character */
627     spacesize = (spacesize+7)>>3;
628     for ( i=0; i<spacesize*(maxy-miny+1); ++i )
629 	putc('\0',file);
630 
631     /* Now the face name */
632     namepos = ftell(file);
633     fwrite(font->sf->familyname,1,strlen(font->sf->familyname)+1,file);
634 
635     /* And now fixup the file size field */
636     endpos = ftell(file);
637     fseek(file,startpos+2,SEEK_SET);
638     lputlong(file,endpos-startpos);
639     fseek(file,namelocpos,SEEK_SET);
640     lputlong(file,namepos);
641     fseek(file,endpos,SEEK_SET);
642     for ( i=0; i<map->enccount; i++ ) if (( gid=map->map[i])!=-1 && ( bdfc = font->glyphs[gid] ) != NULL )
643 	BCRestoreAfterOutput( bdfc );
644 return( true );
645 }
646 
FNTFontDump(char * filename,BDFFont * font,EncMap * map,int res)647 int FNTFontDump(char *filename,BDFFont *font, EncMap *map, int res) {
648     FILE *file;
649     int ret;
650 
651     file = fopen(filename,"wb");
652     if ( file==NULL ) {
653 	LogError( _("Can't open %s\n"), filename );
654 return( 0 );
655     }
656     ret = _FntFontDump(file,font,map,res);
657     if ( ferror(file))
658 	ret = 0;
659     if ( fclose(file)!=0 )
660 	ret = 0;
661 return( ret );
662 }
663 
664 /* From wine tools fnt2fon.c by Huw Davies, modified with permission */
665 typedef unsigned short	WORD;
666 typedef unsigned char	BYTE;
667 typedef unsigned char	CHAR;
668 typedef signed short	INT16;
669 typedef int		INT;
670 typedef uint32		DWORD;		/* originally unsigned long */
671 typedef int32		LONG;
672 #define CALLBACK
673 typedef int32		FARPROC;	/* Pointers screw up the alignment on 64 bit machines */
674 typedef int32		FARPROC16;	/* ditto */
675 typedef unsigned short	HANDLE16;
676 typedef int32		LONG_PTR;	/* originally "long", but that won't work on 64 bit machines */
677 typedef LONG_PTR        LRESULT;
678 
679 typedef struct
680 {
681     WORD  ne_magic;             /* 00 NE signature 'NE' */
682     BYTE  ne_ver;               /* 02 Linker version number */
683     BYTE  ne_rev;               /* 03 Linker revision number */
684     WORD  ne_enttab;            /* 04 Offset to entry table relative to NE */
685     WORD  ne_cbenttab;          /* 06 Length of entry table in bytes */
686     LONG  ne_crc;               /* 08 Checksum */
687     WORD  ne_flags;             /* 0c Flags about segments in this file */
688     WORD  ne_autodata;          /* 0e Automatic data segment number */
689     WORD  ne_heap;              /* 10 Initial size of local heap */
690     WORD  ne_stack;             /* 12 Initial size of stack */
691     DWORD ne_csip;              /* 14 Initial CS:IP */
692     DWORD ne_sssp;              /* 18 Initial SS:SP */
693     WORD  ne_cseg;              /* 1c # of entries in segment table */
694     WORD  ne_cmod;              /* 1e # of entries in module reference tab. */
695     WORD  ne_cbnrestab;         /* 20 Length of nonresident-name table     */
696     WORD  ne_segtab;            /* 22 Offset to segment table */
697     WORD  ne_rsrctab;           /* 24 Offset to resource table */
698     WORD  ne_restab;            /* 26 Offset to resident-name table */
699     WORD  ne_modtab;            /* 28 Offset to module reference table */
700     WORD  ne_imptab;            /* 2a Offset to imported name table */
701     DWORD ne_nrestab;           /* 2c Offset to nonresident-name table */
702     WORD  ne_cmovent;           /* 30 # of movable entry points */
703     WORD  ne_align;             /* 32 Logical sector alignment shift count */
704     WORD  ne_cres;              /* 34 # of resource segments */
705     BYTE  ne_exetyp;            /* 36 Flags indicating target OS */
706     BYTE  ne_flagsothers;       /* 37 Additional information flags */
707     WORD  ne_pretthunks;        /* 38 Offset to return thunks */
708     WORD  ne_psegrefbytes;      /* 3a Offset to segment ref. bytes */
709     WORD  ne_swaparea;          /* 3c Reserved by Microsoft */
710     WORD  ne_expver;            /* 3e Expected Windows version number */
711 } IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER;
712 
713 #define NE_SEGFLAGS_MOVEABLE    0x0010
714 #define NE_SEGFLAGS_SHAREABLE   0x0020
715 #define NE_SEGFLAGS_PRELOAD     0x0040
716 #define NE_SEGFLAGS_DISCARDABLE 0x1000
717 
718 #define NE_FFLAGS_GUI           0x0300
719 #define NE_FFLAGS_LIBMODULE     0x8000
720 
721 #define NE_OSFLAGS_WINDOWS      0x04
722 
723 typedef struct
724 {
725     WORD     offset;
726     WORD     length;
727     WORD     flags;
728     WORD     id;
729     HANDLE16 handle;
730     WORD     usage;
731 } NE_NAMEINFO;
732 
733 #define NE_RSCTYPE_FONTDIR        0x8007
734 #define NE_RSCTYPE_FONT           0x8008
735 
736 typedef struct
737 {
738     WORD        type_id;   /* Type identifier */
739     WORD        count;     /* Number of resources of this type */
740     FARPROC16   resloader; /* SetResourceHandler() */
741     /*
742      * Name info array.
743      */
744 } NE_TYPEINFO;
745 
746 static const BYTE MZ_hdr[] = {'M',  'Z',  0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
747                  0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
748                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
750                  0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T',  'h',
751                  'i',  's',  ' ',  'P',  'r',  'o',  'g',  'r',  'a',  'm',  ' ',  'c',  'a',  'n',  'n',  'o',
752                  't',  ' ',  'b',  'e',  ' ',  'r',  'u',  'n',  ' ',  'i',  'n',  ' ',  'D',  'O',  'S',  ' ',
753                  'm',  'o',  'd',  'e',  0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
754 };
755 
756 
FONFontDump(char * filename,SplineFont * sf,int32 * sizes,int resol,EncMap * map)757 int FONFontDump(char *filename,SplineFont *sf, int32 *sizes,int resol,
758 	EncMap *map) {
759     BDFFont *bdf;
760     /* res = -1 => Guess depending on pixel size of font */
761     FILE **fntarray;
762     int *file_lens;
763     int num_files;
764     int i, j;
765     long off;
766     char name[200];
767     int c;
768     char *cp;
769     short point_size, dpi[2], align;
770     FILE *fon;
771     int resource_table_len, non_resident_name_len, resident_name_len;
772     unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, font_off;
773     char resident_name[200] = "";
774     int fontdir_len = 2;
775     char non_resident_name[200] = "";
776     IMAGE_OS2_HEADER NE_hdr;
777     NE_TYPEINFO rc_type;
778     NE_NAMEINFO rc_name;
779     unsigned short first_res = 0x0050, pad, res;
780     struct _fnt_header *fnt_header;
781     char buf[0x1000];
782     int nread;
783 
784     if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
785 
786     for ( i=0; sizes[i]!=0; ++i );
787     ff_progress_change_line1(_("Saving Bitmap Font(s)"));
788     ff_progress_change_stages(i);
789     num_files = i;
790     fntarray = (FILE **)malloc(num_files*sizeof(FILE *));
791     file_lens = (int *)malloc(num_files*sizeof(int));
792 
793     for ( i=0; sizes[i]!=0; ++i ) {
794 	for ( bdf=sf->bitmaps; bdf!=NULL &&
795 		(bdf->pixelsize!=(sizes[i]&0xffff) || BDFDepth(bdf)!=(sizes[i]>>16));
796 		bdf=bdf->next );
797 	if ( bdf==NULL ) {
798 	    ff_post_notice(_("Missing Bitmap"),_("Attempt to save a pixel size that has not been created (%d@%d)"),
799 		    sizes[i]&0xffff, sizes[i]>>16);
800 	    for ( j=0; j<i; ++j )
801 		fclose(fntarray[j]);
802             free(file_lens);
803 	    free(fntarray);
804 return( false );
805 	}
806 	fntarray[i] = GFileTmpfile();
807 	if ( !_FntFontDump(fntarray[i],bdf,map,resol) ) {
808 	    for ( j=0; j<=i; ++j )
809 		fclose(fntarray[j]);
810             free(file_lens);
811 	    free(fntarray);
812 return( false );
813 	}
814 	ff_progress_next_stage();
815 
816 	rewind(fntarray[i]);
817 	lgetushort(fntarray[i]);
818 	file_lens[i] = lgetlong(fntarray[i]);
819 	fseek(fntarray[i], 0x44, SEEK_SET);
820 	point_size = lgetushort(fntarray[i]);
821 	dpi[0] = lgetushort(fntarray[i]);
822 	dpi[1] = lgetushort(fntarray[i]);
823 	fseek(fntarray[i], 0x69, SEEK_SET);
824 	off = lgetlong(fntarray[i]);
825 	fseek(fntarray[i], off, SEEK_SET);
826         cp = name;
827         while((c = fgetc(fntarray[i])) != 0 && c != EOF)
828             *cp++ = c;
829 	*cp = '\0';
830 	rewind(fntarray[i]);
831 
832         fontdir_len += 0x74 + strlen(name) + 1;
833         if(i == 0) {
834             sprintf(non_resident_name, "FONTRES 100,%d,%d : %s %d", dpi[0], dpi[1], name, point_size);
835             strcpy(resident_name, name);
836         } else {
837             sprintf(non_resident_name + strlen(non_resident_name), ",%d", point_size);
838         }
839     }
840 
841     if(dpi[0] <= 108)
842         strcat(non_resident_name, " (VGA res)");
843     else
844         strcat(non_resident_name, " (8514 res)");
845     non_resident_name_len = strlen(non_resident_name) + 4;
846 
847     /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
848     resource_table_len = sizeof(align) + sizeof("FONTDIR") +
849                          sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) +
850                          sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) * num_files +
851                          sizeof(NE_TYPEINFO);
852     resource_table_off = sizeof(NE_hdr);
853     resident_name_off = resource_table_off + resource_table_len;
854     resident_name_len = strlen(resident_name) + 4;
855     module_ref_off = resident_name_off + resident_name_len;
856     non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(align);
857 
858     memset(&NE_hdr, 0, sizeof(NE_hdr));
859     NE_hdr.ne_magic = 0x454e;
860     NE_hdr.ne_ver = 5;
861     NE_hdr.ne_rev = 1;
862     NE_hdr.ne_flags = NE_FFLAGS_LIBMODULE | NE_FFLAGS_GUI;
863     NE_hdr.ne_cbnrestab = non_resident_name_len;
864     NE_hdr.ne_segtab = sizeof(NE_hdr);
865     NE_hdr.ne_rsrctab = sizeof(NE_hdr);
866     NE_hdr.ne_restab = resident_name_off;
867     NE_hdr.ne_modtab = module_ref_off;
868     NE_hdr.ne_imptab = module_ref_off;
869     NE_hdr.ne_enttab = NE_hdr.ne_modtab;
870     NE_hdr.ne_nrestab = non_resident_name_off;
871     NE_hdr.ne_align = 4;
872     NE_hdr.ne_exetyp = NE_OSFLAGS_WINDOWS;
873     NE_hdr.ne_expver = 0x400;
874 
875     fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
876     font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
877 
878     fon = fopen(filename, "wb");
879     if ( fon==NULL ) {
880 	ff_post_error(_("Couldn't open file"),_("Could not open output file: %s"),
881 		filename );
882 	for ( j=0; j<num_files; ++j )
883 	    fclose(fntarray[j]);
884 	free(fntarray);
885         free(file_lens);
886 return( false );
887     }
888 
889     fwrite(MZ_hdr, sizeof(MZ_hdr), 1, fon);
890     /* Write out the NE_hdr. Beware of endian problems */
891     lputshort(fon, NE_hdr.ne_magic);
892     putc(NE_hdr.ne_ver,fon);
893     putc(NE_hdr.ne_rev,fon);
894     lputshort(fon, NE_hdr.ne_enttab);
895     lputshort(fon, NE_hdr.ne_cbenttab);
896     lputlong(fon, NE_hdr.ne_crc);
897     lputshort(fon, NE_hdr.ne_flags);
898     lputshort(fon, NE_hdr.ne_autodata);
899     lputshort(fon, NE_hdr.ne_heap);
900     lputshort(fon, NE_hdr.ne_stack);
901     lputlong(fon, NE_hdr.ne_csip);
902     lputlong(fon, NE_hdr.ne_sssp);
903     lputshort(fon, NE_hdr.ne_cseg);
904     lputshort(fon, NE_hdr.ne_cmod);
905     lputshort(fon, NE_hdr.ne_cbnrestab);
906     lputshort(fon, NE_hdr.ne_segtab);
907     lputshort(fon, NE_hdr.ne_rsrctab);
908     lputshort(fon, NE_hdr.ne_restab);
909     lputshort(fon, NE_hdr.ne_modtab);
910     lputshort(fon, NE_hdr.ne_imptab);
911     lputlong(fon, NE_hdr.ne_nrestab);
912     lputshort(fon, NE_hdr.ne_cmovent);
913     lputshort(fon, NE_hdr.ne_align);
914     lputshort(fon, NE_hdr.ne_cres);
915     putc(NE_hdr.ne_exetyp,fon);
916     putc(NE_hdr.ne_flagsothers,fon);
917     lputshort(fon, NE_hdr.ne_pretthunks);
918     lputshort(fon, NE_hdr.ne_psegrefbytes);
919     lputshort(fon, NE_hdr.ne_swaparea);
920     lputshort(fon, NE_hdr.ne_expver);
921 
922     align = 4;
923     lputshort(fon, align);
924 
925     rc_type.type_id = NE_RSCTYPE_FONTDIR;
926     rc_type.count = 1;
927     rc_type.resloader = 0;
928     lputshort(fon, rc_type.type_id);
929     lputshort(fon, rc_type.count);
930     lputlong(fon, (long) rc_type.resloader);
931 
932     rc_name.offset = fontdir_off >> 4;
933     rc_name.length = (fontdir_len + 15) >> 4;
934     rc_name.flags = NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD;
935     rc_name.id = resident_name_off - sizeof("FONTDIR") - NE_hdr.ne_rsrctab;
936     rc_name.handle = 0;
937     rc_name.usage = 0;
938     lputshort(fon, rc_name.offset);
939     lputshort(fon, rc_name.length);
940     lputshort(fon, rc_name.flags);
941     lputshort(fon, rc_name.id);
942     lputshort(fon, rc_name.handle);
943     lputshort(fon, rc_name.usage);
944 
945     rc_type.type_id = NE_RSCTYPE_FONT;
946     rc_type.count = num_files;
947     rc_type.resloader = 0;
948     lputshort(fon, rc_type.type_id);
949     lputshort(fon, rc_type.count);
950     lputlong(fon, (long) rc_type.resloader);
951 
952     for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
953         int len = (file_lens[i] + 15) & ~0xf;
954 
955         rc_name.offset = font_off >> 4;
956         rc_name.length = len >> 4;
957         rc_name.flags = NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_SHAREABLE | NE_SEGFLAGS_DISCARDABLE;
958         rc_name.id = res;
959         rc_name.handle = 0;
960         rc_name.usage = 0;
961 	lputshort(fon, rc_name.offset);
962 	lputshort(fon, rc_name.length);
963 	lputshort(fon, rc_name.flags);
964 	lputshort(fon, rc_name.id);
965 	lputshort(fon, rc_name.handle);
966 	lputshort(fon, rc_name.usage);
967 
968         font_off += len;
969     }
970 
971     /* empty type info */
972     memset(&rc_type, 0, sizeof(rc_type));
973     lputshort(fon, rc_type.type_id);
974     lputshort(fon, rc_type.count);
975     lputlong(fon, (long) rc_type.resloader);
976 
977     fputc(strlen("FONTDIR"), fon);
978     fwrite("FONTDIR", strlen("FONTDIR"), 1, fon);
979     fputc(strlen(resident_name), fon);
980     fwrite(resident_name, strlen(resident_name), 1, fon);
981 
982     fputc(0x00, fon);    fputc(0x00, fon);
983     fputc(0x00, fon);
984     fputc(0x00, fon);    fputc(0x00, fon);
985 
986     fputc(strlen(non_resident_name), fon);
987     fwrite(non_resident_name, strlen(non_resident_name), 1, fon);
988     fputc(0x00, fon); /* terminator */
989 
990     /* empty ne_modtab and ne_imptab */
991     fputc(0x00, fon);
992     fputc(0x00, fon);
993 
994     pad = ftell(fon) & 0xf;
995     if(pad != 0)
996         pad = 0x10 - pad;
997     for(i = 0; i < pad; i++)
998         fputc(0x00, fon);
999 
1000     /* FONTDIR resource */
1001     lputshort(fon,num_files);
1002 
1003     for(res = first_res, i = 0; i < num_files; i++, res++) {
1004         lputshort(fon,res);
1005 
1006         /* The first 0x6D bytes of the FNT file and the FONTDIRENTRY match */
1007         rewind(fntarray[i]);
1008         fread(buf, 0x6D, 1, fntarray[i]);
1009         fwrite(buf, 0x6D, 1, fon);
1010 
1011         /* FONTDIRENTRY.dfReserved */
1012         lputlong(fon,0);
1013         /* FONTDIRENTRY.szDeviceName */
1014         fputc(0x00, fon);
1015 
1016 	fseek(fntarray[i], 0x69, SEEK_SET);
1017 	off = lgetlong(fntarray[i]);
1018         fseek(fntarray[i], off, SEEK_SET);
1019 
1020         cp = name;
1021         while((c = fgetc(fntarray[i])) != 0 && c != EOF)
1022             *cp++ = c;
1023         *cp = '\0';
1024         fwrite(name, strlen(name) + 1, 1, fon);
1025     }
1026 
1027     pad = ftell(fon) & 0xf;
1028     if(pad != 0)
1029         pad = 0x10 - pad;
1030     for(i = 0; i < pad; i++)
1031         fputc(0x00, fon);
1032 
1033     for(res = first_res, i = 0; i < num_files; i++, res++) {
1034         rewind(fntarray[i]);
1035 
1036         while(1) {
1037             nread = fread(buf, 1, sizeof(buf), fntarray[i]);
1038             if(!nread)
1039 	break;
1040             fwrite(buf, nread, 1, fon);
1041         }
1042         fclose(fntarray[i]);
1043         pad = file_lens[i] & 0xf;
1044         if(pad != 0)
1045             pad = 0x10 - pad;
1046         for(j = 0; j < pad; j++)
1047             fputc(0x00, fon);
1048     }
1049     fclose(fon);
1050     free(fntarray);
1051     free(file_lens);
1052 
1053 return true;
1054 }
1055