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"
59 INT16 dfInternalLeading
;
60 INT16 dfExternalLeading
;
68 BYTE dfPitchAndFamily
;
114 #define NE_FFLAGS_SINGLEDATA 0x0001
115 #define NE_FFLAGS_MULTIPLEDATA 0x0002
116 #define NE_FFLAGS_WIN32 0x0010
117 #define NE_FFLAGS_FRAMEBUF 0x0100
118 #define NE_FFLAGS_CONSOLE 0x0200
119 #define NE_FFLAGS_GUI 0x0300
120 #define NE_FFLAGS_SELFLOAD 0x0800
121 #define NE_FFLAGS_LINKERROR 0x2000
122 #define NE_FFLAGS_CALLWEP 0x4000
123 #define NE_FFLAGS_LIBMODULE 0x8000
125 #define NE_OSFLAGS_WINDOWS 0x02
127 #define NE_RSCTYPE_FONTDIR 0x8007
128 #define NE_RSCTYPE_FONT 0x8008
129 #define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
131 #define NE_SEGFLAGS_DATA 0x0001
132 #define NE_SEGFLAGS_ALLOCATED 0x0002
133 #define NE_SEGFLAGS_LOADED 0x0004
134 #define NE_SEGFLAGS_ITERATED 0x0008
135 #define NE_SEGFLAGS_MOVEABLE 0x0010
136 #define NE_SEGFLAGS_SHAREABLE 0x0020
137 #define NE_SEGFLAGS_PRELOAD 0x0040
138 #define NE_SEGFLAGS_EXECUTEONLY 0x0080
139 #define NE_SEGFLAGS_READONLY 0x0080
140 #define NE_SEGFLAGS_RELOC_DATA 0x0100
141 #define NE_SEGFLAGS_SELFLOAD 0x0800
142 #define NE_SEGFLAGS_DISCARDABLE 0x1000
143 #define NE_SEGFLAGS_32BIT 0x2000
159 CHAR caretSlopeNumerator
;
160 CHAR caretSlopeDenominator
;
171 ULONG indexSubTableArrayOffset
;
172 ULONG indexTableSize
;
173 ULONG numberOfIndexSubTables
;
175 sbitLineMetrics_t hori
;
176 sbitLineMetrics_t vert
;
177 USHORT startGlyphIndex
;
178 USHORT endGlyphIndex
;
191 static FT_Version_t FT_Version
;
193 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
194 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
195 GET_BE_WORD(&((WORD *)(ptr))[0]) ))
202 CHAR_TABLE_ENTRY dfCharTable
[258];
206 static const BYTE MZ_hdr
[] =
208 'M', 'Z', 0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
209 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
212 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
213 'i', 's', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n', 'n', 'o',
214 't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O', 'S', ' ',
215 'm', 'o', 'd', 'e', 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
218 static char *option_output
;
219 static int option_defchar
= ' ';
220 static int option_dpi
= 96;
221 static int option_fnt_mode
= 0;
222 static int option_quiet
= 0;
224 static const char *output_name
;
226 static FT_Library ft_library
;
228 static void usage(char **argv
)
230 fprintf(stderr
, "%s [options] input.ttf ppem,enc,avg_width ...\n", argv
[0]);
231 fprintf(stderr
, "Options:\n");
232 fprintf(stderr
, " -h Display help\n" );
233 fprintf(stderr
, " -d char Set the font default char\n" );
234 fprintf(stderr
, " -o file Set output file name\n" );
235 fprintf(stderr
, " -q Quiet mode\n" );
236 fprintf(stderr
, " -r dpi Set resolution in DPI (default: 96)\n" );
237 fprintf(stderr
, " -s Single .fnt file mode\n" );
241 #define __attribute__(X)
244 /* atexit handler to cleanup files */
245 static void cleanup(void)
247 if (output_name
) unlink( output_name
);
250 static void exit_on_signal( int sig
)
252 exit(1); /* this will call the atexit functions */
255 static void error(const char *s
, ...) __attribute__((format (printf
, 1, 2)));
257 static void error(const char *s
, ...)
261 fprintf(stderr
, "Error: ");
262 vfprintf(stderr
, s
, ap
);
267 static const char *get_face_name( const struct fontinfo
*info
)
269 return (const char *)info
->data
+ info
->hdr
.fi
.dfFace
- info
->hdr
.fi
.dfBitsOffset
;
272 static int lookup_charset(int enc
)
274 /* FIXME: make winelib app and use TranslateCharsetInfo */
279 return RUSSIAN_CHARSET
;
283 return GREEK_CHARSET
;
285 return TURKISH_CHARSET
;
287 return HEBREW_CHARSET
;
289 return ARABIC_CHARSET
;
291 return BALTIC_CHARSET
;
293 return VIETNAMESE_CHARSET
;
313 return SHIFTJIS_CHARSET
;
315 return GB2312_CHARSET
;
317 return HANGUL_CHARSET
;
319 return CHINESEBIG5_CHARSET
;
321 fprintf(stderr
, "Unknown encoding %d - using OEM_CHARSET\n", enc
);
326 static int get_char(const union cptable
*cptable
, int enc
, int index
)
328 /* Korean has the Won sign in place of '\\' */
329 if(enc
== 949 && index
== '\\')
332 return cptable
->sbcs
.cp2uni
[index
];
335 /* from gdi32/freetype.c */
336 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
341 /* If the FT_Load_Sfnt_Table function is there we'll use it */
342 #ifdef HAVE_FT_LOAD_SFNT_TABLE
343 err
= FT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
344 #elif defined(HAVE_FREETYPE_INTERNAL_SFNT_H)
345 TT_Face tt_face
= (TT_Face
) ft_face
;
346 SFNT_Interface
*sfnt
;
347 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
350 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
354 /* A field was added in the middle of the structure in 2.1.x */
355 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
357 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
359 err
= FT_Err_Unimplemented_Feature
;
364 static struct fontinfo
*fill_fontinfo( const char *face_name
, int ppem
, int enc
, int dpi
,
365 unsigned char def_char
, int avg_width
)
368 int ascent
= 0, il
, el
, descent
= 0, width_bytes
= 0, space_size
, max_width
= 0;
369 BYTE left_byte
, right_byte
, byte
;
371 int i
, x
, y
, x_off
, x_end
, first_char
;
374 const union cptable
*cptable
;
375 FT_SfntName sfntname
;
379 bitmapSizeTable_t
*size_table
;
381 struct fontinfo
*info
;
384 if (FT_New_Face(ft_library
, face_name
, 0, &face
)) error( "Cannot open face %s\n", face_name
);
385 if (FT_Set_Pixel_Sizes(face
, ppem
, ppem
)) error( "cannot set face size to %u\n", ppem
);
387 cptable
= wine_cp_get_table(enc
);
389 error("Can't find codepage %d\n", enc
);
391 if(cptable
->info
.char_size
!= 1) {
392 /* for double byte charsets we actually want to use cp1252 */
393 cptable
= wine_cp_get_table(1252);
395 error("Can't find codepage 1252\n");
398 assert( face
->size
->metrics
.y_ppem
== ppem
);
401 if (load_sfnt_table(face
, TTAG_EBLC
, 0, NULL
, &needed
))
402 fprintf(stderr
,"Can't find EBLC table\n");
405 eblc
= malloc(needed
);
406 load_sfnt_table(face
, TTAG_EBLC
, 0, (FT_Byte
*)eblc
, &needed
);
408 num_sizes
= GET_BE_DWORD(&eblc
->numSizes
);
410 size_table
= (bitmapSizeTable_t
*)(eblc
+ 1);
411 for(i
= 0; i
< num_sizes
; i
++)
413 if(size_table
->hori
.ascender
- size_table
->hori
.descender
== ppem
)
415 ascent
= size_table
->hori
.ascender
;
416 descent
= -size_table
->hori
.descender
;
425 /* Versions of fontforge prior to early 2006 have incorrect
426 ascender values in the eblc table, so we won't find the
427 correct bitmapSizeTable. In this case use the height of
428 the Aring glyph instead. */
431 if(FT_Load_Char(face
, 0xc5, FT_LOAD_DEFAULT
))
432 error("Can't find Aring\n");
433 ascent
= face
->glyph
->metrics
.horiBearingY
>> 6;
434 descent
= ppem
- ascent
;
437 start
= sizeof(FNT_HEADER
);
439 if(FT_Load_Char(face
, 'M', FT_LOAD_DEFAULT
))
440 error("Can't find M\n");
441 il
= ascent
- (face
->glyph
->metrics
.height
>> 6);
443 /* Hack: Courier has no internal leading, nor do any Chinese or Japanese fonts */
444 if(!strcmp(face
->family_name
, "Courier") || enc
== 936 || enc
== 950 || enc
== 932)
446 /* Japanese system fonts have an external leading (not small font) */
447 if (enc
== 932 && ppem
> 11)
452 first_char
= FT_Get_First_Char(face
, &gi
);
453 if(first_char
== 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
454 first_char
= 32; /* FT_Get_Next_Char for some reason returns too high
455 number in this case */
457 info
= calloc( 1, sizeof(*info
) );
459 info
->hdr
.fi
.dfFirstChar
= first_char
;
460 info
->hdr
.fi
.dfLastChar
= 0xff;
461 start
+= ((unsigned char)info
->hdr
.fi
.dfLastChar
- (unsigned char)info
->hdr
.fi
.dfFirstChar
+ 3 ) * sizeof(*info
->dfCharTable
);
463 num_names
= FT_Get_Sfnt_Name_Count(face
);
464 for(i
= 0; i
<num_names
; i
++) {
465 FT_Get_Sfnt_Name(face
, i
, &sfntname
);
466 if(sfntname
.platform_id
== 1 && sfntname
.encoding_id
== 0 &&
467 sfntname
.language_id
== 0 && sfntname
.name_id
== 0) {
468 size_t len
= min( sfntname
.string_len
, sizeof(info
->hdr
.dfCopyright
)-1 );
469 memcpy(info
->hdr
.dfCopyright
, sfntname
.string
, len
);
470 info
->hdr
.dfCopyright
[len
] = 0;
474 os2
= FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
475 for(i
= first_char
; i
< 0x100; i
++) {
476 int c
= get_char(cptable
, enc
, i
);
477 gi
= FT_Get_Char_Index(face
, c
);
478 if(gi
== 0 && !option_quiet
)
479 fprintf(stderr
, "warning: %s %u: missing glyph for char %04x\n",
480 face
->family_name
, ppem
, cptable
->sbcs
.cp2uni
[i
]);
481 if(FT_Load_Char(face
, c
, FT_LOAD_DEFAULT
)) {
482 fprintf(stderr
, "error loading char %d - bad news!\n", i
);
485 info
->dfCharTable
[i
].width
= face
->glyph
->metrics
.horiAdvance
>> 6;
486 info
->dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
487 width_bytes
+= ((face
->glyph
->metrics
.horiAdvance
>> 6) + 7) >> 3;
488 if(max_width
< (face
->glyph
->metrics
.horiAdvance
>> 6))
489 max_width
= face
->glyph
->metrics
.horiAdvance
>> 6;
492 space_size
= (ppem
+ 3) / 4;
493 info
->dfCharTable
[i
].width
= space_size
;
494 info
->dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
495 width_bytes
+= (space_size
+ 7) >> 3;
497 info
->dfCharTable
[++i
].width
= 0;
498 info
->dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
500 info
->hdr
.fi
.dfType
= 0;
501 info
->hdr
.fi
.dfPoints
= ((ppem
- il
- el
) * 72 + dpi
/2) / dpi
;
502 info
->hdr
.fi
.dfVertRes
= dpi
;
503 info
->hdr
.fi
.dfHorizRes
= dpi
;
504 info
->hdr
.fi
.dfAscent
= ascent
;
505 info
->hdr
.fi
.dfInternalLeading
= il
;
506 info
->hdr
.fi
.dfExternalLeading
= el
;
507 info
->hdr
.fi
.dfItalic
= (face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
508 info
->hdr
.fi
.dfUnderline
= 0;
509 info
->hdr
.fi
.dfStrikeOut
= 0;
510 info
->hdr
.fi
.dfWeight
= os2
->usWeightClass
;
511 info
->hdr
.fi
.dfCharSet
= lookup_charset(enc
);
512 info
->hdr
.fi
.dfPixWidth
= (face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
) ? avg_width
: 0;
513 info
->hdr
.fi
.dfPixHeight
= ppem
;
514 info
->hdr
.fi
.dfPitchAndFamily
= FT_IS_FIXED_WIDTH(face
) ? 0 : TMPF_FIXED_PITCH
;
515 switch(os2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
516 case PAN_FAMILY_SCRIPT
:
517 info
->hdr
.fi
.dfPitchAndFamily
|= FF_SCRIPT
;
519 case PAN_FAMILY_DECORATIVE
:
520 case PAN_FAMILY_PICTORIAL
:
521 info
->hdr
.fi
.dfPitchAndFamily
|= FF_DECORATIVE
;
523 case PAN_FAMILY_TEXT_DISPLAY
:
524 if(info
->hdr
.fi
.dfPitchAndFamily
== 0) /* fixed */
525 info
->hdr
.fi
.dfPitchAndFamily
= FF_MODERN
;
527 switch(os2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
528 case PAN_SERIF_NORMAL_SANS
:
529 case PAN_SERIF_OBTUSE_SANS
:
530 case PAN_SERIF_PERP_SANS
:
531 info
->hdr
.fi
.dfPitchAndFamily
|= FF_SWISS
;
534 info
->hdr
.fi
.dfPitchAndFamily
|= FF_ROMAN
;
539 info
->hdr
.fi
.dfPitchAndFamily
|= FF_DONTCARE
;
542 info
->hdr
.fi
.dfAvgWidth
= avg_width
;
543 info
->hdr
.fi
.dfMaxWidth
= max_width
;
544 info
->hdr
.fi
.dfDefaultChar
= def_char
- info
->hdr
.fi
.dfFirstChar
;
545 info
->hdr
.fi
.dfBreakChar
= ' ' - info
->hdr
.fi
.dfFirstChar
;
546 info
->hdr
.fi
.dfWidthBytes
= (width_bytes
+ 1) & ~1;
548 info
->hdr
.fi
.dfFace
= start
+ info
->hdr
.fi
.dfWidthBytes
* ppem
;
549 info
->hdr
.fi
.dfBitsOffset
= start
;
550 info
->hdr
.fi
.dfFlags
= 0x10; /* DFF_1COLOR */
551 info
->hdr
.fi
.dfFlags
|= FT_IS_FIXED_WIDTH(face
) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
553 info
->hdr
.dfVersion
= 0x300;
554 info
->hdr
.dfSize
= start
+ info
->hdr
.fi
.dfWidthBytes
* ppem
+ strlen(face
->family_name
) + 1;
556 info
->data
= calloc( info
->hdr
.dfSize
- start
, 1 );
559 for(i
= first_char
; i
< 0x100; i
++) {
560 int c
= get_char(cptable
, enc
, i
);
561 if(FT_Load_Char(face
, c
, FT_LOAD_DEFAULT
)) {
564 assert(info
->dfCharTable
[i
].width
== face
->glyph
->metrics
.horiAdvance
>> 6);
566 for(x
= 0; x
< ((info
->dfCharTable
[i
].width
+ 7) / 8); x
++) {
567 for(y
= 0; y
< ppem
; y
++) {
568 if(y
< ascent
- face
->glyph
->bitmap_top
||
569 y
>= face
->glyph
->bitmap
.rows
+ ascent
- face
->glyph
->bitmap_top
) {
570 info
->data
[data_pos
++] = 0;
573 x_off
= face
->glyph
->bitmap_left
/ 8;
574 x_end
= (face
->glyph
->bitmap_left
+ face
->glyph
->bitmap
.width
- 1) / 8;
575 if(x
< x_off
|| x
> x_end
) {
576 info
->data
[data_pos
++] = 0;
582 left_byte
= face
->glyph
->bitmap
.buffer
[(y
- (ascent
- face
->glyph
->bitmap_top
)) * face
->glyph
->bitmap
.pitch
+ x
- x_off
- 1];
584 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
585 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)))
588 right_byte
= face
->glyph
->bitmap
.buffer
[(y
- (ascent
- face
->glyph
->bitmap_top
)) * face
->glyph
->bitmap
.pitch
+ x
- x_off
];
590 byte
= (left_byte
<< (8 - (face
->glyph
->bitmap_left
& 7))) & 0xff;
591 byte
|= ((right_byte
>> (face
->glyph
->bitmap_left
& 7)) & 0xff);
592 info
->data
[data_pos
++] = byte
;
596 data_pos
+= ((space_size
+ 7) / 8) * ppem
;
597 if (width_bytes
& 1) data_pos
+= ppem
;
599 memcpy( info
->data
+ data_pos
, face
->family_name
, strlen( face
->family_name
));
600 data_pos
+= strlen( face
->family_name
) + 1;
601 assert( start
+ data_pos
== info
->hdr
.dfSize
);
603 FT_Done_Face( face
);
607 static void write_fontinfo( const struct fontinfo
*info
, FILE *fp
)
609 fwrite( &info
->hdr
, sizeof(info
->hdr
), 1, fp
);
610 fwrite( info
->dfCharTable
+ info
->hdr
.fi
.dfFirstChar
, sizeof(*info
->dfCharTable
),
611 ((unsigned char)info
->hdr
.fi
.dfLastChar
- (unsigned char)info
->hdr
.fi
.dfFirstChar
) + 3, fp
);
612 fwrite( info
->data
, info
->hdr
.dfSize
- info
->hdr
.fi
.dfBitsOffset
, 1, fp
);
615 /* parse options from the argv array and remove all the recognized ones */
616 static char **parse_options( int argc
, char **argv
)
620 while ((optc
= getopt( argc
, argv
, "d:ho:qr:s" )) != -1)
625 option_defchar
= atoi( optarg
);
628 option_output
= strdup( optarg
);
634 option_dpi
= atoi( optarg
);
647 return &argv
[optind
];
650 int main(int argc
, char **argv
)
654 short align
, num_files
;
655 int resource_table_len
, non_resident_name_len
, resident_name_len
;
656 unsigned short resource_table_off
, resident_name_off
, module_ref_off
, non_resident_name_off
, fontdir_off
, font_off
;
657 char resident_name
[200];
659 char non_resident_name
[200];
660 unsigned short first_res
= 0x0050, pad
, res
;
661 IMAGE_OS2_HEADER NE_hdr
;
664 struct fontinfo
**info
;
668 args
= parse_options( argc
, argv
);
670 input_file
= *args
++;
671 if (!input_file
|| !*args
)
677 if(FT_Init_FreeType(&ft_library
))
678 error("ft init failure\n");
680 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
681 FT_Library_Version(ft_library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
684 while (args
[num_files
]) num_files
++;
686 if (option_fnt_mode
&& num_files
> 1)
687 error( "can only specify one font in .fnt mode\n" );
689 info
= malloc( num_files
* sizeof(*info
) );
690 for (i
= 0; i
< num_files
; i
++)
692 int ppem
, enc
, avg_width
;
695 if (sscanf( args
[i
], "%d,%d,%d", &ppem
, &enc
, &avg_width
) != 3)
700 if (!(info
[i
] = fill_fontinfo( input_file
, ppem
, enc
, option_dpi
, option_defchar
, avg_width
)))
703 name
= get_face_name( info
[i
] );
704 fontdir_len
+= 0x74 + strlen(name
) + 1;
706 sprintf(non_resident_name
, "FONTRES 100,%d,%d : %s %d",
707 info
[i
]->hdr
.fi
.dfVertRes
, info
[i
]->hdr
.fi
.dfHorizRes
,
708 name
, info
[i
]->hdr
.fi
.dfPoints
);
709 strcpy(resident_name
, name
);
711 sprintf(non_resident_name
+ strlen(non_resident_name
), ",%d", info
[i
]->hdr
.fi
.dfPoints
);
715 if (option_dpi
<= 108)
716 strcat(non_resident_name
, " (VGA res)");
718 strcat(non_resident_name
, " (8514 res)");
719 non_resident_name_len
= strlen(non_resident_name
) + 4;
721 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
722 resource_table_len
= sizeof(align
) + sizeof("FONTDIR") +
723 sizeof(NE_TYPEINFO
) + sizeof(NE_NAMEINFO
) +
724 sizeof(NE_TYPEINFO
) + sizeof(NE_NAMEINFO
) * num_files
+
726 resource_table_off
= sizeof(NE_hdr
);
727 resident_name_off
= resource_table_off
+ resource_table_len
;
728 resident_name_len
= strlen(resident_name
) + 4;
729 module_ref_off
= resident_name_off
+ resident_name_len
;
730 non_resident_name_off
= sizeof(MZ_hdr
) + module_ref_off
+ sizeof(align
);
732 memset(&NE_hdr
, 0, sizeof(NE_hdr
));
733 NE_hdr
.ne_magic
= 0x454e;
736 NE_hdr
.ne_flags
= NE_FFLAGS_LIBMODULE
| NE_FFLAGS_GUI
;
737 NE_hdr
.ne_cbnrestab
= non_resident_name_len
;
738 NE_hdr
.ne_segtab
= sizeof(NE_hdr
);
739 NE_hdr
.ne_rsrctab
= sizeof(NE_hdr
);
740 NE_hdr
.ne_restab
= resident_name_off
;
741 NE_hdr
.ne_modtab
= module_ref_off
;
742 NE_hdr
.ne_imptab
= module_ref_off
;
743 NE_hdr
.ne_enttab
= NE_hdr
.ne_modtab
;
744 NE_hdr
.ne_nrestab
= non_resident_name_off
;
746 NE_hdr
.ne_exetyp
= NE_OSFLAGS_WINDOWS
;
747 NE_hdr
.ne_expver
= 0x400;
749 fontdir_off
= (non_resident_name_off
+ non_resident_name_len
+ 15) & ~0xf;
750 font_off
= (fontdir_off
+ fontdir_len
+ 15) & ~0x0f;
753 signal( SIGTERM
, exit_on_signal
);
754 signal( SIGINT
, exit_on_signal
);
756 signal( SIGHUP
, exit_on_signal
);
759 if (!option_output
) /* build a default output name */
761 char *p
= strrchr( input_file
, '/' );
764 option_output
= malloc( strlen(p
) + sizeof(".fon") );
765 strcpy( option_output
, p
);
766 p
= strrchr( option_output
, '.' );
767 if (!p
) p
= option_output
+ strlen(option_output
);
768 strcpy( p
, option_fnt_mode
? ".fnt" : ".fon" );
771 if (!(ofp
= fopen(option_output
, "wb")))
773 perror( option_output
);
776 output_name
= option_output
;
779 write_fontinfo( info
[0], ofp
);
783 fwrite(MZ_hdr
, sizeof(MZ_hdr
), 1, ofp
);
784 fwrite(&NE_hdr
, sizeof(NE_hdr
), 1, ofp
);
787 fwrite(&align
, sizeof(align
), 1, ofp
);
789 rc_type
.type_id
= NE_RSCTYPE_FONTDIR
;
791 rc_type
.resloader
= 0;
792 fwrite(&rc_type
, sizeof(rc_type
), 1, ofp
);
794 rc_name
.offset
= fontdir_off
>> 4;
795 rc_name
.length
= (fontdir_len
+ 15) >> 4;
796 rc_name
.flags
= NE_SEGFLAGS_MOVEABLE
| NE_SEGFLAGS_PRELOAD
;
797 rc_name
.id
= resident_name_off
- sizeof("FONTDIR") - NE_hdr
.ne_rsrctab
;
800 fwrite(&rc_name
, sizeof(rc_name
), 1, ofp
);
802 rc_type
.type_id
= NE_RSCTYPE_FONT
;
803 rc_type
.count
= num_files
;
804 rc_type
.resloader
= 0;
805 fwrite(&rc_type
, sizeof(rc_type
), 1, ofp
);
807 for(res
= first_res
| 0x8000, i
= 0; i
< num_files
; i
++, res
++) {
808 int len
= (info
[i
]->hdr
.dfSize
+ 15) & ~0xf;
810 rc_name
.offset
= font_off
>> 4;
811 rc_name
.length
= len
>> 4;
812 rc_name
.flags
= NE_SEGFLAGS_MOVEABLE
| NE_SEGFLAGS_SHAREABLE
| NE_SEGFLAGS_DISCARDABLE
;
816 fwrite(&rc_name
, sizeof(rc_name
), 1, ofp
);
821 /* empty type info */
822 memset(&rc_type
, 0, sizeof(rc_type
));
823 fwrite(&rc_type
, sizeof(rc_type
), 1, ofp
);
825 fputc(strlen("FONTDIR"), ofp
);
826 fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp
);
827 fputc(strlen(resident_name
), ofp
);
828 fwrite(resident_name
, strlen(resident_name
), 1, ofp
);
830 fputc(0x00, ofp
); fputc(0x00, ofp
);
832 fputc(0x00, ofp
); fputc(0x00, ofp
);
834 fputc(strlen(non_resident_name
), ofp
);
835 fwrite(non_resident_name
, strlen(non_resident_name
), 1, ofp
);
836 fputc(0x00, ofp
); /* terminator */
838 /* empty ne_modtab and ne_imptab */
842 pad
= ftell(ofp
) & 0xf;
845 for(i
= 0; i
< pad
; i
++)
848 /* FONTDIR resource */
849 fwrite(&num_files
, sizeof(num_files
), 1, ofp
);
851 for(res
= first_res
, i
= 0; i
< num_files
; i
++, res
++) {
852 const char *name
= get_face_name( info
[i
] );
853 fwrite(&res
, sizeof(res
), 1, ofp
);
854 fwrite(&info
[i
]->hdr
, FIELD_OFFSET(FNT_HEADER
,fi
.dfBitsOffset
), 1, ofp
);
856 fwrite(name
, strlen(name
) + 1, 1, ofp
);
859 pad
= ftell(ofp
) & 0xf;
862 for(i
= 0; i
< pad
; i
++)
865 for(res
= first_res
, i
= 0; i
< num_files
; i
++, res
++) {
866 write_fontinfo( info
[i
], ofp
);
867 pad
= info
[i
]->hdr
.dfSize
& 0xf;
870 for(j
= 0; j
< pad
; j
++)
879 #else /* HAVE_FREETYPE */
881 int main(int argc
, char **argv
)
883 fprintf( stderr
, "%s needs to be built with FreeType support\n", argv
[0] );
887 #endif /* HAVE_FREETYPE */