Release 1.5.29.
[wine] / tools / sfnt2fnt.c
1 /*
2  * sfnttofnt.  Bitmap only ttf to Window fnt file converter
3  *
4  * Copyright 2004 Huw Davies
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
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
33
34 #ifdef HAVE_FREETYPE
35
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
44 #include "wine/unicode.h"
45 #include "wingdi.h"
46 #include "basetsd.h"
47
48 #include "pshpack1.h"
49
50 typedef struct
51 {
52     INT16 dfType;
53     INT16 dfPoints;
54     INT16 dfVertRes;
55     INT16 dfHorizRes;
56     INT16 dfAscent;
57     INT16 dfInternalLeading;
58     INT16 dfExternalLeading;
59     BYTE  dfItalic;
60     BYTE  dfUnderline;
61     BYTE  dfStrikeOut;
62     INT16 dfWeight;
63     BYTE  dfCharSet;
64     INT16 dfPixWidth;
65     INT16 dfPixHeight;
66     BYTE  dfPitchAndFamily;
67     INT16 dfAvgWidth;
68     INT16 dfMaxWidth;
69     BYTE  dfFirstChar;
70     BYTE  dfLastChar;
71     BYTE  dfDefaultChar;
72     BYTE  dfBreakChar;
73     INT16 dfWidthBytes;
74     LONG  dfDevice;
75     LONG  dfFace;
76     LONG  dfBitsPointer;
77     LONG  dfBitsOffset;
78     BYTE  dfReserved;
79     LONG  dfFlags;
80     INT16 dfAspace;
81     INT16 dfBspace;
82     INT16 dfCspace;
83     LONG  dfColorPointer;
84     LONG  dfReserved1[4];
85 } FONTINFO16;
86
87 typedef struct
88 {
89     WORD dfVersion;
90     DWORD dfSize;
91     char dfCopyright[60];
92     FONTINFO16 fi;
93 } FNT_HEADER;
94
95 typedef struct
96 {
97     WORD  offset;
98     WORD  length;
99     WORD  flags;
100     WORD  id;
101     WORD  handle;
102     WORD  usage;
103 } NE_NAMEINFO;
104
105 typedef struct
106 {
107     WORD  type_id;
108     WORD  count;
109     DWORD resloader;
110 } NE_TYPEINFO;
111
112 #define NE_FFLAGS_SINGLEDATA    0x0001
113 #define NE_FFLAGS_MULTIPLEDATA  0x0002
114 #define NE_FFLAGS_WIN32         0x0010
115 #define NE_FFLAGS_FRAMEBUF      0x0100
116 #define NE_FFLAGS_CONSOLE       0x0200
117 #define NE_FFLAGS_GUI           0x0300
118 #define NE_FFLAGS_SELFLOAD      0x0800
119 #define NE_FFLAGS_LINKERROR     0x2000
120 #define NE_FFLAGS_CALLWEP       0x4000
121 #define NE_FFLAGS_LIBMODULE     0x8000
122
123 #define NE_OSFLAGS_WINDOWS      0x02
124
125 #define NE_RSCTYPE_FONTDIR            0x8007
126 #define NE_RSCTYPE_FONT               0x8008
127 #define NE_RSCTYPE_SCALABLE_FONTPATH  0x80cc
128
129 #define NE_SEGFLAGS_DATA        0x0001
130 #define NE_SEGFLAGS_ALLOCATED   0x0002
131 #define NE_SEGFLAGS_LOADED      0x0004
132 #define NE_SEGFLAGS_ITERATED    0x0008
133 #define NE_SEGFLAGS_MOVEABLE    0x0010
134 #define NE_SEGFLAGS_SHAREABLE   0x0020
135 #define NE_SEGFLAGS_PRELOAD     0x0040
136 #define NE_SEGFLAGS_EXECUTEONLY 0x0080
137 #define NE_SEGFLAGS_READONLY    0x0080
138 #define NE_SEGFLAGS_RELOC_DATA  0x0100
139 #define NE_SEGFLAGS_SELFLOAD    0x0800
140 #define NE_SEGFLAGS_DISCARDABLE 0x1000
141 #define NE_SEGFLAGS_32BIT       0x2000
142
143 typedef struct {
144     WORD width;
145     DWORD offset;
146 } CHAR_TABLE_ENTRY;
147
148 typedef struct {
149     DWORD version;
150     ULONG numSizes;
151 } eblcHeader_t;
152
153 typedef struct {
154     CHAR ascender;
155     CHAR descender;
156     BYTE widthMax;
157     CHAR caretSlopeNumerator;
158     CHAR caretSlopeDenominator;
159     CHAR caretOffset;
160     CHAR minOriginSB;
161     CHAR minAdvanceSB;
162     CHAR maxBeforeBL;
163     CHAR maxAfterBL;
164     CHAR pad1;
165     CHAR pad2;
166 } sbitLineMetrics_t;
167
168 typedef struct {
169     ULONG indexSubTableArrayOffset;
170     ULONG indexTableSize;
171     ULONG numberOfIndexSubTables;
172     ULONG colorRef;
173     sbitLineMetrics_t hori;
174     sbitLineMetrics_t vert;
175     USHORT startGlyphIndex;
176     USHORT endGlyphIndex;
177     BYTE ppemX;
178     BYTE ppemY;
179     BYTE bitDepth;
180     CHAR flags;
181 } bitmapSizeTable_t;
182
183 typedef struct
184 {
185     FT_Int major;
186     FT_Int minor;
187     FT_Int patch;
188 } FT_Version_t;
189 static FT_Version_t FT_Version;
190
191 #include "poppack.h"
192
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]) ))
196 #ifdef WORDS_BIGENDIAN
197 static WORD byteswap_word(WORD x)
198 {
199     return ( ( (x & 0xff) << 8) |
200              ( (x & 0xff00) >> 8) );
201 }
202 static DWORD byteswap_dword(DWORD x)
203 {
204     return ( ( (x & 0xff) << 24) |
205              ( (x & 0xff00) << 8) |
206              ( (x & 0xff0000) >> 8) |
207              ( (x & 0xff000000) >> 24) );
208 }
209 # define PUT_LE_WORD(x) byteswap_word(x)
210 # define PUT_LE_DWORD(x) byteswap_dword(x)
211 #else
212 # define PUT_LE_WORD(x) (x)
213 # define PUT_LE_DWORD(x) (x)
214 #endif
215
216 struct fontinfo
217 {
218     FNT_HEADER hdr;
219     CHAR_TABLE_ENTRY dfCharTable[258];
220     BYTE *data;
221 };
222
223 static const BYTE MZ_hdr[] =
224 {
225     'M',  'Z',  0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
226     0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
229     0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T',  'h',
230     'i',  's',  ' ',  'P',  'r',  'o',  'g',  'r',  'a',  'm',  ' ',  'c',  'a',  'n',  'n',  'o',
231     't',  ' ',  'b',  'e',  ' ',  'r',  'u',  'n',  ' ',  'i',  'n',  ' ',  'D',  'O',  'S',  ' ',
232     'm',  'o',  'd',  'e',  0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
233 };
234
235 static char *option_output;
236 static int option_defchar = ' ';
237 static int option_dpi = 96;
238 static int option_fnt_mode = 0;
239 static int option_quiet = 0;
240
241 static const char *output_name;
242
243 static FT_Library ft_library;
244
245 static void usage(char **argv)
246 {
247     fprintf(stderr, "%s [options] input.ttf ppem,enc,avg_width ...\n", argv[0]);
248     fprintf(stderr, "Options:\n");
249     fprintf(stderr, "  -h       Display help\n" );
250     fprintf(stderr, "  -d char  Set the font default char\n" );
251     fprintf(stderr, "  -o file  Set output file name\n" );
252     fprintf(stderr, "  -q       Quiet mode\n" );
253     fprintf(stderr, "  -r dpi   Set resolution in DPI (default: 96)\n" );
254     fprintf(stderr, "  -s       Single .fnt file mode\n" );
255 }
256
257 #ifndef __GNUC__
258 #define __attribute__(X)
259 #endif
260
261 /* atexit handler to cleanup files */
262 static void cleanup(void)
263 {
264     if (output_name) unlink( output_name );
265 }
266
267 static void exit_on_signal( int sig )
268 {
269     exit(1);  /* this will call the atexit functions */
270 }
271
272 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
273
274 static void error(const char *s, ...)
275 {
276     va_list ap;
277     va_start(ap, s);
278     fprintf(stderr, "Error: ");
279     vfprintf(stderr, s, ap);
280     va_end(ap);
281     exit(1);
282 }
283
284 static const char *get_face_name( const struct fontinfo *info )
285 {
286     return (const char *)info->data + info->hdr.fi.dfFace - info->hdr.fi.dfBitsOffset;
287 }
288
289 static int lookup_charset(int enc)
290 {
291     /* FIXME: make winelib app and use TranslateCharsetInfo */
292     switch(enc) {
293     case 1250:
294         return EE_CHARSET;
295     case 1251:
296         return RUSSIAN_CHARSET;
297     case 1252:
298         return ANSI_CHARSET;
299     case 1253:
300         return GREEK_CHARSET;
301     case 1254:
302         return TURKISH_CHARSET;
303     case 1255:
304         return HEBREW_CHARSET;
305     case 1256:
306         return ARABIC_CHARSET;
307     case 1257:
308         return BALTIC_CHARSET;
309     case 1258:
310         return VIETNAMESE_CHARSET;
311     case 437:
312     case 737:
313     case 775:
314     case 850:
315     case 852:
316     case 855:
317     case 857:
318     case 860:
319     case 861:
320     case 862:
321     case 863:
322     case 864:
323     case 865:
324     case 866:
325     case 869:
326         return OEM_CHARSET;
327     case 874:
328         return THAI_CHARSET;
329     case 932:
330         return SHIFTJIS_CHARSET;
331     case 936:
332         return GB2312_CHARSET;
333     case 949:
334         return HANGUL_CHARSET;
335     case 950:
336         return CHINESEBIG5_CHARSET;
337     }
338     fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
339
340     return OEM_CHARSET;
341 }
342
343 static int get_char(const union cptable *cptable, int enc, int index)
344 {
345     /* Korean has the Won sign in place of '\\' */
346     if(enc == 949 && index == '\\')
347         return 0x20a9;
348
349     return cptable->sbcs.cp2uni[index];
350 }
351
352 static struct fontinfo *fill_fontinfo( const char *face_name, int ppem, int enc, int dpi,
353                                        unsigned char def_char, int avg_width )
354 {
355     FT_Face face;
356     int ascent = 0, il, el, width_bytes = 0, space_size, max_width = 0;
357     BYTE left_byte, right_byte, byte;
358     DWORD start;
359     int i, x, y, x_off, x_end, first_char;
360     FT_UInt gi;
361     int num_names;
362     const union cptable *cptable;
363     FT_SfntName sfntname;
364     TT_OS2 *os2;
365     FT_ULong needed;
366     eblcHeader_t *eblc;
367     bitmapSizeTable_t *size_table;
368     int num_sizes;
369     struct fontinfo *info;
370     size_t data_pos;
371
372     if (FT_New_Face(ft_library, face_name, 0, &face)) error( "Cannot open face %s\n", face_name );
373     if (FT_Set_Pixel_Sizes(face, ppem, ppem)) error( "cannot set face size to %u\n", ppem );
374
375     cptable = wine_cp_get_table(enc);
376     if(!cptable)
377         error("Can't find codepage %d\n", enc);
378
379     if(cptable->info.char_size != 1) {
380         /* for double byte charsets we actually want to use cp1252 */
381         cptable = wine_cp_get_table(1252);
382         if(!cptable)
383             error("Can't find codepage 1252\n");
384     }
385
386     assert( face->size->metrics.y_ppem == ppem );
387
388     needed = 0;
389     if (FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
390         fprintf(stderr,"Can't find EBLC table\n");
391     else
392     {
393         eblc = malloc(needed);
394         FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
395
396         num_sizes = GET_BE_DWORD(&eblc->numSizes);
397
398         size_table = (bitmapSizeTable_t *)(eblc + 1);
399         for(i = 0; i < num_sizes; i++)
400         {
401             if( (signed char)size_table->hori.ascender - (signed char)size_table->hori.descender == ppem)
402             {
403                 ascent = size_table->hori.ascender;
404                 break;
405             }
406             size_table++;
407         }
408
409         free(eblc);
410     }
411
412     /* Versions of fontforge prior to early 2006 have incorrect
413        ascender values in the eblc table, so we won't find the 
414        correct bitmapSizeTable.  In this case use the height of
415        the Aring glyph instead. */
416     if(ascent == 0) 
417     {
418         if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
419             error("Can't find Aring\n");
420         ascent = face->glyph->metrics.horiBearingY >> 6;
421     }
422
423     start = sizeof(FNT_HEADER);
424
425     if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
426         error("Can't find M\n");
427     il = ascent - (face->glyph->metrics.height >> 6);
428
429     /* Hack: Courier has no internal leading, nor do any Chinese or Japanese fonts */
430     if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950 || enc == 932)
431         il = 0;
432     else if (!strcmp(face->family_name, "Fixedsys"))
433         il = 3;
434
435     /* Japanese System font has an external leading */
436     if (!strcmp(face->family_name, "System") && enc == 932)
437         el = 2;
438     else
439         el = 0;
440
441     first_char = FT_Get_First_Char(face, &gi);
442     if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
443         first_char = 32; /* FT_Get_Next_Char for some reason returns too high
444                             number in this case */
445
446     info = calloc( 1, sizeof(*info) );
447
448     info->hdr.fi.dfFirstChar = first_char;
449     info->hdr.fi.dfLastChar = 0xff;
450     start += ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar + 3 ) * sizeof(*info->dfCharTable);
451
452     num_names = FT_Get_Sfnt_Name_Count(face);
453     for(i = 0; i <num_names; i++) {
454         FT_Get_Sfnt_Name(face, i, &sfntname);
455         if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
456            sfntname.language_id == 0 && sfntname.name_id == 0) {
457             size_t len = min( sfntname.string_len, sizeof(info->hdr.dfCopyright)-1 );
458             memcpy(info->hdr.dfCopyright, sfntname.string, len);
459             info->hdr.dfCopyright[len] = 0;
460         }
461     }
462
463     os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
464     for(i = first_char; i < 0x100; i++) {
465         int c = get_char(cptable, enc, i);
466         gi = FT_Get_Char_Index(face, c);
467         if(gi == 0 && !option_quiet)
468             fprintf(stderr, "warning: %s %u: missing glyph for char %04x\n",
469                     face->family_name, ppem, cptable->sbcs.cp2uni[i]);
470         if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
471             fprintf(stderr, "error loading char %d - bad news!\n", i);
472             continue;
473         }
474         info->dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
475         info->dfCharTable[i].offset = start + (width_bytes * ppem);
476         width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
477         if(max_width < (face->glyph->metrics.horiAdvance >> 6))
478             max_width = face->glyph->metrics.horiAdvance >> 6;
479     }
480     /* space */
481     space_size = (ppem + 3) / 4;
482     info->dfCharTable[i].width = space_size;
483     info->dfCharTable[i].offset = start + (width_bytes * ppem);
484     width_bytes += (space_size + 7) >> 3;
485     /* sentinel */
486     info->dfCharTable[++i].width = 0;
487     info->dfCharTable[i].offset = start + (width_bytes * ppem);
488
489     info->hdr.fi.dfType = 0;
490     info->hdr.fi.dfPoints = ((ppem - il - el) * 72 + dpi/2) / dpi;
491     info->hdr.fi.dfVertRes = dpi;
492     info->hdr.fi.dfHorizRes = dpi;
493     info->hdr.fi.dfAscent = ascent;
494     info->hdr.fi.dfInternalLeading = il;
495     info->hdr.fi.dfExternalLeading = el;
496     info->hdr.fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
497     info->hdr.fi.dfUnderline = 0;
498     info->hdr.fi.dfStrikeOut = 0;
499     info->hdr.fi.dfWeight = os2->usWeightClass;
500     info->hdr.fi.dfCharSet = lookup_charset(enc);
501     info->hdr.fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ? avg_width : 0;
502     info->hdr.fi.dfPixHeight = ppem;
503     info->hdr.fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
504     switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
505     case PAN_FAMILY_SCRIPT:
506         info->hdr.fi.dfPitchAndFamily |= FF_SCRIPT;
507         break;
508     case PAN_FAMILY_DECORATIVE:
509     case PAN_FAMILY_PICTORIAL:
510         info->hdr.fi.dfPitchAndFamily |= FF_DECORATIVE;
511         break;
512     case PAN_FAMILY_TEXT_DISPLAY:
513         if(info->hdr.fi.dfPitchAndFamily == 0) /* fixed */
514             info->hdr.fi.dfPitchAndFamily = FF_MODERN;
515         else {
516             switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
517             case PAN_SERIF_NORMAL_SANS:
518             case PAN_SERIF_OBTUSE_SANS:
519             case PAN_SERIF_PERP_SANS:
520                 info->hdr.fi.dfPitchAndFamily |= FF_SWISS;
521                 break;
522             default:
523                 info->hdr.fi.dfPitchAndFamily |= FF_ROMAN;
524             }
525         }
526         break;
527     default:
528         info->hdr.fi.dfPitchAndFamily |= FF_DONTCARE;
529     }
530
531     info->hdr.fi.dfAvgWidth = avg_width;
532     info->hdr.fi.dfMaxWidth = (enc == 932) ? avg_width * 2 : max_width;
533     info->hdr.fi.dfDefaultChar = def_char - info->hdr.fi.dfFirstChar;
534     info->hdr.fi.dfBreakChar = ' ' - info->hdr.fi.dfFirstChar;
535     info->hdr.fi.dfWidthBytes = (width_bytes + 1) & ~1;
536
537     info->hdr.fi.dfFace = start + info->hdr.fi.dfWidthBytes * ppem;
538     info->hdr.fi.dfBitsOffset = start;
539     info->hdr.fi.dfFlags = 0x10; /* DFF_1COLOR */
540     info->hdr.fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
541
542     info->hdr.dfVersion = 0x300;
543     info->hdr.dfSize = start + info->hdr.fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
544
545     info->data = calloc( info->hdr.dfSize - start, 1 );
546     data_pos = 0;
547
548     for(i = first_char; i < 0x100; i++) {
549         int c = get_char(cptable, enc, i);
550         if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
551             continue;
552         }
553         assert(info->dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
554
555         for(x = 0; x < ((info->dfCharTable[i].width + 7) / 8); x++) {
556             for(y = 0; y < ppem; y++) {
557                 if(y < ascent - face->glyph->bitmap_top ||
558                    y >=  face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
559                     info->data[data_pos++] = 0;
560                     continue;
561                 }
562                 x_off = face->glyph->bitmap_left / 8;
563                 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
564                 if(x < x_off || x > x_end) {
565                     info->data[data_pos++] = 0;
566                     continue;
567                 }
568                 if(x == x_off)
569                     left_byte = 0;
570                 else
571                     left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
572
573                 /* On the last non-trivial output byte (x == x_end) have we got one or two input bytes */
574                 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)))
575                     right_byte = 0;
576                 else
577                     right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
578
579                 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
580                 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
581                 info->data[data_pos++] = byte;
582             }
583         }
584     }
585     data_pos += ((space_size + 7) / 8) * ppem;
586     if (width_bytes & 1) data_pos += ppem;
587
588     memcpy( info->data + data_pos, face->family_name, strlen( face->family_name ));
589     data_pos += strlen( face->family_name ) + 1;
590     assert( start + data_pos == info->hdr.dfSize );
591
592     FT_Done_Face( face );
593     return info;
594 }
595
596 static void adjust_fontinfo( FONTINFO16 * fi )
597 {
598     fi->dfType = PUT_LE_WORD(fi->dfType);
599     fi->dfPoints = PUT_LE_WORD(fi->dfPoints);
600     fi->dfVertRes = PUT_LE_WORD(fi->dfVertRes);
601     fi->dfHorizRes = PUT_LE_WORD(fi->dfHorizRes);
602     fi->dfAscent = PUT_LE_WORD(fi->dfAscent);
603     fi->dfInternalLeading = PUT_LE_WORD(fi->dfInternalLeading);
604     fi->dfExternalLeading = PUT_LE_WORD(fi->dfExternalLeading);
605     fi->dfWeight = PUT_LE_WORD(fi->dfWeight);
606     fi->dfPixWidth = PUT_LE_WORD(fi->dfPixWidth);
607     fi->dfPixHeight = PUT_LE_WORD(fi->dfPixHeight);
608     fi->dfAvgWidth = PUT_LE_WORD(fi->dfAvgWidth);
609     fi->dfMaxWidth = PUT_LE_WORD(fi->dfMaxWidth);
610     fi->dfWidthBytes = PUT_LE_WORD(fi->dfWidthBytes);
611     fi->dfAspace = PUT_LE_WORD(fi->dfAspace);
612     fi->dfBspace = PUT_LE_WORD(fi->dfBspace);
613     fi->dfCspace = PUT_LE_WORD(fi->dfCspace);
614     fi->dfDevice = PUT_LE_DWORD(fi->dfDevice);
615     fi->dfFace = PUT_LE_DWORD(fi->dfFace);
616     fi->dfBitsPointer = PUT_LE_DWORD(fi->dfBitsPointer);
617     fi->dfBitsOffset = PUT_LE_DWORD(fi->dfBitsOffset);
618     fi->dfFlags = PUT_LE_DWORD(fi->dfFlags);
619     fi->dfColorPointer = PUT_LE_DWORD(fi->dfColorPointer);
620 }
621
622 static void write_fontinfo( const struct fontinfo *info, FILE *fp )
623 {
624     FNT_HEADER tmp_hdr;
625     int num_chars, i;
626     CHAR_TABLE_ENTRY tmp_chartable[258];
627     memcpy(&tmp_hdr, &info->hdr, sizeof(info->hdr));
628     tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
629     tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
630     adjust_fontinfo(&(tmp_hdr.fi));
631     fwrite( &tmp_hdr, sizeof(info->hdr), 1, fp );
632     num_chars = ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar) + 3;
633
634     memcpy(&tmp_chartable, info->dfCharTable + info->hdr.fi.dfFirstChar, num_chars * sizeof(CHAR_TABLE_ENTRY));
635     for (i=0; i < num_chars; ++i) {
636         tmp_chartable[i].width = PUT_LE_WORD(tmp_chartable[i].width);
637         tmp_chartable[i].offset = PUT_LE_DWORD(tmp_chartable[i].offset);
638     }
639     fwrite( tmp_chartable, sizeof(CHAR_TABLE_ENTRY), num_chars, fp );
640     fwrite( info->data, info->hdr.dfSize - info->hdr.fi.dfBitsOffset, 1, fp );
641 }
642
643 /* parse options from the argv array and remove all the recognized ones */
644 static char **parse_options( int argc, char **argv )
645 {
646     int optc;
647
648     while ((optc = getopt( argc, argv, "d:ho:qr:s" )) != -1)
649     {
650         switch(optc)
651         {
652         case 'd':
653             option_defchar = atoi( optarg );
654             break;
655         case 'o':
656             option_output = strdup( optarg );
657             break;
658         case 'q':
659             option_quiet = 1;
660             break;
661         case 'r':
662             option_dpi = atoi( optarg );
663             break;
664         case 's':
665             option_fnt_mode = 1;
666             break;
667         case 'h':
668             usage(argv);
669             exit(0);
670         case '?':
671             usage(argv);
672             exit(1);
673         }
674     }
675     return &argv[optind];
676 }
677
678 int main(int argc, char **argv)
679 {
680     int i, j;
681     FILE *ofp;
682     short align, num_files;
683     int resource_table_len, non_resident_name_len, resident_name_len;
684     unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, font_off;
685     char resident_name[200];
686     int fontdir_len = 2;
687     char non_resident_name[200];
688     unsigned short first_res = 0x0050, pad, res;
689     IMAGE_OS2_HEADER NE_hdr;
690     NE_TYPEINFO rc_type;
691     NE_NAMEINFO rc_name;
692     struct fontinfo **info;
693     char *input_file;
694     char **args;
695     short tmp16;
696
697     args = parse_options( argc, argv );
698
699     input_file = *args++;
700     if (!input_file || !*args)
701     {
702         usage(argv);
703         exit(1);
704     }
705
706     if(FT_Init_FreeType(&ft_library))
707         error("ft init failure\n");
708
709     FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
710     FT_Library_Version(ft_library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
711
712     num_files = 0;
713     while (args[num_files]) num_files++;
714
715     if (option_fnt_mode && num_files > 1)
716         error( "can only specify one font in .fnt mode\n" );
717
718     info = malloc( num_files * sizeof(*info) );
719     for (i = 0; i < num_files; i++)
720     {
721         int ppem, enc, avg_width;
722         const char *name;
723
724         if (sscanf( args[i], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
725         {
726             usage(argv);
727             exit(1);
728         }
729         if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
730             exit(1);
731
732         name = get_face_name( info[i] );
733         fontdir_len += 0x74 + strlen(name) + 1;
734         if(i == 0) {
735             sprintf(non_resident_name, "FONTRES 100,%d,%d : %s %d",
736                     info[i]->hdr.fi.dfVertRes, info[i]->hdr.fi.dfHorizRes,
737                     name, info[i]->hdr.fi.dfPoints );
738             strcpy(resident_name, name);
739         } else {
740             sprintf(non_resident_name + strlen(non_resident_name), ",%d", info[i]->hdr.fi.dfPoints );
741         }
742     }
743
744     if (option_dpi <= 108)
745         strcat(non_resident_name, " (VGA res)");
746     else
747         strcat(non_resident_name, " (8514 res)");
748     non_resident_name_len = strlen(non_resident_name) + 4;
749
750     /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
751     resource_table_len = sizeof(align) + sizeof("FONTDIR") +
752                          sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) +
753                          sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) * num_files +
754                          sizeof(NE_TYPEINFO);
755     resource_table_off = sizeof(NE_hdr);
756     resident_name_off = resource_table_off + resource_table_len;
757     resident_name_len = strlen(resident_name) + 4;
758     module_ref_off = resident_name_off + resident_name_len;
759     non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(align);
760
761     memset(&NE_hdr, 0, sizeof(NE_hdr));
762     NE_hdr.ne_magic = PUT_LE_WORD(0x454e);
763     NE_hdr.ne_ver = 5;
764     NE_hdr.ne_rev = 1;
765     NE_hdr.ne_flags = PUT_LE_WORD(NE_FFLAGS_LIBMODULE | NE_FFLAGS_GUI);
766     NE_hdr.ne_cbnrestab = PUT_LE_WORD(non_resident_name_len);
767     NE_hdr.ne_segtab = PUT_LE_WORD(sizeof(NE_hdr));
768     NE_hdr.ne_rsrctab = PUT_LE_WORD(sizeof(NE_hdr));
769     NE_hdr.ne_restab = PUT_LE_WORD(resident_name_off);
770     NE_hdr.ne_modtab = PUT_LE_WORD(module_ref_off);
771     NE_hdr.ne_imptab = PUT_LE_WORD(module_ref_off);
772     NE_hdr.ne_enttab = NE_hdr.ne_modtab;
773     NE_hdr.ne_nrestab = PUT_LE_DWORD(non_resident_name_off);
774     NE_hdr.ne_align = PUT_LE_WORD(4);
775     NE_hdr.ne_exetyp = NE_OSFLAGS_WINDOWS;
776     NE_hdr.ne_expver = PUT_LE_WORD(0x400);
777
778     fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
779     font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
780
781     atexit( cleanup );
782     signal( SIGTERM, exit_on_signal );
783     signal( SIGINT, exit_on_signal );
784 #ifdef SIGHUP
785     signal( SIGHUP, exit_on_signal );
786 #endif
787
788     if (!option_output)  /* build a default output name */
789     {
790         char *p = strrchr( input_file, '/' );
791         if (p) p++;
792         else p = input_file;
793         option_output = malloc( strlen(p) + sizeof(".fon") );
794         strcpy( option_output, p );
795         p = strrchr( option_output, '.' );
796         if (!p) p = option_output + strlen(option_output);
797         strcpy( p, option_fnt_mode ? ".fnt" : ".fon" );
798     }
799
800     if (!(ofp = fopen(option_output, "wb")))
801     {
802         perror( option_output );
803         exit(1);
804     }
805     output_name = option_output;
806     if (option_fnt_mode)
807     {
808         write_fontinfo( info[0], ofp );
809         goto done;
810     }
811
812     fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
813     fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
814
815     align = PUT_LE_WORD(4);
816     fwrite(&align, sizeof(align), 1, ofp);
817
818     rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONTDIR);
819     rc_type.count = PUT_LE_WORD(1);
820     rc_type.resloader = 0;
821     fwrite(&rc_type, sizeof(rc_type), 1, ofp);
822
823     rc_name.offset = PUT_LE_WORD(fontdir_off >> 4);
824     rc_name.length = PUT_LE_WORD((fontdir_len + 15) >> 4);
825     rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD);
826     rc_name.id = PUT_LE_WORD(resident_name_off - sizeof("FONTDIR") - sizeof(NE_hdr));
827     rc_name.handle = 0;
828     rc_name.usage = 0;
829     fwrite(&rc_name, sizeof(rc_name), 1, ofp);
830
831     rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONT);
832     rc_type.count = PUT_LE_WORD(num_files);
833     rc_type.resloader = 0;
834     fwrite(&rc_type, sizeof(rc_type), 1, ofp);
835
836     for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
837         int len = (info[i]->hdr.dfSize + 15) & ~0xf;
838
839         rc_name.offset = PUT_LE_WORD(font_off >> 4);
840         rc_name.length = PUT_LE_WORD(len >> 4);
841         rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_SHAREABLE | NE_SEGFLAGS_DISCARDABLE);
842         rc_name.id = PUT_LE_WORD(res);
843         rc_name.handle = 0;
844         rc_name.usage = 0;
845         fwrite(&rc_name, sizeof(rc_name), 1, ofp);
846
847         font_off += len;
848     }
849
850     /* empty type info */
851     memset(&rc_type, 0, sizeof(rc_type));
852     fwrite(&rc_type, sizeof(rc_type), 1, ofp);
853
854     fputc(strlen("FONTDIR"), ofp);
855     fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp);
856     fputc(strlen(resident_name), ofp);
857     fwrite(resident_name, strlen(resident_name), 1, ofp);
858
859     fputc(0x00, ofp);    fputc(0x00, ofp);
860     fputc(0x00, ofp);
861     fputc(0x00, ofp);    fputc(0x00, ofp);
862
863     fputc(strlen(non_resident_name), ofp);
864     fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
865     fputc(0x00, ofp); /* terminator */
866
867     /* empty ne_modtab and ne_imptab */
868     fputc(0x00, ofp);
869     fputc(0x00, ofp);
870
871     pad = ftell(ofp) & 0xf;
872     if(pad != 0)
873         pad = 0x10 - pad;
874     for(i = 0; i < pad; i++)
875         fputc(0x00, ofp);
876
877     /* FONTDIR resource */
878     tmp16 = PUT_LE_WORD(num_files);
879     fwrite(&tmp16, sizeof(tmp16), 1, ofp);
880
881     for(res = first_res, i = 0; i < num_files; i++, res++) {
882         FNT_HEADER tmp_hdr;
883         int sz;
884         const char *name = get_face_name( info[i] );
885         tmp16 = PUT_LE_WORD(res);
886         fwrite(&tmp16, sizeof(tmp16), 1, ofp);
887         sz = FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset);
888         memcpy(&tmp_hdr, &info[i]->hdr, sz);
889         tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
890         tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
891         adjust_fontinfo(&(tmp_hdr.fi));
892         fwrite(&tmp_hdr, FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset), 1, ofp);
893         fputc(0x00, ofp);
894         fwrite(name, strlen(name) + 1, 1, ofp);
895     }
896
897     pad = ftell(ofp) & 0xf;
898     if(pad != 0)
899         pad = 0x10 - pad;
900     for(i = 0; i < pad; i++)
901         fputc(0x00, ofp);
902
903     for(res = first_res, i = 0; i < num_files; i++, res++) {
904         write_fontinfo( info[i], ofp );
905         pad = info[i]->hdr.dfSize & 0xf;
906         if(pad != 0)
907             pad = 0x10 - pad;
908         for(j = 0; j < pad; j++)
909             fputc(0x00, ofp);
910     }
911 done:
912     fclose(ofp);
913     output_name = NULL;
914     exit(0);
915 }
916
917 #else /* HAVE_FREETYPE */
918
919 int main(int argc, char **argv)
920 {
921     fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
922     exit(1);
923 }
924
925 #endif /* HAVE_FREETYPE */