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
44 #include "wine/unicode.h"
56 INT16 dfInternalLeading
;
57 INT16 dfExternalLeading
;
65 BYTE dfPitchAndFamily
;
111 #define NE_FFLAGS_SINGLEDATA 0x0001
112 #define NE_FFLAGS_MULTIPLEDATA 0x0002
113 #define NE_FFLAGS_WIN32 0x0010
114 #define NE_FFLAGS_FRAMEBUF 0x0100
115 #define NE_FFLAGS_CONSOLE 0x0200
116 #define NE_FFLAGS_GUI 0x0300
117 #define NE_FFLAGS_SELFLOAD 0x0800
118 #define NE_FFLAGS_LINKERROR 0x2000
119 #define NE_FFLAGS_CALLWEP 0x4000
120 #define NE_FFLAGS_LIBMODULE 0x8000
122 #define NE_OSFLAGS_WINDOWS 0x02
124 #define NE_RSCTYPE_FONTDIR 0x8007
125 #define NE_RSCTYPE_FONT 0x8008
126 #define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
128 #define NE_SEGFLAGS_DATA 0x0001
129 #define NE_SEGFLAGS_ALLOCATED 0x0002
130 #define NE_SEGFLAGS_LOADED 0x0004
131 #define NE_SEGFLAGS_ITERATED 0x0008
132 #define NE_SEGFLAGS_MOVEABLE 0x0010
133 #define NE_SEGFLAGS_SHAREABLE 0x0020
134 #define NE_SEGFLAGS_PRELOAD 0x0040
135 #define NE_SEGFLAGS_EXECUTEONLY 0x0080
136 #define NE_SEGFLAGS_READONLY 0x0080
137 #define NE_SEGFLAGS_RELOC_DATA 0x0100
138 #define NE_SEGFLAGS_SELFLOAD 0x0800
139 #define NE_SEGFLAGS_DISCARDABLE 0x1000
140 #define NE_SEGFLAGS_32BIT 0x2000
156 CHAR caretSlopeNumerator
;
157 CHAR caretSlopeDenominator
;
168 ULONG indexSubTableArrayOffset
;
169 ULONG indexTableSize
;
170 ULONG numberOfIndexSubTables
;
172 sbitLineMetrics_t hori
;
173 sbitLineMetrics_t vert
;
174 USHORT startGlyphIndex
;
175 USHORT endGlyphIndex
;
188 static FT_Version_t FT_Version
;
190 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
191 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
192 GET_BE_WORD(&((WORD *)(ptr))[0]) ))
199 CHAR_TABLE_ENTRY dfCharTable
[258];
203 static const BYTE MZ_hdr
[] =
205 'M', 'Z', 0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
206 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
209 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
210 'i', 's', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n', 'n', 'o',
211 't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O', 'S', ' ',
212 'm', 'o', 'd', 'e', 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
215 static char *option_output
;
216 static int option_defchar
= ' ';
217 static int option_dpi
= 96;
218 static int option_fnt_mode
= 0;
219 static int option_quiet
= 0;
221 static const char *output_name
;
223 static FT_Library ft_library
;
225 static void usage(char **argv
)
227 fprintf(stderr
, "%s [options] input.ttf ppem,enc,avg_width ...\n", argv
[0]);
228 fprintf(stderr
, "Options:\n");
229 fprintf(stderr
, " -h Display help\n" );
230 fprintf(stderr
, " -d char Set the font default char\n" );
231 fprintf(stderr
, " -o file Set output file name\n" );
232 fprintf(stderr
, " -q Quiet mode\n" );
233 fprintf(stderr
, " -r dpi Set resolution in DPI (default: 96)\n" );
234 fprintf(stderr
, " -s Single .fnt file mode\n" );
238 #define __attribute__(X)
241 /* atexit handler to cleanup files */
242 static void cleanup(void)
244 if (output_name
) unlink( output_name
);
247 static void exit_on_signal( int sig
)
249 exit(1); /* this will call the atexit functions */
252 static void error(const char *s
, ...) __attribute__((format (printf
, 1, 2)));
254 static void error(const char *s
, ...)
258 fprintf(stderr
, "Error: ");
259 vfprintf(stderr
, s
, ap
);
264 static const char *get_face_name( const struct fontinfo
*info
)
266 return (const char *)info
->data
+ info
->hdr
.fi
.dfFace
- info
->hdr
.fi
.dfBitsOffset
;
269 static int lookup_charset(int enc
)
271 /* FIXME: make winelib app and use TranslateCharsetInfo */
276 return RUSSIAN_CHARSET
;
280 return GREEK_CHARSET
;
282 return TURKISH_CHARSET
;
284 return HEBREW_CHARSET
;
286 return ARABIC_CHARSET
;
288 return BALTIC_CHARSET
;
290 return VIETNAMESE_CHARSET
;
310 return SHIFTJIS_CHARSET
;
312 return GB2312_CHARSET
;
314 return HANGUL_CHARSET
;
316 return CHINESEBIG5_CHARSET
;
318 fprintf(stderr
, "Unknown encoding %d - using OEM_CHARSET\n", enc
);
323 static int get_char(const union cptable
*cptable
, int enc
, int index
)
325 /* Korean has the Won sign in place of '\\' */
326 if(enc
== 949 && index
== '\\')
329 return cptable
->sbcs
.cp2uni
[index
];
332 static struct fontinfo
*fill_fontinfo( const char *face_name
, int ppem
, int enc
, int dpi
,
333 unsigned char def_char
, int avg_width
)
336 int ascent
= 0, il
, el
, width_bytes
= 0, space_size
, max_width
= 0;
337 BYTE left_byte
, right_byte
, byte
;
339 int i
, x
, y
, x_off
, x_end
, first_char
;
342 const union cptable
*cptable
;
343 FT_SfntName sfntname
;
347 bitmapSizeTable_t
*size_table
;
349 struct fontinfo
*info
;
352 if (FT_New_Face(ft_library
, face_name
, 0, &face
)) error( "Cannot open face %s\n", face_name
);
353 if (FT_Set_Pixel_Sizes(face
, ppem
, ppem
)) error( "cannot set face size to %u\n", ppem
);
355 cptable
= wine_cp_get_table(enc
);
357 error("Can't find codepage %d\n", enc
);
359 if(cptable
->info
.char_size
!= 1) {
360 /* for double byte charsets we actually want to use cp1252 */
361 cptable
= wine_cp_get_table(1252);
363 error("Can't find codepage 1252\n");
366 assert( face
->size
->metrics
.y_ppem
== ppem
);
369 if (FT_Load_Sfnt_Table(face
, TTAG_EBLC
, 0, NULL
, &needed
))
370 fprintf(stderr
,"Can't find EBLC table\n");
373 eblc
= malloc(needed
);
374 FT_Load_Sfnt_Table(face
, TTAG_EBLC
, 0, (FT_Byte
*)eblc
, &needed
);
376 num_sizes
= GET_BE_DWORD(&eblc
->numSizes
);
378 size_table
= (bitmapSizeTable_t
*)(eblc
+ 1);
379 for(i
= 0; i
< num_sizes
; i
++)
381 if(size_table
->hori
.ascender
- size_table
->hori
.descender
== ppem
)
383 ascent
= size_table
->hori
.ascender
;
392 /* Versions of fontforge prior to early 2006 have incorrect
393 ascender values in the eblc table, so we won't find the
394 correct bitmapSizeTable. In this case use the height of
395 the Aring glyph instead. */
398 if(FT_Load_Char(face
, 0xc5, FT_LOAD_DEFAULT
))
399 error("Can't find Aring\n");
400 ascent
= face
->glyph
->metrics
.horiBearingY
>> 6;
403 start
= sizeof(FNT_HEADER
);
405 if(FT_Load_Char(face
, 'M', FT_LOAD_DEFAULT
))
406 error("Can't find M\n");
407 il
= ascent
- (face
->glyph
->metrics
.height
>> 6);
409 /* Hack: Courier has no internal leading, nor do any Chinese or Japanese fonts */
410 if(!strcmp(face
->family_name
, "Courier") || enc
== 936 || enc
== 950 || enc
== 932)
412 /* Japanese system fonts have an external leading (not small font) */
413 if (enc
== 932 && ppem
> 11)
418 first_char
= FT_Get_First_Char(face
, &gi
);
419 if(first_char
== 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
420 first_char
= 32; /* FT_Get_Next_Char for some reason returns too high
421 number in this case */
423 info
= calloc( 1, sizeof(*info
) );
425 info
->hdr
.fi
.dfFirstChar
= first_char
;
426 info
->hdr
.fi
.dfLastChar
= 0xff;
427 start
+= ((unsigned char)info
->hdr
.fi
.dfLastChar
- (unsigned char)info
->hdr
.fi
.dfFirstChar
+ 3 ) * sizeof(*info
->dfCharTable
);
429 num_names
= FT_Get_Sfnt_Name_Count(face
);
430 for(i
= 0; i
<num_names
; i
++) {
431 FT_Get_Sfnt_Name(face
, i
, &sfntname
);
432 if(sfntname
.platform_id
== 1 && sfntname
.encoding_id
== 0 &&
433 sfntname
.language_id
== 0 && sfntname
.name_id
== 0) {
434 size_t len
= min( sfntname
.string_len
, sizeof(info
->hdr
.dfCopyright
)-1 );
435 memcpy(info
->hdr
.dfCopyright
, sfntname
.string
, len
);
436 info
->hdr
.dfCopyright
[len
] = 0;
440 os2
= FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
441 for(i
= first_char
; i
< 0x100; i
++) {
442 int c
= get_char(cptable
, enc
, i
);
443 gi
= FT_Get_Char_Index(face
, c
);
444 if(gi
== 0 && !option_quiet
)
445 fprintf(stderr
, "warning: %s %u: missing glyph for char %04x\n",
446 face
->family_name
, ppem
, cptable
->sbcs
.cp2uni
[i
]);
447 if(FT_Load_Char(face
, c
, FT_LOAD_DEFAULT
)) {
448 fprintf(stderr
, "error loading char %d - bad news!\n", i
);
451 info
->dfCharTable
[i
].width
= face
->glyph
->metrics
.horiAdvance
>> 6;
452 info
->dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
453 width_bytes
+= ((face
->glyph
->metrics
.horiAdvance
>> 6) + 7) >> 3;
454 if(max_width
< (face
->glyph
->metrics
.horiAdvance
>> 6))
455 max_width
= face
->glyph
->metrics
.horiAdvance
>> 6;
458 space_size
= (ppem
+ 3) / 4;
459 info
->dfCharTable
[i
].width
= space_size
;
460 info
->dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
461 width_bytes
+= (space_size
+ 7) >> 3;
463 info
->dfCharTable
[++i
].width
= 0;
464 info
->dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
466 info
->hdr
.fi
.dfType
= 0;
467 info
->hdr
.fi
.dfPoints
= ((ppem
- il
- el
) * 72 + dpi
/2) / dpi
;
468 info
->hdr
.fi
.dfVertRes
= dpi
;
469 info
->hdr
.fi
.dfHorizRes
= dpi
;
470 info
->hdr
.fi
.dfAscent
= ascent
;
471 info
->hdr
.fi
.dfInternalLeading
= il
;
472 info
->hdr
.fi
.dfExternalLeading
= el
;
473 info
->hdr
.fi
.dfItalic
= (face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
474 info
->hdr
.fi
.dfUnderline
= 0;
475 info
->hdr
.fi
.dfStrikeOut
= 0;
476 info
->hdr
.fi
.dfWeight
= os2
->usWeightClass
;
477 info
->hdr
.fi
.dfCharSet
= lookup_charset(enc
);
478 info
->hdr
.fi
.dfPixWidth
= (face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
) ? avg_width
: 0;
479 info
->hdr
.fi
.dfPixHeight
= ppem
;
480 info
->hdr
.fi
.dfPitchAndFamily
= FT_IS_FIXED_WIDTH(face
) ? 0 : TMPF_FIXED_PITCH
;
481 switch(os2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
482 case PAN_FAMILY_SCRIPT
:
483 info
->hdr
.fi
.dfPitchAndFamily
|= FF_SCRIPT
;
485 case PAN_FAMILY_DECORATIVE
:
486 case PAN_FAMILY_PICTORIAL
:
487 info
->hdr
.fi
.dfPitchAndFamily
|= FF_DECORATIVE
;
489 case PAN_FAMILY_TEXT_DISPLAY
:
490 if(info
->hdr
.fi
.dfPitchAndFamily
== 0) /* fixed */
491 info
->hdr
.fi
.dfPitchAndFamily
= FF_MODERN
;
493 switch(os2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
494 case PAN_SERIF_NORMAL_SANS
:
495 case PAN_SERIF_OBTUSE_SANS
:
496 case PAN_SERIF_PERP_SANS
:
497 info
->hdr
.fi
.dfPitchAndFamily
|= FF_SWISS
;
500 info
->hdr
.fi
.dfPitchAndFamily
|= FF_ROMAN
;
505 info
->hdr
.fi
.dfPitchAndFamily
|= FF_DONTCARE
;
508 info
->hdr
.fi
.dfAvgWidth
= avg_width
;
509 info
->hdr
.fi
.dfMaxWidth
= max_width
;
510 info
->hdr
.fi
.dfDefaultChar
= def_char
- info
->hdr
.fi
.dfFirstChar
;
511 info
->hdr
.fi
.dfBreakChar
= ' ' - info
->hdr
.fi
.dfFirstChar
;
512 info
->hdr
.fi
.dfWidthBytes
= (width_bytes
+ 1) & ~1;
514 info
->hdr
.fi
.dfFace
= start
+ info
->hdr
.fi
.dfWidthBytes
* ppem
;
515 info
->hdr
.fi
.dfBitsOffset
= start
;
516 info
->hdr
.fi
.dfFlags
= 0x10; /* DFF_1COLOR */
517 info
->hdr
.fi
.dfFlags
|= FT_IS_FIXED_WIDTH(face
) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
519 info
->hdr
.dfVersion
= 0x300;
520 info
->hdr
.dfSize
= start
+ info
->hdr
.fi
.dfWidthBytes
* ppem
+ strlen(face
->family_name
) + 1;
522 info
->data
= calloc( info
->hdr
.dfSize
- start
, 1 );
525 for(i
= first_char
; i
< 0x100; i
++) {
526 int c
= get_char(cptable
, enc
, i
);
527 if(FT_Load_Char(face
, c
, FT_LOAD_DEFAULT
)) {
530 assert(info
->dfCharTable
[i
].width
== face
->glyph
->metrics
.horiAdvance
>> 6);
532 for(x
= 0; x
< ((info
->dfCharTable
[i
].width
+ 7) / 8); x
++) {
533 for(y
= 0; y
< ppem
; y
++) {
534 if(y
< ascent
- face
->glyph
->bitmap_top
||
535 y
>= face
->glyph
->bitmap
.rows
+ ascent
- face
->glyph
->bitmap_top
) {
536 info
->data
[data_pos
++] = 0;
539 x_off
= face
->glyph
->bitmap_left
/ 8;
540 x_end
= (face
->glyph
->bitmap_left
+ face
->glyph
->bitmap
.width
- 1) / 8;
541 if(x
< x_off
|| x
> x_end
) {
542 info
->data
[data_pos
++] = 0;
548 left_byte
= face
->glyph
->bitmap
.buffer
[(y
- (ascent
- face
->glyph
->bitmap_top
)) * face
->glyph
->bitmap
.pitch
+ x
- x_off
- 1];
550 /* On the last non-trivial output byte (x == x_end) have we got one or two input bytes */
551 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)))
554 right_byte
= face
->glyph
->bitmap
.buffer
[(y
- (ascent
- face
->glyph
->bitmap_top
)) * face
->glyph
->bitmap
.pitch
+ x
- x_off
];
556 byte
= (left_byte
<< (8 - (face
->glyph
->bitmap_left
& 7))) & 0xff;
557 byte
|= ((right_byte
>> (face
->glyph
->bitmap_left
& 7)) & 0xff);
558 info
->data
[data_pos
++] = byte
;
562 data_pos
+= ((space_size
+ 7) / 8) * ppem
;
563 if (width_bytes
& 1) data_pos
+= ppem
;
565 memcpy( info
->data
+ data_pos
, face
->family_name
, strlen( face
->family_name
));
566 data_pos
+= strlen( face
->family_name
) + 1;
567 assert( start
+ data_pos
== info
->hdr
.dfSize
);
569 FT_Done_Face( face
);
573 static void write_fontinfo( const struct fontinfo
*info
, FILE *fp
)
575 fwrite( &info
->hdr
, sizeof(info
->hdr
), 1, fp
);
576 fwrite( info
->dfCharTable
+ info
->hdr
.fi
.dfFirstChar
, sizeof(*info
->dfCharTable
),
577 ((unsigned char)info
->hdr
.fi
.dfLastChar
- (unsigned char)info
->hdr
.fi
.dfFirstChar
) + 3, fp
);
578 fwrite( info
->data
, info
->hdr
.dfSize
- info
->hdr
.fi
.dfBitsOffset
, 1, fp
);
581 /* parse options from the argv array and remove all the recognized ones */
582 static char **parse_options( int argc
, char **argv
)
586 while ((optc
= getopt( argc
, argv
, "d:ho:qr:s" )) != -1)
591 option_defchar
= atoi( optarg
);
594 option_output
= strdup( optarg
);
600 option_dpi
= atoi( optarg
);
613 return &argv
[optind
];
616 int main(int argc
, char **argv
)
620 short align
, num_files
;
621 int resource_table_len
, non_resident_name_len
, resident_name_len
;
622 unsigned short resource_table_off
, resident_name_off
, module_ref_off
, non_resident_name_off
, fontdir_off
, font_off
;
623 char resident_name
[200];
625 char non_resident_name
[200];
626 unsigned short first_res
= 0x0050, pad
, res
;
627 IMAGE_OS2_HEADER NE_hdr
;
630 struct fontinfo
**info
;
634 args
= parse_options( argc
, argv
);
636 input_file
= *args
++;
637 if (!input_file
|| !*args
)
643 if(FT_Init_FreeType(&ft_library
))
644 error("ft init failure\n");
646 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
647 FT_Library_Version(ft_library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
650 while (args
[num_files
]) num_files
++;
652 if (option_fnt_mode
&& num_files
> 1)
653 error( "can only specify one font in .fnt mode\n" );
655 info
= malloc( num_files
* sizeof(*info
) );
656 for (i
= 0; i
< num_files
; i
++)
658 int ppem
, enc
, avg_width
;
661 if (sscanf( args
[i
], "%d,%d,%d", &ppem
, &enc
, &avg_width
) != 3)
666 if (!(info
[i
] = fill_fontinfo( input_file
, ppem
, enc
, option_dpi
, option_defchar
, avg_width
)))
669 name
= get_face_name( info
[i
] );
670 fontdir_len
+= 0x74 + strlen(name
) + 1;
672 sprintf(non_resident_name
, "FONTRES 100,%d,%d : %s %d",
673 info
[i
]->hdr
.fi
.dfVertRes
, info
[i
]->hdr
.fi
.dfHorizRes
,
674 name
, info
[i
]->hdr
.fi
.dfPoints
);
675 strcpy(resident_name
, name
);
677 sprintf(non_resident_name
+ strlen(non_resident_name
), ",%d", info
[i
]->hdr
.fi
.dfPoints
);
681 if (option_dpi
<= 108)
682 strcat(non_resident_name
, " (VGA res)");
684 strcat(non_resident_name
, " (8514 res)");
685 non_resident_name_len
= strlen(non_resident_name
) + 4;
687 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
688 resource_table_len
= sizeof(align
) + sizeof("FONTDIR") +
689 sizeof(NE_TYPEINFO
) + sizeof(NE_NAMEINFO
) +
690 sizeof(NE_TYPEINFO
) + sizeof(NE_NAMEINFO
) * num_files
+
692 resource_table_off
= sizeof(NE_hdr
);
693 resident_name_off
= resource_table_off
+ resource_table_len
;
694 resident_name_len
= strlen(resident_name
) + 4;
695 module_ref_off
= resident_name_off
+ resident_name_len
;
696 non_resident_name_off
= sizeof(MZ_hdr
) + module_ref_off
+ sizeof(align
);
698 memset(&NE_hdr
, 0, sizeof(NE_hdr
));
699 NE_hdr
.ne_magic
= 0x454e;
702 NE_hdr
.ne_flags
= NE_FFLAGS_LIBMODULE
| NE_FFLAGS_GUI
;
703 NE_hdr
.ne_cbnrestab
= non_resident_name_len
;
704 NE_hdr
.ne_segtab
= sizeof(NE_hdr
);
705 NE_hdr
.ne_rsrctab
= sizeof(NE_hdr
);
706 NE_hdr
.ne_restab
= resident_name_off
;
707 NE_hdr
.ne_modtab
= module_ref_off
;
708 NE_hdr
.ne_imptab
= module_ref_off
;
709 NE_hdr
.ne_enttab
= NE_hdr
.ne_modtab
;
710 NE_hdr
.ne_nrestab
= non_resident_name_off
;
712 NE_hdr
.ne_exetyp
= NE_OSFLAGS_WINDOWS
;
713 NE_hdr
.ne_expver
= 0x400;
715 fontdir_off
= (non_resident_name_off
+ non_resident_name_len
+ 15) & ~0xf;
716 font_off
= (fontdir_off
+ fontdir_len
+ 15) & ~0x0f;
719 signal( SIGTERM
, exit_on_signal
);
720 signal( SIGINT
, exit_on_signal
);
722 signal( SIGHUP
, exit_on_signal
);
725 if (!option_output
) /* build a default output name */
727 char *p
= strrchr( input_file
, '/' );
730 option_output
= malloc( strlen(p
) + sizeof(".fon") );
731 strcpy( option_output
, p
);
732 p
= strrchr( option_output
, '.' );
733 if (!p
) p
= option_output
+ strlen(option_output
);
734 strcpy( p
, option_fnt_mode
? ".fnt" : ".fon" );
737 if (!(ofp
= fopen(option_output
, "wb")))
739 perror( option_output
);
742 output_name
= option_output
;
745 write_fontinfo( info
[0], ofp
);
749 fwrite(MZ_hdr
, sizeof(MZ_hdr
), 1, ofp
);
750 fwrite(&NE_hdr
, sizeof(NE_hdr
), 1, ofp
);
753 fwrite(&align
, sizeof(align
), 1, ofp
);
755 rc_type
.type_id
= NE_RSCTYPE_FONTDIR
;
757 rc_type
.resloader
= 0;
758 fwrite(&rc_type
, sizeof(rc_type
), 1, ofp
);
760 rc_name
.offset
= fontdir_off
>> 4;
761 rc_name
.length
= (fontdir_len
+ 15) >> 4;
762 rc_name
.flags
= NE_SEGFLAGS_MOVEABLE
| NE_SEGFLAGS_PRELOAD
;
763 rc_name
.id
= resident_name_off
- sizeof("FONTDIR") - NE_hdr
.ne_rsrctab
;
766 fwrite(&rc_name
, sizeof(rc_name
), 1, ofp
);
768 rc_type
.type_id
= NE_RSCTYPE_FONT
;
769 rc_type
.count
= num_files
;
770 rc_type
.resloader
= 0;
771 fwrite(&rc_type
, sizeof(rc_type
), 1, ofp
);
773 for(res
= first_res
| 0x8000, i
= 0; i
< num_files
; i
++, res
++) {
774 int len
= (info
[i
]->hdr
.dfSize
+ 15) & ~0xf;
776 rc_name
.offset
= font_off
>> 4;
777 rc_name
.length
= len
>> 4;
778 rc_name
.flags
= NE_SEGFLAGS_MOVEABLE
| NE_SEGFLAGS_SHAREABLE
| NE_SEGFLAGS_DISCARDABLE
;
782 fwrite(&rc_name
, sizeof(rc_name
), 1, ofp
);
787 /* empty type info */
788 memset(&rc_type
, 0, sizeof(rc_type
));
789 fwrite(&rc_type
, sizeof(rc_type
), 1, ofp
);
791 fputc(strlen("FONTDIR"), ofp
);
792 fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp
);
793 fputc(strlen(resident_name
), ofp
);
794 fwrite(resident_name
, strlen(resident_name
), 1, ofp
);
796 fputc(0x00, ofp
); fputc(0x00, ofp
);
798 fputc(0x00, ofp
); fputc(0x00, ofp
);
800 fputc(strlen(non_resident_name
), ofp
);
801 fwrite(non_resident_name
, strlen(non_resident_name
), 1, ofp
);
802 fputc(0x00, ofp
); /* terminator */
804 /* empty ne_modtab and ne_imptab */
808 pad
= ftell(ofp
) & 0xf;
811 for(i
= 0; i
< pad
; i
++)
814 /* FONTDIR resource */
815 fwrite(&num_files
, sizeof(num_files
), 1, ofp
);
817 for(res
= first_res
, i
= 0; i
< num_files
; i
++, res
++) {
818 const char *name
= get_face_name( info
[i
] );
819 fwrite(&res
, sizeof(res
), 1, ofp
);
820 fwrite(&info
[i
]->hdr
, FIELD_OFFSET(FNT_HEADER
,fi
.dfBitsOffset
), 1, ofp
);
822 fwrite(name
, strlen(name
) + 1, 1, ofp
);
825 pad
= ftell(ofp
) & 0xf;
828 for(i
= 0; i
< pad
; i
++)
831 for(res
= first_res
, i
= 0; i
< num_files
; i
++, res
++) {
832 write_fontinfo( info
[i
], ofp
);
833 pad
= info
[i
]->hdr
.dfSize
& 0xf;
836 for(j
= 0; j
< pad
; j
++)
845 #else /* HAVE_FREETYPE */
847 int main(int argc
, char **argv
)
849 fprintf( stderr
, "%s needs to be built with FreeType support\n", argv
[0] );
853 #endif /* HAVE_FREETYPE */