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