2 * sfnttofnt. Bitmap only ttf to Window fnt file converter
4 * Copyright 2004 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
36 #ifdef HAVE_FT2BUILD_H
39 #include FT_FREETYPE_H
40 #include FT_SFNT_NAMES_H
41 #include FT_TRUETYPE_TABLES_H
42 #include FT_TRUETYPE_TAGS_H
43 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
44 #include <freetype/internal/sfnt.h>
47 #include "wine/unicode.h"
48 #include "wine/wingdi16.h"
75 CHAR caretSlopeNumerator
;
76 CHAR caretSlopeDenominator
;
87 ULONG indexSubTableArrayOffset
;
89 ULONG numberOfIndexSubTables
;
91 sbitLineMetrics_t hori
;
92 sbitLineMetrics_t vert
;
93 USHORT startGlyphIndex
;
107 static FT_Version_t FT_Version
;
109 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
110 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
111 GET_BE_WORD(&((WORD *)(ptr))[0]) ))
118 CHAR_TABLE_ENTRY dfCharTable
[258];
122 static const BYTE MZ_hdr
[] =
124 'M', 'Z', 0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
125 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
128 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
129 'i', 's', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n', 'n', 'o',
130 't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O', 'S', ' ',
131 'm', 'o', 'd', 'e', 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
134 static char *option_output
;
135 static int option_defchar
= ' ';
136 static int option_dpi
= 96;
137 static int option_fnt_mode
= 0;
138 static int option_quiet
= 0;
140 static const char *output_name
;
142 static FT_Library ft_library
;
144 static void usage(char **argv
)
146 fprintf(stderr
, "%s [options] input.ttf ppem,enc,avg_width ...\n", argv
[0]);
147 fprintf(stderr
, "Options:\n");
148 fprintf(stderr
, " -h Display help\n" );
149 fprintf(stderr
, " -d char Set the font default char\n" );
150 fprintf(stderr
, " -o file Set output file name\n" );
151 fprintf(stderr
, " -q Quiet mode\n" );
152 fprintf(stderr
, " -r dpi Set resolution in DPI (default: 96)\n" );
153 fprintf(stderr
, " -s Single .fnt file mode\n" );
157 #define __attribute__(X)
160 /* atexit handler to cleanup files */
161 static void cleanup(void)
163 if (output_name
) unlink( output_name
);
166 static void exit_on_signal( int sig
)
168 exit(1); /* this will call the atexit functions */
171 static void error(const char *s
, ...) __attribute__((format (printf
, 1, 2)));
173 static void error(const char *s
, ...)
177 fprintf(stderr
, "Error: ");
178 vfprintf(stderr
, s
, ap
);
183 static const char *get_face_name( const struct fontinfo
*info
)
185 return (const char *)info
->data
+ info
->hdr
.fi
.dfFace
- info
->hdr
.fi
.dfBitsOffset
;
188 static int lookup_charset(int enc
)
190 /* FIXME: make winelib app and use TranslateCharsetInfo */
195 return RUSSIAN_CHARSET
;
199 return GREEK_CHARSET
;
201 return TURKISH_CHARSET
;
203 return HEBREW_CHARSET
;
205 return ARABIC_CHARSET
;
207 return BALTIC_CHARSET
;
209 return VIETNAMESE_CHARSET
;
229 return SHIFTJIS_CHARSET
;
231 return GB2312_CHARSET
;
233 return HANGUL_CHARSET
;
235 return CHINESEBIG5_CHARSET
;
237 fprintf(stderr
, "Unknown encoding %d - using OEM_CHARSET\n", enc
);
242 static int get_char(const union cptable
*cptable
, int enc
, int index
)
244 /* Korean has the Won sign in place of '\\' */
245 if(enc
== 949 && index
== '\\')
248 return cptable
->sbcs
.cp2uni
[index
];
251 /* from gdi32/freetype.c */
252 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
257 /* If the FT_Load_Sfnt_Table function is there we'll use it */
258 #ifdef HAVE_FT_LOAD_SFNT_TABLE
259 err
= FT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
260 #elif defined(HAVE_FREETYPE_INTERNAL_SFNT_H)
261 TT_Face tt_face
= (TT_Face
) ft_face
;
262 SFNT_Interface
*sfnt
;
263 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
266 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
270 /* A field was added in the middle of the structure in 2.1.x */
271 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
273 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
275 err
= FT_Err_Unimplemented_Feature
;
280 static struct fontinfo
*fill_fontinfo( const char *face_name
, int ppem
, int enc
, int dpi
,
281 unsigned char def_char
, int avg_width
)
284 int ascent
= 0, il
, el
, descent
= 0, width_bytes
= 0, space_size
, max_width
= 0;
285 BYTE left_byte
, right_byte
, byte
;
287 int i
, x
, y
, x_off
, x_end
, first_char
;
290 const union cptable
*cptable
;
291 FT_SfntName sfntname
;
295 bitmapSizeTable_t
*size_table
;
297 struct fontinfo
*info
;
300 if (FT_New_Face(ft_library
, face_name
, 0, &face
)) error( "Cannot open face %s\n", face_name
);
301 if (FT_Set_Pixel_Sizes(face
, ppem
, ppem
)) error( "cannot set face size to %u\n", ppem
);
303 cptable
= wine_cp_get_table(enc
);
305 error("Can't find codepage %d\n", enc
);
307 if(cptable
->info
.char_size
!= 1) {
308 /* for double byte charsets we actually want to use cp1252 */
309 cptable
= wine_cp_get_table(1252);
311 error("Can't find codepage 1252\n");
314 assert( face
->size
->metrics
.y_ppem
== ppem
);
317 if (load_sfnt_table(face
, TTAG_EBLC
, 0, NULL
, &needed
))
318 fprintf(stderr
,"Can't find EBLC table\n");
321 eblc
= malloc(needed
);
322 load_sfnt_table(face
, TTAG_EBLC
, 0, (FT_Byte
*)eblc
, &needed
);
324 num_sizes
= GET_BE_DWORD(&eblc
->numSizes
);
326 size_table
= (bitmapSizeTable_t
*)(eblc
+ 1);
327 for(i
= 0; i
< num_sizes
; i
++)
329 if(size_table
->hori
.ascender
- size_table
->hori
.descender
== ppem
)
331 ascent
= size_table
->hori
.ascender
;
332 descent
= -size_table
->hori
.descender
;
341 /* Versions of fontforge prior to early 2006 have incorrect
342 ascender values in the eblc table, so we won't find the
343 correct bitmapSizeTable. In this case use the height of
344 the Aring glyph instead. */
347 if(FT_Load_Char(face
, 0xc5, FT_LOAD_DEFAULT
))
348 error("Can't find Aring\n");
349 ascent
= face
->glyph
->metrics
.horiBearingY
>> 6;
350 descent
= ppem
- ascent
;
353 start
= sizeof(FNT_HEADER
);
355 if(FT_Load_Char(face
, 'M', FT_LOAD_DEFAULT
))
356 error("Can't find M\n");
357 il
= ascent
- (face
->glyph
->metrics
.height
>> 6);
359 /* Hack: Courier has no internal leading, nor do any Chinese or Japanese fonts */
360 if(!strcmp(face
->family_name
, "Courier") || enc
== 936 || enc
== 950 || enc
== 932)
362 /* Japanese system fonts have an external leading (not small font) */
363 if (enc
== 932 && ppem
> 11)
368 first_char
= FT_Get_First_Char(face
, &gi
);
369 if(first_char
== 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
370 first_char
= 32; /* FT_Get_Next_Char for some reason returns too high
371 number in this case */
373 info
= calloc( 1, sizeof(*info
) );
375 info
->hdr
.fi
.dfFirstChar
= first_char
;
376 info
->hdr
.fi
.dfLastChar
= 0xff;
377 start
+= ((unsigned char)info
->hdr
.fi
.dfLastChar
- (unsigned char)info
->hdr
.fi
.dfFirstChar
+ 3 ) * sizeof(*info
->dfCharTable
);
379 num_names
= FT_Get_Sfnt_Name_Count(face
);
380 for(i
= 0; i
<num_names
; i
++) {
381 FT_Get_Sfnt_Name(face
, i
, &sfntname
);
382 if(sfntname
.platform_id
== 1 && sfntname
.encoding_id
== 0 &&
383 sfntname
.language_id
== 0 && sfntname
.name_id
== 0) {
384 size_t len
= min( sfntname
.string_len
, sizeof(info
->hdr
.dfCopyright
)-1 );
385 memcpy(info
->hdr
.dfCopyright
, sfntname
.string
, len
);
386 info
->hdr
.dfCopyright
[len
] = 0;
390 os2
= FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
391 for(i
= first_char
; i
< 0x100; i
++) {
392 int c
= get_char(cptable
, enc
, i
);
393 gi
= FT_Get_Char_Index(face
, c
);
394 if(gi
== 0 && !option_quiet
)
395 fprintf(stderr
, "warning: %s %u: missing glyph for char %04x\n",
396 face
->family_name
, ppem
, cptable
->sbcs
.cp2uni
[i
]);
397 if(FT_Load_Char(face
, c
, FT_LOAD_DEFAULT
)) {
398 fprintf(stderr
, "error loading char %d - bad news!\n", i
);
401 info
->dfCharTable
[i
].width
= face
->glyph
->metrics
.horiAdvance
>> 6;
402 info
->dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
403 width_bytes
+= ((face
->glyph
->metrics
.horiAdvance
>> 6) + 7) >> 3;
404 if(max_width
< (face
->glyph
->metrics
.horiAdvance
>> 6))
405 max_width
= face
->glyph
->metrics
.horiAdvance
>> 6;
408 space_size
= (ppem
+ 3) / 4;
409 info
->dfCharTable
[i
].width
= space_size
;
410 info
->dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
411 width_bytes
+= (space_size
+ 7) >> 3;
413 info
->dfCharTable
[++i
].width
= 0;
414 info
->dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
416 info
->hdr
.fi
.dfType
= 0;
417 info
->hdr
.fi
.dfPoints
= ((ppem
- il
) * 72 + dpi
/2) / dpi
;
418 info
->hdr
.fi
.dfVertRes
= dpi
;
419 info
->hdr
.fi
.dfHorizRes
= dpi
;
420 info
->hdr
.fi
.dfAscent
= ascent
;
421 info
->hdr
.fi
.dfInternalLeading
= il
;
422 info
->hdr
.fi
.dfExternalLeading
= el
;
423 info
->hdr
.fi
.dfItalic
= (face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
424 info
->hdr
.fi
.dfUnderline
= 0;
425 info
->hdr
.fi
.dfStrikeOut
= 0;
426 info
->hdr
.fi
.dfWeight
= os2
->usWeightClass
;
427 info
->hdr
.fi
.dfCharSet
= lookup_charset(enc
);
428 info
->hdr
.fi
.dfPixWidth
= (face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
) ? avg_width
: 0;
429 info
->hdr
.fi
.dfPixHeight
= ppem
;
430 info
->hdr
.fi
.dfPitchAndFamily
= FT_IS_FIXED_WIDTH(face
) ? 0 : TMPF_FIXED_PITCH
;
431 switch(os2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
432 case PAN_FAMILY_SCRIPT
:
433 info
->hdr
.fi
.dfPitchAndFamily
|= FF_SCRIPT
;
435 case PAN_FAMILY_DECORATIVE
:
436 case PAN_FAMILY_PICTORIAL
:
437 info
->hdr
.fi
.dfPitchAndFamily
|= FF_DECORATIVE
;
439 case PAN_FAMILY_TEXT_DISPLAY
:
440 if(info
->hdr
.fi
.dfPitchAndFamily
== 0) /* fixed */
441 info
->hdr
.fi
.dfPitchAndFamily
= FF_MODERN
;
443 switch(os2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
444 case PAN_SERIF_NORMAL_SANS
:
445 case PAN_SERIF_OBTUSE_SANS
:
446 case PAN_SERIF_PERP_SANS
:
447 info
->hdr
.fi
.dfPitchAndFamily
|= FF_SWISS
;
450 info
->hdr
.fi
.dfPitchAndFamily
|= FF_ROMAN
;
455 info
->hdr
.fi
.dfPitchAndFamily
|= FF_DONTCARE
;
458 info
->hdr
.fi
.dfAvgWidth
= avg_width
;
459 info
->hdr
.fi
.dfMaxWidth
= max_width
;
460 info
->hdr
.fi
.dfDefaultChar
= def_char
- info
->hdr
.fi
.dfFirstChar
;
461 info
->hdr
.fi
.dfBreakChar
= ' ' - info
->hdr
.fi
.dfFirstChar
;
462 info
->hdr
.fi
.dfWidthBytes
= (width_bytes
+ 1) & ~1;
464 info
->hdr
.fi
.dfFace
= start
+ info
->hdr
.fi
.dfWidthBytes
* ppem
;
465 info
->hdr
.fi
.dfBitsOffset
= start
;
466 info
->hdr
.fi
.dfFlags
= 0x10; /* DFF_1COLOR */
467 info
->hdr
.fi
.dfFlags
|= FT_IS_FIXED_WIDTH(face
) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
469 info
->hdr
.dfVersion
= 0x300;
470 info
->hdr
.dfSize
= start
+ info
->hdr
.fi
.dfWidthBytes
* ppem
+ strlen(face
->family_name
) + 1;
472 info
->data
= calloc( info
->hdr
.dfSize
- start
, 1 );
475 for(i
= first_char
; i
< 0x100; i
++) {
476 int c
= get_char(cptable
, enc
, i
);
477 if(FT_Load_Char(face
, c
, FT_LOAD_DEFAULT
)) {
480 assert(info
->dfCharTable
[i
].width
== face
->glyph
->metrics
.horiAdvance
>> 6);
482 for(x
= 0; x
< ((info
->dfCharTable
[i
].width
+ 7) / 8); x
++) {
483 for(y
= 0; y
< ppem
; y
++) {
484 if(y
< ascent
- face
->glyph
->bitmap_top
||
485 y
>= face
->glyph
->bitmap
.rows
+ ascent
- face
->glyph
->bitmap_top
) {
486 info
->data
[data_pos
++] = 0;
489 x_off
= face
->glyph
->bitmap_left
/ 8;
490 x_end
= (face
->glyph
->bitmap_left
+ face
->glyph
->bitmap
.width
- 1) / 8;
491 if(x
< x_off
|| x
> x_end
) {
492 info
->data
[data_pos
++] = 0;
498 left_byte
= face
->glyph
->bitmap
.buffer
[(y
- (ascent
- face
->glyph
->bitmap_top
)) * face
->glyph
->bitmap
.pitch
+ x
- x_off
- 1];
500 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
501 if(x
== x_end
&& (face
->glyph
->bitmap_left
% 8 != 0) && ((face
->glyph
->bitmap
.width
% 8 == 0) || (x
!= (((face
->glyph
->bitmap
.width
) & ~0x7) + face
->glyph
->bitmap_left
) / 8)))
504 right_byte
= face
->glyph
->bitmap
.buffer
[(y
- (ascent
- face
->glyph
->bitmap_top
)) * face
->glyph
->bitmap
.pitch
+ x
- x_off
];
506 byte
= (left_byte
<< (8 - (face
->glyph
->bitmap_left
& 7))) & 0xff;
507 byte
|= ((right_byte
>> (face
->glyph
->bitmap_left
& 7)) & 0xff);
508 info
->data
[data_pos
++] = byte
;
512 data_pos
+= ((space_size
+ 7) / 8) * ppem
;
513 if (width_bytes
& 1) data_pos
+= ppem
;
515 memcpy( info
->data
+ data_pos
, face
->family_name
, strlen( face
->family_name
));
516 data_pos
+= strlen( face
->family_name
) + 1;
517 assert( start
+ data_pos
== info
->hdr
.dfSize
);
519 FT_Done_Face( face
);
523 static void write_fontinfo( const struct fontinfo
*info
, FILE *fp
)
525 fwrite( &info
->hdr
, sizeof(info
->hdr
), 1, fp
);
526 fwrite( info
->dfCharTable
+ info
->hdr
.fi
.dfFirstChar
, sizeof(*info
->dfCharTable
),
527 ((unsigned char)info
->hdr
.fi
.dfLastChar
- (unsigned char)info
->hdr
.fi
.dfFirstChar
) + 3, fp
);
528 fwrite( info
->data
, info
->hdr
.dfSize
- info
->hdr
.fi
.dfBitsOffset
, 1, fp
);
531 /* parse options from the argv array and remove all the recognized ones */
532 static char **parse_options( int argc
, char **argv
)
536 while ((optc
= getopt( argc
, argv
, "d:ho:qr:s" )) != -1)
541 option_defchar
= atoi( optarg
);
544 option_output
= strdup( optarg
);
550 option_dpi
= atoi( optarg
);
563 return &argv
[optind
];
566 int main(int argc
, char **argv
)
570 short align
, num_files
;
571 int resource_table_len
, non_resident_name_len
, resident_name_len
;
572 unsigned short resource_table_off
, resident_name_off
, module_ref_off
, non_resident_name_off
, fontdir_off
, font_off
;
573 char resident_name
[200];
575 char non_resident_name
[200];
576 unsigned short first_res
= 0x0050, pad
, res
;
577 IMAGE_OS2_HEADER NE_hdr
;
580 struct fontinfo
**info
;
584 args
= parse_options( argc
, argv
);
586 input_file
= *args
++;
587 if (!input_file
|| !*args
)
593 if(FT_Init_FreeType(&ft_library
))
594 error("ft init failure\n");
596 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
597 FT_Library_Version(ft_library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
600 while (args
[num_files
]) num_files
++;
602 if (option_fnt_mode
&& num_files
> 1)
603 error( "can only specify one font in .fnt mode\n" );
605 info
= malloc( num_files
* sizeof(*info
) );
606 for (i
= 0; i
< num_files
; i
++)
608 int ppem
, enc
, avg_width
;
611 if (sscanf( args
[i
], "%d,%d,%d", &ppem
, &enc
, &avg_width
) != 3)
616 if (!(info
[i
] = fill_fontinfo( input_file
, ppem
, enc
, option_dpi
, option_defchar
, avg_width
)))
619 name
= get_face_name( info
[i
] );
620 fontdir_len
+= 0x74 + strlen(name
) + 1;
622 sprintf(non_resident_name
, "FONTRES 100,%d,%d : %s %d",
623 info
[i
]->hdr
.fi
.dfVertRes
, info
[i
]->hdr
.fi
.dfHorizRes
,
624 name
, info
[i
]->hdr
.fi
.dfPoints
);
625 strcpy(resident_name
, name
);
627 sprintf(non_resident_name
+ strlen(non_resident_name
), ",%d", info
[i
]->hdr
.fi
.dfPoints
);
631 if (option_dpi
<= 108)
632 strcat(non_resident_name
, " (VGA res)");
634 strcat(non_resident_name
, " (8514 res)");
635 non_resident_name_len
= strlen(non_resident_name
) + 4;
637 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
638 resource_table_len
= sizeof(align
) + sizeof("FONTDIR") +
639 sizeof(NE_TYPEINFO
) + sizeof(NE_NAMEINFO
) +
640 sizeof(NE_TYPEINFO
) + sizeof(NE_NAMEINFO
) * num_files
+
642 resource_table_off
= sizeof(NE_hdr
);
643 resident_name_off
= resource_table_off
+ resource_table_len
;
644 resident_name_len
= strlen(resident_name
) + 4;
645 module_ref_off
= resident_name_off
+ resident_name_len
;
646 non_resident_name_off
= sizeof(MZ_hdr
) + module_ref_off
+ sizeof(align
);
648 memset(&NE_hdr
, 0, sizeof(NE_hdr
));
649 NE_hdr
.ne_magic
= 0x454e;
652 NE_hdr
.ne_flags
= NE_FFLAGS_LIBMODULE
| NE_FFLAGS_GUI
;
653 NE_hdr
.ne_cbnrestab
= non_resident_name_len
;
654 NE_hdr
.ne_segtab
= sizeof(NE_hdr
);
655 NE_hdr
.ne_rsrctab
= sizeof(NE_hdr
);
656 NE_hdr
.ne_restab
= resident_name_off
;
657 NE_hdr
.ne_modtab
= module_ref_off
;
658 NE_hdr
.ne_imptab
= module_ref_off
;
659 NE_hdr
.ne_enttab
= NE_hdr
.ne_modtab
;
660 NE_hdr
.ne_nrestab
= non_resident_name_off
;
662 NE_hdr
.ne_exetyp
= NE_OSFLAGS_WINDOWS
;
663 NE_hdr
.ne_expver
= 0x400;
665 fontdir_off
= (non_resident_name_off
+ non_resident_name_len
+ 15) & ~0xf;
666 font_off
= (fontdir_off
+ fontdir_len
+ 15) & ~0x0f;
669 signal( SIGTERM
, exit_on_signal
);
670 signal( SIGINT
, exit_on_signal
);
672 signal( SIGHUP
, exit_on_signal
);
675 if (!option_output
) /* build a default output name */
677 char *p
= strrchr( input_file
, '/' );
680 option_output
= malloc( strlen(p
) + sizeof(".fon") );
681 strcpy( option_output
, p
);
682 p
= strrchr( option_output
, '.' );
683 if (!p
) p
= option_output
+ strlen(option_output
);
684 strcpy( p
, option_fnt_mode
? ".fnt" : ".fon" );
687 if (!(ofp
= fopen(option_output
, "wb")))
689 perror( option_output
);
692 output_name
= option_output
;
695 write_fontinfo( info
[0], ofp
);
699 fwrite(MZ_hdr
, sizeof(MZ_hdr
), 1, ofp
);
700 fwrite(&NE_hdr
, sizeof(NE_hdr
), 1, ofp
);
703 fwrite(&align
, sizeof(align
), 1, ofp
);
705 rc_type
.type_id
= NE_RSCTYPE_FONTDIR
;
707 rc_type
.resloader
= 0;
708 fwrite(&rc_type
, sizeof(rc_type
), 1, ofp
);
710 rc_name
.offset
= fontdir_off
>> 4;
711 rc_name
.length
= (fontdir_len
+ 15) >> 4;
712 rc_name
.flags
= NE_SEGFLAGS_MOVEABLE
| NE_SEGFLAGS_PRELOAD
;
713 rc_name
.id
= resident_name_off
- sizeof("FONTDIR") - NE_hdr
.ne_rsrctab
;
716 fwrite(&rc_name
, sizeof(rc_name
), 1, ofp
);
718 rc_type
.type_id
= NE_RSCTYPE_FONT
;
719 rc_type
.count
= num_files
;
720 rc_type
.resloader
= 0;
721 fwrite(&rc_type
, sizeof(rc_type
), 1, ofp
);
723 for(res
= first_res
| 0x8000, i
= 0; i
< num_files
; i
++, res
++) {
724 int len
= (info
[i
]->hdr
.dfSize
+ 15) & ~0xf;
726 rc_name
.offset
= font_off
>> 4;
727 rc_name
.length
= len
>> 4;
728 rc_name
.flags
= NE_SEGFLAGS_MOVEABLE
| NE_SEGFLAGS_SHAREABLE
| NE_SEGFLAGS_DISCARDABLE
;
732 fwrite(&rc_name
, sizeof(rc_name
), 1, ofp
);
737 /* empty type info */
738 memset(&rc_type
, 0, sizeof(rc_type
));
739 fwrite(&rc_type
, sizeof(rc_type
), 1, ofp
);
741 fputc(strlen("FONTDIR"), ofp
);
742 fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp
);
743 fputc(strlen(resident_name
), ofp
);
744 fwrite(resident_name
, strlen(resident_name
), 1, ofp
);
746 fputc(0x00, ofp
); fputc(0x00, ofp
);
748 fputc(0x00, ofp
); fputc(0x00, ofp
);
750 fputc(strlen(non_resident_name
), ofp
);
751 fwrite(non_resident_name
, strlen(non_resident_name
), 1, ofp
);
752 fputc(0x00, ofp
); /* terminator */
754 /* empty ne_modtab and ne_imptab */
758 pad
= ftell(ofp
) & 0xf;
761 for(i
= 0; i
< pad
; i
++)
764 /* FONTDIR resource */
765 fwrite(&num_files
, sizeof(num_files
), 1, ofp
);
767 for(res
= first_res
, i
= 0; i
< num_files
; i
++, res
++) {
768 const char *name
= get_face_name( info
[i
] );
769 fwrite(&res
, sizeof(res
), 1, ofp
);
770 fwrite(&info
[i
]->hdr
, FIELD_OFFSET(FNT_HEADER
,fi
.dfBitsOffset
), 1, ofp
);
772 fwrite(name
, strlen(name
) + 1, 1, ofp
);
775 pad
= ftell(ofp
) & 0xf;
778 for(i
= 0; i
< pad
; i
++)
781 for(res
= first_res
, i
= 0; i
< num_files
; i
++, res
++) {
782 write_fontinfo( info
[i
], ofp
);
783 pad
= info
[i
]->hdr
.dfSize
& 0xf;
786 for(j
= 0; j
< pad
; j
++)
795 #else /* HAVE_FREETYPE */
797 int main(int argc
, char **argv
)
799 fprintf( stderr
, "%s needs to be built with FreeType support\n", argv
[0] );
803 #endif /* HAVE_FREETYPE */