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