winex11: Explicitly clear virtual desktop maximized state.
[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     /* Japanese system fonts have an external leading (not small font) */
433     if (enc == 932 && ppem > 11)
434         el = 2;
435     else
436         el = 0;
437
438     first_char = FT_Get_First_Char(face, &gi);
439     if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
440         first_char = 32; /* FT_Get_Next_Char for some reason returns too high
441                             number in this case */
442
443     info = calloc( 1, sizeof(*info) );
444
445     info->hdr.fi.dfFirstChar = first_char;
446     info->hdr.fi.dfLastChar = 0xff;
447     start += ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar + 3 ) * sizeof(*info->dfCharTable);
448
449     num_names = FT_Get_Sfnt_Name_Count(face);
450     for(i = 0; i <num_names; i++) {
451         FT_Get_Sfnt_Name(face, i, &sfntname);
452         if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
453            sfntname.language_id == 0 && sfntname.name_id == 0) {
454             size_t len = min( sfntname.string_len, sizeof(info->hdr.dfCopyright)-1 );
455             memcpy(info->hdr.dfCopyright, sfntname.string, len);
456             info->hdr.dfCopyright[len] = 0;
457         }
458     }
459
460     os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
461     for(i = first_char; i < 0x100; i++) {
462         int c = get_char(cptable, enc, i);
463         gi = FT_Get_Char_Index(face, c);
464         if(gi == 0 && !option_quiet)
465             fprintf(stderr, "warning: %s %u: missing glyph for char %04x\n",
466                     face->family_name, ppem, cptable->sbcs.cp2uni[i]);
467         if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
468             fprintf(stderr, "error loading char %d - bad news!\n", i);
469             continue;
470         }
471         info->dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
472         info->dfCharTable[i].offset = start + (width_bytes * ppem);
473         width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
474         if(max_width < (face->glyph->metrics.horiAdvance >> 6))
475             max_width = face->glyph->metrics.horiAdvance >> 6;
476     }
477     /* space */
478     space_size = (ppem + 3) / 4;
479     info->dfCharTable[i].width = space_size;
480     info->dfCharTable[i].offset = start + (width_bytes * ppem);
481     width_bytes += (space_size + 7) >> 3;
482     /* sentinel */
483     info->dfCharTable[++i].width = 0;
484     info->dfCharTable[i].offset = start + (width_bytes * ppem);
485
486     info->hdr.fi.dfType = 0;
487     info->hdr.fi.dfPoints = ((ppem - il - el) * 72 + dpi/2) / dpi;
488     info->hdr.fi.dfVertRes = dpi;
489     info->hdr.fi.dfHorizRes = dpi;
490     info->hdr.fi.dfAscent = ascent;
491     info->hdr.fi.dfInternalLeading = il;
492     info->hdr.fi.dfExternalLeading = el;
493     info->hdr.fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
494     info->hdr.fi.dfUnderline = 0;
495     info->hdr.fi.dfStrikeOut = 0;
496     info->hdr.fi.dfWeight = os2->usWeightClass;
497     info->hdr.fi.dfCharSet = lookup_charset(enc);
498     info->hdr.fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ? avg_width : 0;
499     info->hdr.fi.dfPixHeight = ppem;
500     info->hdr.fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
501     switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
502     case PAN_FAMILY_SCRIPT:
503         info->hdr.fi.dfPitchAndFamily |= FF_SCRIPT;
504         break;
505     case PAN_FAMILY_DECORATIVE:
506     case PAN_FAMILY_PICTORIAL:
507         info->hdr.fi.dfPitchAndFamily |= FF_DECORATIVE;
508         break;
509     case PAN_FAMILY_TEXT_DISPLAY:
510         if(info->hdr.fi.dfPitchAndFamily == 0) /* fixed */
511             info->hdr.fi.dfPitchAndFamily = FF_MODERN;
512         else {
513             switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
514             case PAN_SERIF_NORMAL_SANS:
515             case PAN_SERIF_OBTUSE_SANS:
516             case PAN_SERIF_PERP_SANS:
517                 info->hdr.fi.dfPitchAndFamily |= FF_SWISS;
518                 break;
519             default:
520                 info->hdr.fi.dfPitchAndFamily |= FF_ROMAN;
521             }
522         }
523         break;
524     default:
525         info->hdr.fi.dfPitchAndFamily |= FF_DONTCARE;
526     }
527
528     info->hdr.fi.dfAvgWidth = avg_width;
529     info->hdr.fi.dfMaxWidth = max_width;
530     info->hdr.fi.dfDefaultChar = def_char - info->hdr.fi.dfFirstChar;
531     info->hdr.fi.dfBreakChar = ' ' - info->hdr.fi.dfFirstChar;
532     info->hdr.fi.dfWidthBytes = (width_bytes + 1) & ~1;
533
534     info->hdr.fi.dfFace = start + info->hdr.fi.dfWidthBytes * ppem;
535     info->hdr.fi.dfBitsOffset = start;
536     info->hdr.fi.dfFlags = 0x10; /* DFF_1COLOR */
537     info->hdr.fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
538
539     info->hdr.dfVersion = 0x300;
540     info->hdr.dfSize = start + info->hdr.fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
541
542     info->data = calloc( info->hdr.dfSize - start, 1 );
543     data_pos = 0;
544
545     for(i = first_char; i < 0x100; i++) {
546         int c = get_char(cptable, enc, i);
547         if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
548             continue;
549         }
550         assert(info->dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
551
552         for(x = 0; x < ((info->dfCharTable[i].width + 7) / 8); x++) {
553             for(y = 0; y < ppem; y++) {
554                 if(y < ascent - face->glyph->bitmap_top ||
555                    y >=  face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
556                     info->data[data_pos++] = 0;
557                     continue;
558                 }
559                 x_off = face->glyph->bitmap_left / 8;
560                 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
561                 if(x < x_off || x > x_end) {
562                     info->data[data_pos++] = 0;
563                     continue;
564                 }
565                 if(x == x_off)
566                     left_byte = 0;
567                 else
568                     left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
569
570                 /* On the last non-trivial output byte (x == x_end) have we got one or two input bytes */
571                 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)))
572                     right_byte = 0;
573                 else
574                     right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
575
576                 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
577                 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
578                 info->data[data_pos++] = byte;
579             }
580         }
581     }
582     data_pos += ((space_size + 7) / 8) * ppem;
583     if (width_bytes & 1) data_pos += ppem;
584
585     memcpy( info->data + data_pos, face->family_name, strlen( face->family_name ));
586     data_pos += strlen( face->family_name ) + 1;
587     assert( start + data_pos == info->hdr.dfSize );
588
589     FT_Done_Face( face );
590     return info;
591 }
592
593 static void adjust_fontinfo( FONTINFO16 * fi )
594 {
595     fi->dfType = PUT_LE_WORD(fi->dfType);
596     fi->dfPoints = PUT_LE_WORD(fi->dfPoints);
597     fi->dfVertRes = PUT_LE_WORD(fi->dfVertRes);
598     fi->dfHorizRes = PUT_LE_WORD(fi->dfHorizRes);
599     fi->dfAscent = PUT_LE_WORD(fi->dfAscent);
600     fi->dfInternalLeading = PUT_LE_WORD(fi->dfInternalLeading);
601     fi->dfExternalLeading = PUT_LE_WORD(fi->dfExternalLeading);
602     fi->dfWeight = PUT_LE_WORD(fi->dfWeight);
603     fi->dfPixWidth = PUT_LE_WORD(fi->dfPixWidth);
604     fi->dfPixHeight = PUT_LE_WORD(fi->dfPixHeight);
605     fi->dfAvgWidth = PUT_LE_WORD(fi->dfAvgWidth);
606     fi->dfMaxWidth = PUT_LE_WORD(fi->dfMaxWidth);
607     fi->dfWidthBytes = PUT_LE_WORD(fi->dfWidthBytes);
608     fi->dfAspace = PUT_LE_WORD(fi->dfAspace);
609     fi->dfBspace = PUT_LE_WORD(fi->dfBspace);
610     fi->dfCspace = PUT_LE_WORD(fi->dfCspace);
611     fi->dfDevice = PUT_LE_DWORD(fi->dfDevice);
612     fi->dfFace = PUT_LE_DWORD(fi->dfFace);
613     fi->dfBitsPointer = PUT_LE_DWORD(fi->dfBitsPointer);
614     fi->dfBitsOffset = PUT_LE_DWORD(fi->dfBitsOffset);
615     fi->dfFlags = PUT_LE_DWORD(fi->dfFlags);
616     fi->dfColorPointer = PUT_LE_DWORD(fi->dfColorPointer);
617 }
618
619 static void write_fontinfo( const struct fontinfo *info, FILE *fp )
620 {
621     FNT_HEADER tmp_hdr;
622     int num_chars, i;
623     CHAR_TABLE_ENTRY tmp_chartable[258];
624     memcpy(&tmp_hdr, &info->hdr, sizeof(info->hdr));
625     tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
626     tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
627     adjust_fontinfo(&(tmp_hdr.fi));
628     fwrite( &tmp_hdr, sizeof(info->hdr), 1, fp );
629     num_chars = ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar) + 3;
630
631     memcpy(&tmp_chartable, info->dfCharTable + info->hdr.fi.dfFirstChar, num_chars * sizeof(CHAR_TABLE_ENTRY));
632     for (i=0; i < num_chars; ++i) {
633         tmp_chartable[i].width = PUT_LE_WORD(tmp_chartable[i].width);
634         tmp_chartable[i].offset = PUT_LE_DWORD(tmp_chartable[i].offset);
635     }
636     fwrite( tmp_chartable, sizeof(CHAR_TABLE_ENTRY), num_chars, fp );
637     fwrite( info->data, info->hdr.dfSize - info->hdr.fi.dfBitsOffset, 1, fp );
638 }
639
640 /* parse options from the argv array and remove all the recognized ones */
641 static char **parse_options( int argc, char **argv )
642 {
643     int optc;
644
645     while ((optc = getopt( argc, argv, "d:ho:qr:s" )) != -1)
646     {
647         switch(optc)
648         {
649         case 'd':
650             option_defchar = atoi( optarg );
651             break;
652         case 'o':
653             option_output = strdup( optarg );
654             break;
655         case 'q':
656             option_quiet = 1;
657             break;
658         case 'r':
659             option_dpi = atoi( optarg );
660             break;
661         case 's':
662             option_fnt_mode = 1;
663             break;
664         case 'h':
665             usage(argv);
666             exit(0);
667         case '?':
668             usage(argv);
669             exit(1);
670         }
671     }
672     return &argv[optind];
673 }
674
675 int main(int argc, char **argv)
676 {
677     int i, j;
678     FILE *ofp;
679     short align, num_files;
680     int resource_table_len, non_resident_name_len, resident_name_len;
681     unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, font_off;
682     char resident_name[200];
683     int fontdir_len = 2;
684     char non_resident_name[200];
685     unsigned short first_res = 0x0050, pad, res;
686     IMAGE_OS2_HEADER NE_hdr;
687     NE_TYPEINFO rc_type;
688     NE_NAMEINFO rc_name;
689     struct fontinfo **info;
690     char *input_file;
691     char **args;
692     short tmp16;
693
694     args = parse_options( argc, argv );
695
696     input_file = *args++;
697     if (!input_file || !*args)
698     {
699         usage(argv);
700         exit(1);
701     }
702
703     if(FT_Init_FreeType(&ft_library))
704         error("ft init failure\n");
705
706     FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
707     FT_Library_Version(ft_library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
708
709     num_files = 0;
710     while (args[num_files]) num_files++;
711
712     if (option_fnt_mode && num_files > 1)
713         error( "can only specify one font in .fnt mode\n" );
714
715     info = malloc( num_files * sizeof(*info) );
716     for (i = 0; i < num_files; i++)
717     {
718         int ppem, enc, avg_width;
719         const char *name;
720
721         if (sscanf( args[i], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
722         {
723             usage(argv);
724             exit(1);
725         }
726         if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
727             exit(1);
728
729         name = get_face_name( info[i] );
730         fontdir_len += 0x74 + strlen(name) + 1;
731         if(i == 0) {
732             sprintf(non_resident_name, "FONTRES 100,%d,%d : %s %d",
733                     info[i]->hdr.fi.dfVertRes, info[i]->hdr.fi.dfHorizRes,
734                     name, info[i]->hdr.fi.dfPoints );
735             strcpy(resident_name, name);
736         } else {
737             sprintf(non_resident_name + strlen(non_resident_name), ",%d", info[i]->hdr.fi.dfPoints );
738         }
739     }
740
741     if (option_dpi <= 108)
742         strcat(non_resident_name, " (VGA res)");
743     else
744         strcat(non_resident_name, " (8514 res)");
745     non_resident_name_len = strlen(non_resident_name) + 4;
746
747     /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
748     resource_table_len = sizeof(align) + sizeof("FONTDIR") +
749                          sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) +
750                          sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) * num_files +
751                          sizeof(NE_TYPEINFO);
752     resource_table_off = sizeof(NE_hdr);
753     resident_name_off = resource_table_off + resource_table_len;
754     resident_name_len = strlen(resident_name) + 4;
755     module_ref_off = resident_name_off + resident_name_len;
756     non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(align);
757
758     memset(&NE_hdr, 0, sizeof(NE_hdr));
759     NE_hdr.ne_magic = PUT_LE_WORD(0x454e);
760     NE_hdr.ne_ver = 5;
761     NE_hdr.ne_rev = 1;
762     NE_hdr.ne_flags = PUT_LE_WORD(NE_FFLAGS_LIBMODULE | NE_FFLAGS_GUI);
763     NE_hdr.ne_cbnrestab = PUT_LE_WORD(non_resident_name_len);
764     NE_hdr.ne_segtab = PUT_LE_WORD(sizeof(NE_hdr));
765     NE_hdr.ne_rsrctab = PUT_LE_WORD(sizeof(NE_hdr));
766     NE_hdr.ne_restab = PUT_LE_WORD(resident_name_off);
767     NE_hdr.ne_modtab = PUT_LE_WORD(module_ref_off);
768     NE_hdr.ne_imptab = PUT_LE_WORD(module_ref_off);
769     NE_hdr.ne_enttab = NE_hdr.ne_modtab;
770     NE_hdr.ne_nrestab = PUT_LE_DWORD(non_resident_name_off);
771     NE_hdr.ne_align = PUT_LE_WORD(4);
772     NE_hdr.ne_exetyp = NE_OSFLAGS_WINDOWS;
773     NE_hdr.ne_expver = PUT_LE_WORD(0x400);
774
775     fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
776     font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
777
778     atexit( cleanup );
779     signal( SIGTERM, exit_on_signal );
780     signal( SIGINT, exit_on_signal );
781 #ifdef SIGHUP
782     signal( SIGHUP, exit_on_signal );
783 #endif
784
785     if (!option_output)  /* build a default output name */
786     {
787         char *p = strrchr( input_file, '/' );
788         if (p) p++;
789         else p = input_file;
790         option_output = malloc( strlen(p) + sizeof(".fon") );
791         strcpy( option_output, p );
792         p = strrchr( option_output, '.' );
793         if (!p) p = option_output + strlen(option_output);
794         strcpy( p, option_fnt_mode ? ".fnt" : ".fon" );
795     }
796
797     if (!(ofp = fopen(option_output, "wb")))
798     {
799         perror( option_output );
800         exit(1);
801     }
802     output_name = option_output;
803     if (option_fnt_mode)
804     {
805         write_fontinfo( info[0], ofp );
806         goto done;
807     }
808
809     fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
810     fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
811
812     align = PUT_LE_WORD(4);
813     fwrite(&align, sizeof(align), 1, ofp);
814
815     rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONTDIR);
816     rc_type.count = PUT_LE_WORD(1);
817     rc_type.resloader = 0;
818     fwrite(&rc_type, sizeof(rc_type), 1, ofp);
819
820     rc_name.offset = PUT_LE_WORD(fontdir_off >> 4);
821     rc_name.length = PUT_LE_WORD((fontdir_len + 15) >> 4);
822     rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD);
823     rc_name.id = PUT_LE_WORD(resident_name_off - sizeof("FONTDIR") - sizeof(NE_hdr));
824     rc_name.handle = 0;
825     rc_name.usage = 0;
826     fwrite(&rc_name, sizeof(rc_name), 1, ofp);
827
828     rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONT);
829     rc_type.count = PUT_LE_WORD(num_files);
830     rc_type.resloader = 0;
831     fwrite(&rc_type, sizeof(rc_type), 1, ofp);
832
833     for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
834         int len = (info[i]->hdr.dfSize + 15) & ~0xf;
835
836         rc_name.offset = PUT_LE_WORD(font_off >> 4);
837         rc_name.length = PUT_LE_WORD(len >> 4);
838         rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_SHAREABLE | NE_SEGFLAGS_DISCARDABLE);
839         rc_name.id = PUT_LE_WORD(res);
840         rc_name.handle = 0;
841         rc_name.usage = 0;
842         fwrite(&rc_name, sizeof(rc_name), 1, ofp);
843
844         font_off += len;
845     }
846
847     /* empty type info */
848     memset(&rc_type, 0, sizeof(rc_type));
849     fwrite(&rc_type, sizeof(rc_type), 1, ofp);
850
851     fputc(strlen("FONTDIR"), ofp);
852     fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp);
853     fputc(strlen(resident_name), ofp);
854     fwrite(resident_name, strlen(resident_name), 1, ofp);
855
856     fputc(0x00, ofp);    fputc(0x00, ofp);
857     fputc(0x00, ofp);
858     fputc(0x00, ofp);    fputc(0x00, ofp);
859
860     fputc(strlen(non_resident_name), ofp);
861     fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
862     fputc(0x00, ofp); /* terminator */
863
864     /* empty ne_modtab and ne_imptab */
865     fputc(0x00, ofp);
866     fputc(0x00, ofp);
867
868     pad = ftell(ofp) & 0xf;
869     if(pad != 0)
870         pad = 0x10 - pad;
871     for(i = 0; i < pad; i++)
872         fputc(0x00, ofp);
873
874     /* FONTDIR resource */
875     tmp16 = PUT_LE_WORD(num_files);
876     fwrite(&tmp16, sizeof(tmp16), 1, ofp);
877
878     for(res = first_res, i = 0; i < num_files; i++, res++) {
879         FNT_HEADER tmp_hdr;
880         int sz;
881         const char *name = get_face_name( info[i] );
882         tmp16 = PUT_LE_WORD(res);
883         fwrite(&tmp16, sizeof(tmp16), 1, ofp);
884         sz = FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset);
885         memcpy(&tmp_hdr, &info[i]->hdr, sz);
886         tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
887         tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
888         adjust_fontinfo(&(tmp_hdr.fi));
889         fwrite(&tmp_hdr, FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset), 1, ofp);
890         fputc(0x00, ofp);
891         fwrite(name, strlen(name) + 1, 1, ofp);
892     }
893
894     pad = ftell(ofp) & 0xf;
895     if(pad != 0)
896         pad = 0x10 - pad;
897     for(i = 0; i < pad; i++)
898         fputc(0x00, ofp);
899
900     for(res = first_res, i = 0; i < num_files; i++, res++) {
901         write_fontinfo( info[i], ofp );
902         pad = info[i]->hdr.dfSize & 0xf;
903         if(pad != 0)
904             pad = 0x10 - pad;
905         for(j = 0; j < pad; j++)
906             fputc(0x00, ofp);
907     }
908 done:
909     fclose(ofp);
910     output_name = NULL;
911     exit(0);
912 }
913
914 #else /* HAVE_FREETYPE */
915
916 int main(int argc, char **argv)
917 {
918     fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
919     exit(1);
920 }
921
922 #endif /* HAVE_FREETYPE */