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