include: Move "inline" right after the storage specifier.
[wine/multimedia.git] / tools / sfnt2fnt.c
blobdf43ec036398f8a507b13b9109e2a8a58d6034ab
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
44 #include "wine/unicode.h"
45 #include "wingdi.h"
47 #include "pshpack1.h"
49 typedef struct
51 INT16 dfType;
52 INT16 dfPoints;
53 INT16 dfVertRes;
54 INT16 dfHorizRes;
55 INT16 dfAscent;
56 INT16 dfInternalLeading;
57 INT16 dfExternalLeading;
58 BYTE dfItalic;
59 BYTE dfUnderline;
60 BYTE dfStrikeOut;
61 INT16 dfWeight;
62 BYTE dfCharSet;
63 INT16 dfPixWidth;
64 INT16 dfPixHeight;
65 BYTE dfPitchAndFamily;
66 INT16 dfAvgWidth;
67 INT16 dfMaxWidth;
68 BYTE dfFirstChar;
69 BYTE dfLastChar;
70 BYTE dfDefaultChar;
71 BYTE dfBreakChar;
72 INT16 dfWidthBytes;
73 LONG dfDevice;
74 LONG dfFace;
75 LONG dfBitsPointer;
76 LONG dfBitsOffset;
77 BYTE dfReserved;
78 LONG dfFlags;
79 INT16 dfAspace;
80 INT16 dfBspace;
81 INT16 dfCspace;
82 LONG dfColorPointer;
83 LONG dfReserved1[4];
84 } FONTINFO16;
86 typedef struct
88 WORD dfVersion;
89 DWORD dfSize;
90 char dfCopyright[60];
91 FONTINFO16 fi;
92 } FNT_HEADER;
94 typedef struct
96 WORD offset;
97 WORD length;
98 WORD flags;
99 WORD id;
100 WORD handle;
101 WORD usage;
102 } NE_NAMEINFO;
104 typedef struct
106 WORD type_id;
107 WORD count;
108 DWORD resloader;
109 } NE_TYPEINFO;
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
142 typedef struct {
143 WORD width;
144 DWORD offset;
145 } CHAR_TABLE_ENTRY;
147 typedef struct {
148 DWORD version;
149 ULONG numSizes;
150 } eblcHeader_t;
152 typedef struct {
153 CHAR ascender;
154 CHAR descender;
155 BYTE widthMax;
156 CHAR caretSlopeNumerator;
157 CHAR caretSlopeDenominator;
158 CHAR caretOffset;
159 CHAR minOriginSB;
160 CHAR minAdvanceSB;
161 CHAR maxBeforeBL;
162 CHAR maxAfterBL;
163 CHAR pad1;
164 CHAR pad2;
165 } sbitLineMetrics_t;
167 typedef struct {
168 ULONG indexSubTableArrayOffset;
169 ULONG indexTableSize;
170 ULONG numberOfIndexSubTables;
171 ULONG colorRef;
172 sbitLineMetrics_t hori;
173 sbitLineMetrics_t vert;
174 USHORT startGlyphIndex;
175 USHORT endGlyphIndex;
176 BYTE ppemX;
177 BYTE ppemY;
178 BYTE bitDepth;
179 CHAR flags;
180 } bitmapSizeTable_t;
182 typedef struct
184 FT_Int major;
185 FT_Int minor;
186 FT_Int patch;
187 } FT_Version_t;
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]) ))
194 #include "poppack.h"
196 struct fontinfo
198 FNT_HEADER hdr;
199 CHAR_TABLE_ENTRY dfCharTable[258];
200 BYTE *data;
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" );
237 #ifndef __GNUC__
238 #define __attribute__(X)
239 #endif
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, ...)
256 va_list ap;
257 va_start(ap, s);
258 fprintf(stderr, "Error: ");
259 vfprintf(stderr, s, ap);
260 va_end(ap);
261 exit(1);
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 */
272 switch(enc) {
273 case 1250:
274 return EE_CHARSET;
275 case 1251:
276 return RUSSIAN_CHARSET;
277 case 1252:
278 return ANSI_CHARSET;
279 case 1253:
280 return GREEK_CHARSET;
281 case 1254:
282 return TURKISH_CHARSET;
283 case 1255:
284 return HEBREW_CHARSET;
285 case 1256:
286 return ARABIC_CHARSET;
287 case 1257:
288 return BALTIC_CHARSET;
289 case 1258:
290 return VIETNAMESE_CHARSET;
291 case 437:
292 case 737:
293 case 775:
294 case 850:
295 case 852:
296 case 855:
297 case 857:
298 case 860:
299 case 861:
300 case 862:
301 case 863:
302 case 864:
303 case 865:
304 case 866:
305 case 869:
306 return OEM_CHARSET;
307 case 874:
308 return THAI_CHARSET;
309 case 932:
310 return SHIFTJIS_CHARSET;
311 case 936:
312 return GB2312_CHARSET;
313 case 949:
314 return HANGUL_CHARSET;
315 case 950:
316 return CHINESEBIG5_CHARSET;
318 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
320 return OEM_CHARSET;
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 == '\\')
327 return 0x20a9;
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 )
335 FT_Face face;
336 int ascent = 0, il, el, width_bytes = 0, space_size, max_width = 0;
337 BYTE left_byte, right_byte, byte;
338 DWORD start;
339 int i, x, y, x_off, x_end, first_char;
340 FT_UInt gi;
341 int num_names;
342 const union cptable *cptable;
343 FT_SfntName sfntname;
344 TT_OS2 *os2;
345 FT_ULong needed;
346 eblcHeader_t *eblc;
347 bitmapSizeTable_t *size_table;
348 int num_sizes;
349 struct fontinfo *info;
350 size_t data_pos;
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);
356 if(!cptable)
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);
362 if(!cptable)
363 error("Can't find codepage 1252\n");
366 assert( face->size->metrics.y_ppem == ppem );
368 needed = 0;
369 if (FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
370 fprintf(stderr,"Can't find EBLC table\n");
371 else
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;
384 break;
386 size_table++;
389 free(eblc);
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. */
396 if(ascent == 0)
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)
411 il = 0;
412 /* Japanese system fonts have an external leading (not small font) */
413 if (enc == 932 && ppem > 11)
414 el = 2;
415 else
416 el = 0;
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);
449 continue;
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;
457 /* space */
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;
462 /* sentinel */
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;
484 break;
485 case PAN_FAMILY_DECORATIVE:
486 case PAN_FAMILY_PICTORIAL:
487 info->hdr.fi.dfPitchAndFamily |= FF_DECORATIVE;
488 break;
489 case PAN_FAMILY_TEXT_DISPLAY:
490 if(info->hdr.fi.dfPitchAndFamily == 0) /* fixed */
491 info->hdr.fi.dfPitchAndFamily = FF_MODERN;
492 else {
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;
498 break;
499 default:
500 info->hdr.fi.dfPitchAndFamily |= FF_ROMAN;
503 break;
504 default:
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 );
523 data_pos = 0;
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)) {
528 continue;
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;
537 continue;
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;
543 continue;
545 if(x == x_off)
546 left_byte = 0;
547 else
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)))
552 right_byte = 0;
553 else
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 );
570 return info;
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 )
584 int optc;
586 while ((optc = getopt( argc, argv, "d:ho:qr:s" )) != -1)
588 switch(optc)
590 case 'd':
591 option_defchar = atoi( optarg );
592 break;
593 case 'o':
594 option_output = strdup( optarg );
595 break;
596 case 'q':
597 option_quiet = 1;
598 break;
599 case 'r':
600 option_dpi = atoi( optarg );
601 break;
602 case 's':
603 option_fnt_mode = 1;
604 break;
605 case 'h':
606 usage(argv);
607 exit(0);
608 case '?':
609 usage(argv);
610 exit(1);
613 return &argv[optind];
616 int main(int argc, char **argv)
618 int i, j;
619 FILE *ofp;
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];
624 int fontdir_len = 2;
625 char non_resident_name[200];
626 unsigned short first_res = 0x0050, pad, res;
627 IMAGE_OS2_HEADER NE_hdr;
628 NE_TYPEINFO rc_type;
629 NE_NAMEINFO rc_name;
630 struct fontinfo **info;
631 char *input_file;
632 char **args;
634 args = parse_options( argc, argv );
636 input_file = *args++;
637 if (!input_file || !*args)
639 usage(argv);
640 exit(1);
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);
649 num_files = 0;
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;
659 const char *name;
661 if (sscanf( args[i], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
663 usage(argv);
664 exit(1);
666 if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
667 exit(1);
669 name = get_face_name( info[i] );
670 fontdir_len += 0x74 + strlen(name) + 1;
671 if(i == 0) {
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);
676 } else {
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)");
683 else
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 +
691 sizeof(NE_TYPEINFO);
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;
700 NE_hdr.ne_ver = 5;
701 NE_hdr.ne_rev = 1;
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;
711 NE_hdr.ne_align = 4;
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;
718 atexit( cleanup );
719 signal( SIGTERM, exit_on_signal );
720 signal( SIGINT, exit_on_signal );
721 #ifdef SIGHUP
722 signal( SIGHUP, exit_on_signal );
723 #endif
725 if (!option_output) /* build a default output name */
727 char *p = strrchr( input_file, '/' );
728 if (p) p++;
729 else p = 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 );
740 exit(1);
742 output_name = option_output;
743 if (option_fnt_mode)
745 write_fontinfo( info[0], ofp );
746 goto done;
749 fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
750 fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
752 align = 4;
753 fwrite(&align, sizeof(align), 1, ofp);
755 rc_type.type_id = NE_RSCTYPE_FONTDIR;
756 rc_type.count = 1;
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;
764 rc_name.handle = 0;
765 rc_name.usage = 0;
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;
779 rc_name.id = res;
780 rc_name.handle = 0;
781 rc_name.usage = 0;
782 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
784 font_off += len;
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);
797 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 */
805 fputc(0x00, ofp);
806 fputc(0x00, ofp);
808 pad = ftell(ofp) & 0xf;
809 if(pad != 0)
810 pad = 0x10 - pad;
811 for(i = 0; i < pad; i++)
812 fputc(0x00, ofp);
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);
821 fputc(0x00, ofp);
822 fwrite(name, strlen(name) + 1, 1, ofp);
825 pad = ftell(ofp) & 0xf;
826 if(pad != 0)
827 pad = 0x10 - pad;
828 for(i = 0; i < pad; i++)
829 fputc(0x00, ofp);
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;
834 if(pad != 0)
835 pad = 0x10 - pad;
836 for(j = 0; j < pad; j++)
837 fputc(0x00, ofp);
839 done:
840 fclose(ofp);
841 output_name = NULL;
842 exit(0);
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] );
850 exit(1);
853 #endif /* HAVE_FREETYPE */