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