server: Implement registry symlinks.
[wine/multimedia.git] / tools / sfnt2fnt.c
blob3b6cafcf7cfccc1980e517b04082c7cb17fa706b
1 /*
2 * sfnttofnt. Bitmap only ttf to Window fnt file converter
4 * Copyright 2004 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #ifdef HAVE_GETOPT_H
31 # include <getopt.h>
32 #endif
34 #ifdef HAVE_FREETYPE
36 #ifdef HAVE_FT2BUILD_H
37 #include <ft2build.h>
38 #endif
39 #include FT_FREETYPE_H
40 #include FT_SFNT_NAMES_H
41 #include FT_TRUETYPE_TABLES_H
42 #include FT_TRUETYPE_TAGS_H
43 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
44 #include <freetype/internal/sfnt.h>
45 #endif
47 #include "wine/unicode.h"
48 #include "wingdi.h"
50 #include "pshpack1.h"
52 typedef struct
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;
89 typedef struct
91 WORD dfVersion;
92 DWORD dfSize;
93 char dfCopyright[60];
94 FONTINFO16 fi;
95 } FNT_HEADER;
97 typedef struct
99 WORD offset;
100 WORD length;
101 WORD flags;
102 WORD id;
103 WORD handle;
104 WORD usage;
105 } NE_NAMEINFO;
107 typedef struct
109 WORD type_id;
110 WORD count;
111 DWORD resloader;
112 } NE_TYPEINFO;
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
125 #define NE_OSFLAGS_WINDOWS 0x02
127 #define NE_RSCTYPE_FONTDIR 0x8007
128 #define NE_RSCTYPE_FONT 0x8008
129 #define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
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
145 typedef struct {
146 WORD width;
147 DWORD offset;
148 } CHAR_TABLE_ENTRY;
150 typedef struct {
151 DWORD version;
152 ULONG numSizes;
153 } eblcHeader_t;
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;
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;
185 typedef struct
187 FT_Int major;
188 FT_Int minor;
189 FT_Int patch;
190 } FT_Version_t;
191 static FT_Version_t FT_Version;
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]) ))
197 #include "poppack.h"
199 struct fontinfo
201 FNT_HEADER hdr;
202 CHAR_TABLE_ENTRY dfCharTable[258];
203 BYTE *data;
206 static const BYTE MZ_hdr[] =
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
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;
224 static const char *output_name;
226 static FT_Library ft_library;
228 static void usage(char **argv)
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" );
240 #ifndef __GNUC__
241 #define __attribute__(X)
242 #endif
244 /* atexit handler to cleanup files */
245 static void cleanup(void)
247 if (output_name) unlink( output_name );
250 static void exit_on_signal( int sig )
252 exit(1); /* this will call the atexit functions */
255 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
257 static void error(const char *s, ...)
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);
267 static const char *get_face_name( const struct fontinfo *info )
269 return (const char *)info->data + info->hdr.fi.dfFace - info->hdr.fi.dfBitsOffset;
272 static int lookup_charset(int enc)
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;
321 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
323 return OEM_CHARSET;
326 static int get_char(const union cptable *cptable, int enc, int index)
328 /* Korean has the Won sign in place of '\\' */
329 if(enc == 949 && index == '\\')
330 return 0x20a9;
332 return cptable->sbcs.cp2uni[index];
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)
339 FT_Error err;
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)
349 /* 2.0.x */
350 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
352 else
354 /* A field was added in the middle of the structure in 2.1.x */
355 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
357 err = sfnt->load_any(tt_face, table, offset, buf, len);
358 #else
359 err = FT_Err_Unimplemented_Feature;
360 #endif
361 return err;
364 static struct fontinfo *fill_fontinfo( const char *face_name, int ppem, int enc, int dpi,
365 unsigned char def_char, int avg_width )
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;
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 );
387 cptable = wine_cp_get_table(enc);
388 if(!cptable)
389 error("Can't find codepage %d\n", enc);
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");
398 assert( face->size->metrics.y_ppem == ppem );
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
405 eblc = malloc(needed);
406 load_sfnt_table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
408 num_sizes = GET_BE_DWORD(&eblc->numSizes);
410 size_table = (bitmapSizeTable_t *)(eblc + 1);
411 for(i = 0; i < num_sizes; i++)
413 if(size_table->hori.ascender - size_table->hori.descender == ppem)
415 ascent = size_table->hori.ascender;
416 descent = -size_table->hori.descender;
417 break;
419 size_table++;
422 free(eblc);
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)
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;
437 start = sizeof(FNT_HEADER);
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);
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;
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 */
457 info = calloc( 1, sizeof(*info) );
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);
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;
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;
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;
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);
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;
537 break;
538 default:
539 info->hdr.fi.dfPitchAndFamily |= FF_DONTCARE;
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;
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 */
553 info->hdr.dfVersion = 0x300;
554 info->hdr.dfSize = start + info->hdr.fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
556 info->data = calloc( info->hdr.dfSize - start, 1 );
557 data_pos = 0;
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;
564 assert(info->dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
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;
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;
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];
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];
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;
596 data_pos += ((space_size + 7) / 8) * ppem;
597 if (width_bytes & 1) data_pos += ppem;
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 );
603 FT_Done_Face( face );
604 return info;
607 static void write_fontinfo( const struct fontinfo *info, FILE *fp )
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 );
615 /* parse options from the argv array and remove all the recognized ones */
616 static char **parse_options( int argc, char **argv )
618 int optc;
620 while ((optc = getopt( argc, argv, "d:ho:qr:s" )) != -1)
622 switch(optc)
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);
647 return &argv[optind];
650 int main(int argc, char **argv)
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;
668 args = parse_options( argc, argv );
670 input_file = *args++;
671 if (!input_file || !*args)
673 usage(argv);
674 exit(1);
677 if(FT_Init_FreeType(&ft_library))
678 error("ft init failure\n");
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);
683 num_files = 0;
684 while (args[num_files]) num_files++;
686 if (option_fnt_mode && num_files > 1)
687 error( "can only specify one font in .fnt mode\n" );
689 info = malloc( num_files * sizeof(*info) );
690 for (i = 0; i < num_files; i++)
692 int ppem, enc, avg_width;
693 const char *name;
695 if (sscanf( args[i], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
697 usage(argv);
698 exit(1);
700 if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
701 exit(1);
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 );
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;
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);
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;
749 fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
750 font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
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
759 if (!option_output) /* build a default output name */
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" );
771 if (!(ofp = fopen(option_output, "wb")))
773 perror( option_output );
774 exit(1);
776 output_name = option_output;
777 if (option_fnt_mode)
779 write_fontinfo( info[0], ofp );
780 goto done;
783 fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
784 fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
786 align = 4;
787 fwrite(&align, sizeof(align), 1, ofp);
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);
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);
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);
807 for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
808 int len = (info[i]->hdr.dfSize + 15) & ~0xf;
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);
818 font_off += len;
821 /* empty type info */
822 memset(&rc_type, 0, sizeof(rc_type));
823 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
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);
830 fputc(0x00, ofp); fputc(0x00, ofp);
831 fputc(0x00, ofp);
832 fputc(0x00, ofp); fputc(0x00, ofp);
834 fputc(strlen(non_resident_name), ofp);
835 fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
836 fputc(0x00, ofp); /* terminator */
838 /* empty ne_modtab and ne_imptab */
839 fputc(0x00, ofp);
840 fputc(0x00, ofp);
842 pad = ftell(ofp) & 0xf;
843 if(pad != 0)
844 pad = 0x10 - pad;
845 for(i = 0; i < pad; i++)
846 fputc(0x00, ofp);
848 /* FONTDIR resource */
849 fwrite(&num_files, sizeof(num_files), 1, ofp);
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);
859 pad = ftell(ofp) & 0xf;
860 if(pad != 0)
861 pad = 0x10 - pad;
862 for(i = 0; i < pad; i++)
863 fputc(0x00, ofp);
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);
873 done:
874 fclose(ofp);
875 output_name = NULL;
876 exit(0);
879 #else /* HAVE_FREETYPE */
881 int main(int argc, char **argv)
883 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
884 exit(1);
887 #endif /* HAVE_FREETYPE */