winedump: Add an ability to dump font files.
[wine.git] / tools / sfnt2fnt.c
blobde19d8fb263b2fdf0f22bddc412236d61702592d
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #ifdef HAVE_GETOPT_H
31 # include <getopt.h>
32 #endif
34 #ifdef HAVE_FREETYPE
36 #ifdef HAVE_FT2BUILD_H
37 #include <ft2build.h>
38 #endif
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>
45 #endif
47 #include "wine/unicode.h"
48 #include "wine/wingdi16.h"
49 #include "wingdi.h"
51 #include "pshpack1.h"
53 typedef struct
55 WORD dfVersion;
56 DWORD dfSize;
57 char dfCopyright[60];
58 FONTINFO16 fi;
59 } FNT_HEADER;
61 typedef struct {
62 WORD width;
63 DWORD offset;
64 } CHAR_TABLE_ENTRY;
66 typedef struct {
67 DWORD version;
68 ULONG numSizes;
69 } eblcHeader_t;
71 typedef struct {
72 CHAR ascender;
73 CHAR descender;
74 BYTE widthMax;
75 CHAR caretSlopeNumerator;
76 CHAR caretSlopeDenominator;
77 CHAR caretOffset;
78 CHAR minOriginSB;
79 CHAR minAdvanceSB;
80 CHAR maxBeforeBL;
81 CHAR maxAfterBL;
82 CHAR pad1;
83 CHAR pad2;
84 } sbitLineMetrics_t;
86 typedef struct {
87 ULONG indexSubTableArrayOffset;
88 ULONG indexTableSize;
89 ULONG numberOfIndexSubTables;
90 ULONG colorRef;
91 sbitLineMetrics_t hori;
92 sbitLineMetrics_t vert;
93 USHORT startGlyphIndex;
94 USHORT endGlyphIndex;
95 BYTE ppemX;
96 BYTE ppemY;
97 BYTE bitDepth;
98 CHAR flags;
99 } bitmapSizeTable_t;
101 typedef struct
103 FT_Int major;
104 FT_Int minor;
105 FT_Int patch;
106 } FT_Version_t;
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]) ))
113 #include "poppack.h"
115 struct fontinfo
117 FNT_HEADER hdr;
118 CHAR_TABLE_ENTRY dfCharTable[258];
119 BYTE *data;
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" );
156 #ifndef __GNUC__
157 #define __attribute__(X)
158 #endif
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, ...)
175 va_list ap;
176 va_start(ap, s);
177 fprintf(stderr, "Error: ");
178 vfprintf(stderr, s, ap);
179 va_end(ap);
180 exit(1);
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 */
191 switch(enc) {
192 case 1250:
193 return EE_CHARSET;
194 case 1251:
195 return RUSSIAN_CHARSET;
196 case 1252:
197 return ANSI_CHARSET;
198 case 1253:
199 return GREEK_CHARSET;
200 case 1254:
201 return TURKISH_CHARSET;
202 case 1255:
203 return HEBREW_CHARSET;
204 case 1256:
205 return ARABIC_CHARSET;
206 case 1257:
207 return BALTIC_CHARSET;
208 case 1258:
209 return VIETNAMESE_CHARSET;
210 case 437:
211 case 737:
212 case 775:
213 case 850:
214 case 852:
215 case 855:
216 case 857:
217 case 860:
218 case 861:
219 case 862:
220 case 863:
221 case 864:
222 case 865:
223 case 866:
224 case 869:
225 return OEM_CHARSET;
226 case 874:
227 return THAI_CHARSET;
228 case 932:
229 return SHIFTJIS_CHARSET;
230 case 936:
231 return GB2312_CHARSET;
232 case 949:
233 return HANGUL_CHARSET;
234 case 950:
235 return CHINESEBIG5_CHARSET;
237 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
239 return OEM_CHARSET;
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 == '\\')
246 return 0x20a9;
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)
255 FT_Error err;
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)
265 /* 2.0.x */
266 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
268 else
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);
274 #else
275 err = FT_Err_Unimplemented_Feature;
276 #endif
277 return err;
280 static struct fontinfo *fill_fontinfo( const char *face_name, int ppem, int enc, int dpi,
281 unsigned char def_char, int avg_width )
283 FT_Face face;
284 int ascent = 0, il, el, descent = 0, width_bytes = 0, space_size, max_width = 0;
285 BYTE left_byte, right_byte, byte;
286 DWORD start;
287 int i, x, y, x_off, x_end, first_char;
288 FT_UInt gi;
289 int num_names;
290 const union cptable *cptable;
291 FT_SfntName sfntname;
292 TT_OS2 *os2;
293 FT_ULong needed;
294 eblcHeader_t *eblc;
295 bitmapSizeTable_t *size_table;
296 int num_sizes;
297 struct fontinfo *info;
298 size_t data_pos;
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);
304 if(!cptable)
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);
310 if(!cptable)
311 error("Can't find codepage 1252\n");
314 assert( face->size->metrics.y_ppem == ppem );
316 needed = 0;
317 if (load_sfnt_table(face, TTAG_EBLC, 0, NULL, &needed))
318 fprintf(stderr,"Can't find EBLC table\n");
319 else
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;
333 break;
335 size_table++;
338 free(eblc);
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. */
345 if(ascent == 0)
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)
361 il = 0;
362 /* Japanese system fonts have an external leading (not small font) */
363 if (enc == 932 && ppem > 11)
364 el = 2;
365 else
366 el = 0;
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);
399 continue;
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;
407 /* space */
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;
412 /* sentinel */
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 - el) * 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;
434 break;
435 case PAN_FAMILY_DECORATIVE:
436 case PAN_FAMILY_PICTORIAL:
437 info->hdr.fi.dfPitchAndFamily |= FF_DECORATIVE;
438 break;
439 case PAN_FAMILY_TEXT_DISPLAY:
440 if(info->hdr.fi.dfPitchAndFamily == 0) /* fixed */
441 info->hdr.fi.dfPitchAndFamily = FF_MODERN;
442 else {
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;
448 break;
449 default:
450 info->hdr.fi.dfPitchAndFamily |= FF_ROMAN;
453 break;
454 default:
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 );
473 data_pos = 0;
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)) {
478 continue;
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;
487 continue;
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;
493 continue;
495 if(x == x_off)
496 left_byte = 0;
497 else
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)))
502 right_byte = 0;
503 else
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 );
520 return info;
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 )
534 int optc;
536 while ((optc = getopt( argc, argv, "d:ho:qr:s" )) != -1)
538 switch(optc)
540 case 'd':
541 option_defchar = atoi( optarg );
542 break;
543 case 'o':
544 option_output = strdup( optarg );
545 break;
546 case 'q':
547 option_quiet = 1;
548 break;
549 case 'r':
550 option_dpi = atoi( optarg );
551 break;
552 case 's':
553 option_fnt_mode = 1;
554 break;
555 case 'h':
556 usage(argv);
557 exit(0);
558 case '?':
559 usage(argv);
560 exit(1);
563 return &argv[optind];
566 int main(int argc, char **argv)
568 int i, j;
569 FILE *ofp;
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];
574 int fontdir_len = 2;
575 char non_resident_name[200];
576 unsigned short first_res = 0x0050, pad, res;
577 IMAGE_OS2_HEADER NE_hdr;
578 NE_TYPEINFO rc_type;
579 NE_NAMEINFO rc_name;
580 struct fontinfo **info;
581 char *input_file;
582 char **args;
584 args = parse_options( argc, argv );
586 input_file = *args++;
587 if (!input_file || !*args)
589 usage(argv);
590 exit(1);
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);
599 num_files = 0;
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;
609 const char *name;
611 if (sscanf( args[i], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
613 usage(argv);
614 exit(1);
616 if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
617 exit(1);
619 name = get_face_name( info[i] );
620 fontdir_len += 0x74 + strlen(name) + 1;
621 if(i == 0) {
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);
626 } else {
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)");
633 else
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 +
641 sizeof(NE_TYPEINFO);
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;
650 NE_hdr.ne_ver = 5;
651 NE_hdr.ne_rev = 1;
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;
661 NE_hdr.ne_align = 4;
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;
668 atexit( cleanup );
669 signal( SIGTERM, exit_on_signal );
670 signal( SIGINT, exit_on_signal );
671 #ifdef SIGHUP
672 signal( SIGHUP, exit_on_signal );
673 #endif
675 if (!option_output) /* build a default output name */
677 char *p = strrchr( input_file, '/' );
678 if (p) p++;
679 else p = 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 );
690 exit(1);
692 output_name = option_output;
693 if (option_fnt_mode)
695 write_fontinfo( info[0], ofp );
696 goto done;
699 fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
700 fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
702 align = 4;
703 fwrite(&align, sizeof(align), 1, ofp);
705 rc_type.type_id = NE_RSCTYPE_FONTDIR;
706 rc_type.count = 1;
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;
714 rc_name.handle = 0;
715 rc_name.usage = 0;
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;
729 rc_name.id = res;
730 rc_name.handle = 0;
731 rc_name.usage = 0;
732 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
734 font_off += len;
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);
747 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 */
755 fputc(0x00, ofp);
756 fputc(0x00, ofp);
758 pad = ftell(ofp) & 0xf;
759 if(pad != 0)
760 pad = 0x10 - pad;
761 for(i = 0; i < pad; i++)
762 fputc(0x00, ofp);
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);
771 fputc(0x00, ofp);
772 fwrite(name, strlen(name) + 1, 1, ofp);
775 pad = ftell(ofp) & 0xf;
776 if(pad != 0)
777 pad = 0x10 - pad;
778 for(i = 0; i < pad; i++)
779 fputc(0x00, ofp);
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;
784 if(pad != 0)
785 pad = 0x10 - pad;
786 for(j = 0; j < pad; j++)
787 fputc(0x00, ofp);
789 done:
790 fclose(ofp);
791 output_name = NULL;
792 exit(0);
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] );
800 exit(1);
803 #endif /* HAVE_FREETYPE */