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
22 #include "wine/port.h"
36 #ifdef HAVE_FT2BUILD_H
39 #include FT_FREETYPE_H
40 #include FT_SFNT_NAMES_H
41 #include FT_TRUETYPE_TABLES_H
42 #include FT_TRUETYPE_TAGS_H
44 #include "wine/unicode.h"
57 INT16 dfInternalLeading;
58 INT16 dfExternalLeading;
66 BYTE dfPitchAndFamily;
112 #define NE_FFLAGS_SINGLEDATA 0x0001
113 #define NE_FFLAGS_MULTIPLEDATA 0x0002
114 #define NE_FFLAGS_WIN32 0x0010
115 #define NE_FFLAGS_FRAMEBUF 0x0100
116 #define NE_FFLAGS_CONSOLE 0x0200
117 #define NE_FFLAGS_GUI 0x0300
118 #define NE_FFLAGS_SELFLOAD 0x0800
119 #define NE_FFLAGS_LINKERROR 0x2000
120 #define NE_FFLAGS_CALLWEP 0x4000
121 #define NE_FFLAGS_LIBMODULE 0x8000
123 #define NE_OSFLAGS_WINDOWS 0x02
125 #define NE_RSCTYPE_FONTDIR 0x8007
126 #define NE_RSCTYPE_FONT 0x8008
127 #define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
129 #define NE_SEGFLAGS_DATA 0x0001
130 #define NE_SEGFLAGS_ALLOCATED 0x0002
131 #define NE_SEGFLAGS_LOADED 0x0004
132 #define NE_SEGFLAGS_ITERATED 0x0008
133 #define NE_SEGFLAGS_MOVEABLE 0x0010
134 #define NE_SEGFLAGS_SHAREABLE 0x0020
135 #define NE_SEGFLAGS_PRELOAD 0x0040
136 #define NE_SEGFLAGS_EXECUTEONLY 0x0080
137 #define NE_SEGFLAGS_READONLY 0x0080
138 #define NE_SEGFLAGS_RELOC_DATA 0x0100
139 #define NE_SEGFLAGS_SELFLOAD 0x0800
140 #define NE_SEGFLAGS_DISCARDABLE 0x1000
141 #define NE_SEGFLAGS_32BIT 0x2000
157 CHAR caretSlopeNumerator;
158 CHAR caretSlopeDenominator;
169 ULONG indexSubTableArrayOffset;
170 ULONG indexTableSize;
171 ULONG numberOfIndexSubTables;
173 sbitLineMetrics_t hori;
174 sbitLineMetrics_t vert;
175 USHORT startGlyphIndex;
176 USHORT endGlyphIndex;
189 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]) ))
196 #ifdef WORDS_BIGENDIAN
197 static WORD byteswap_word(WORD x)
199 return ( ( (x & 0xff) << 8) |
200 ( (x & 0xff00) >> 8) );
202 static DWORD byteswap_dword(DWORD x)
204 return ( ( (x & 0xff) << 24) |
205 ( (x & 0xff00) << 8) |
206 ( (x & 0xff0000) >> 8) |
207 ( (x & 0xff000000) >> 24) );
209 # define PUT_LE_WORD(x) byteswap_word(x)
210 # define PUT_LE_DWORD(x) byteswap_dword(x)
212 # define PUT_LE_WORD(x) (x)
213 # define PUT_LE_DWORD(x) (x)
219 CHAR_TABLE_ENTRY dfCharTable[258];
223 static const BYTE MZ_hdr[] =
225 'M', 'Z', 0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
226 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
229 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
230 'i', 's', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n', 'n', 'o',
231 't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O', 'S', ' ',
232 'm', 'o', 'd', 'e', 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
235 static char *option_output;
236 static int option_defchar = ' ';
237 static int option_dpi = 96;
238 static int option_fnt_mode = 0;
239 static int option_quiet = 0;
241 static const char *output_name;
243 static FT_Library ft_library;
245 static void usage(char **argv)
247 fprintf(stderr, "%s [options] input.ttf ppem,enc,avg_width ...\n", argv[0]);
248 fprintf(stderr, "Options:\n");
249 fprintf(stderr, " -h Display help\n" );
250 fprintf(stderr, " -d char Set the font default char\n" );
251 fprintf(stderr, " -o file Set output file name\n" );
252 fprintf(stderr, " -q Quiet mode\n" );
253 fprintf(stderr, " -r dpi Set resolution in DPI (default: 96)\n" );
254 fprintf(stderr, " -s Single .fnt file mode\n" );
258 #define __attribute__(X)
261 /* atexit handler to cleanup files */
262 static void cleanup(void)
264 if (output_name) unlink( output_name );
267 static void exit_on_signal( int sig )
269 exit(1); /* this will call the atexit functions */
272 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
274 static void error(const char *s, ...)
278 fprintf(stderr, "Error: ");
279 vfprintf(stderr, s, ap);
284 static const char *get_face_name( const struct fontinfo *info )
286 return (const char *)info->data + info->hdr.fi.dfFace - info->hdr.fi.dfBitsOffset;
289 static int lookup_charset(int enc)
291 /* FIXME: make winelib app and use TranslateCharsetInfo */
296 return RUSSIAN_CHARSET;
300 return GREEK_CHARSET;
302 return TURKISH_CHARSET;
304 return HEBREW_CHARSET;
306 return ARABIC_CHARSET;
308 return BALTIC_CHARSET;
310 return VIETNAMESE_CHARSET;
330 return SHIFTJIS_CHARSET;
332 return GB2312_CHARSET;
334 return HANGUL_CHARSET;
336 return CHINESEBIG5_CHARSET;
338 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
343 static int get_char(const union cptable *cptable, int enc, int index)
345 /* Korean has the Won sign in place of '\\' */
346 if(enc == 949 && index == '\\')
349 return cptable->sbcs.cp2uni[index];
352 static struct fontinfo *fill_fontinfo( const char *face_name, int ppem, int enc, int dpi,
353 unsigned char def_char, int avg_width )
356 int ascent = 0, il, el, width_bytes = 0, space_size, max_width = 0;
357 BYTE left_byte, right_byte, byte;
359 int i, x, y, x_off, x_end, first_char;
362 const union cptable *cptable;
363 FT_SfntName sfntname;
367 bitmapSizeTable_t *size_table;
369 struct fontinfo *info;
372 if (FT_New_Face(ft_library, face_name, 0, &face)) error( "Cannot open face %s\n", face_name );
373 if (FT_Set_Pixel_Sizes(face, ppem, ppem)) error( "cannot set face size to %u\n", ppem );
375 cptable = wine_cp_get_table(enc);
377 error("Can't find codepage %d\n", enc);
379 if(cptable->info.char_size != 1) {
380 /* for double byte charsets we actually want to use cp1252 */
381 cptable = wine_cp_get_table(1252);
383 error("Can't find codepage 1252\n");
386 assert( face->size->metrics.y_ppem == ppem );
389 if (FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
390 fprintf(stderr,"Can't find EBLC table\n");
393 eblc = malloc(needed);
394 FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
396 num_sizes = GET_BE_DWORD(&eblc->numSizes);
398 size_table = (bitmapSizeTable_t *)(eblc + 1);
399 for(i = 0; i < num_sizes; i++)
401 if( (signed char)size_table->hori.ascender - (signed char)size_table->hori.descender == ppem)
403 ascent = size_table->hori.ascender;
412 /* Versions of fontforge prior to early 2006 have incorrect
413 ascender values in the eblc table, so we won't find the
414 correct bitmapSizeTable. In this case use the height of
415 the Aring glyph instead. */
418 if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
419 error("Can't find Aring\n");
420 ascent = face->glyph->metrics.horiBearingY >> 6;
423 start = sizeof(FNT_HEADER);
425 if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
426 error("Can't find M\n");
427 il = ascent - (face->glyph->metrics.height >> 6);
429 /* Hack: Courier has no internal leading, nor do any Chinese or Japanese fonts */
430 if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950 || enc == 932)
432 /* Japanese system fonts have an external leading (not small font) */
433 if (enc == 932 && ppem > 11)
438 first_char = FT_Get_First_Char(face, &gi);
439 if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
440 first_char = 32; /* FT_Get_Next_Char for some reason returns too high
441 number in this case */
443 info = calloc( 1, sizeof(*info) );
445 info->hdr.fi.dfFirstChar = first_char;
446 info->hdr.fi.dfLastChar = 0xff;
447 start += ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar + 3 ) * sizeof(*info->dfCharTable);
449 num_names = FT_Get_Sfnt_Name_Count(face);
450 for(i = 0; i <num_names; i++) {
451 FT_Get_Sfnt_Name(face, i, &sfntname);
452 if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
453 sfntname.language_id == 0 && sfntname.name_id == 0) {
454 size_t len = min( sfntname.string_len, sizeof(info->hdr.dfCopyright)-1 );
455 memcpy(info->hdr.dfCopyright, sfntname.string, len);
456 info->hdr.dfCopyright[len] = 0;
460 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
461 for(i = first_char; i < 0x100; i++) {
462 int c = get_char(cptable, enc, i);
463 gi = FT_Get_Char_Index(face, c);
464 if(gi == 0 && !option_quiet)
465 fprintf(stderr, "warning: %s %u: missing glyph for char %04x\n",
466 face->family_name, ppem, cptable->sbcs.cp2uni[i]);
467 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
468 fprintf(stderr, "error loading char %d - bad news!\n", i);
471 info->dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
472 info->dfCharTable[i].offset = start + (width_bytes * ppem);
473 width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
474 if(max_width < (face->glyph->metrics.horiAdvance >> 6))
475 max_width = face->glyph->metrics.horiAdvance >> 6;
478 space_size = (ppem + 3) / 4;
479 info->dfCharTable[i].width = space_size;
480 info->dfCharTable[i].offset = start + (width_bytes * ppem);
481 width_bytes += (space_size + 7) >> 3;
483 info->dfCharTable[++i].width = 0;
484 info->dfCharTable[i].offset = start + (width_bytes * ppem);
486 info->hdr.fi.dfType = 0;
487 info->hdr.fi.dfPoints = ((ppem - il - el) * 72 + dpi/2) / dpi;
488 info->hdr.fi.dfVertRes = dpi;
489 info->hdr.fi.dfHorizRes = dpi;
490 info->hdr.fi.dfAscent = ascent;
491 info->hdr.fi.dfInternalLeading = il;
492 info->hdr.fi.dfExternalLeading = el;
493 info->hdr.fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
494 info->hdr.fi.dfUnderline = 0;
495 info->hdr.fi.dfStrikeOut = 0;
496 info->hdr.fi.dfWeight = os2->usWeightClass;
497 info->hdr.fi.dfCharSet = lookup_charset(enc);
498 info->hdr.fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ? avg_width : 0;
499 info->hdr.fi.dfPixHeight = ppem;
500 info->hdr.fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
501 switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
502 case PAN_FAMILY_SCRIPT:
503 info->hdr.fi.dfPitchAndFamily |= FF_SCRIPT;
505 case PAN_FAMILY_DECORATIVE:
506 case PAN_FAMILY_PICTORIAL:
507 info->hdr.fi.dfPitchAndFamily |= FF_DECORATIVE;
509 case PAN_FAMILY_TEXT_DISPLAY:
510 if(info->hdr.fi.dfPitchAndFamily == 0) /* fixed */
511 info->hdr.fi.dfPitchAndFamily = FF_MODERN;
513 switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
514 case PAN_SERIF_NORMAL_SANS:
515 case PAN_SERIF_OBTUSE_SANS:
516 case PAN_SERIF_PERP_SANS:
517 info->hdr.fi.dfPitchAndFamily |= FF_SWISS;
520 info->hdr.fi.dfPitchAndFamily |= FF_ROMAN;
525 info->hdr.fi.dfPitchAndFamily |= FF_DONTCARE;
528 info->hdr.fi.dfAvgWidth = avg_width;
529 info->hdr.fi.dfMaxWidth = max_width;
530 info->hdr.fi.dfDefaultChar = def_char - info->hdr.fi.dfFirstChar;
531 info->hdr.fi.dfBreakChar = ' ' - info->hdr.fi.dfFirstChar;
532 info->hdr.fi.dfWidthBytes = (width_bytes + 1) & ~1;
534 info->hdr.fi.dfFace = start + info->hdr.fi.dfWidthBytes * ppem;
535 info->hdr.fi.dfBitsOffset = start;
536 info->hdr.fi.dfFlags = 0x10; /* DFF_1COLOR */
537 info->hdr.fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
539 info->hdr.dfVersion = 0x300;
540 info->hdr.dfSize = start + info->hdr.fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
542 info->data = calloc( info->hdr.dfSize - start, 1 );
545 for(i = first_char; i < 0x100; i++) {
546 int c = get_char(cptable, enc, i);
547 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
550 assert(info->dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
552 for(x = 0; x < ((info->dfCharTable[i].width + 7) / 8); x++) {
553 for(y = 0; y < ppem; y++) {
554 if(y < ascent - face->glyph->bitmap_top ||
555 y >= face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
556 info->data[data_pos++] = 0;
559 x_off = face->glyph->bitmap_left / 8;
560 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
561 if(x < x_off || x > x_end) {
562 info->data[data_pos++] = 0;
568 left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
570 /* On the last non-trivial output byte (x == x_end) have we got one or two input bytes */
571 if(x == x_end && (face->glyph->bitmap_left % 8 != 0) && ((face->glyph->bitmap.width % 8 == 0) || (x != (((face->glyph->bitmap.width) & ~0x7) + face->glyph->bitmap_left) / 8)))
574 right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
576 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
577 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
578 info->data[data_pos++] = byte;
582 data_pos += ((space_size + 7) / 8) * ppem;
583 if (width_bytes & 1) data_pos += ppem;
585 memcpy( info->data + data_pos, face->family_name, strlen( face->family_name ));
586 data_pos += strlen( face->family_name ) + 1;
587 assert( start + data_pos == info->hdr.dfSize );
589 FT_Done_Face( face );
593 static void adjust_fontinfo( FONTINFO16 * fi )
595 fi->dfType = PUT_LE_WORD(fi->dfType);
596 fi->dfPoints = PUT_LE_WORD(fi->dfPoints);
597 fi->dfVertRes = PUT_LE_WORD(fi->dfVertRes);
598 fi->dfHorizRes = PUT_LE_WORD(fi->dfHorizRes);
599 fi->dfAscent = PUT_LE_WORD(fi->dfAscent);
600 fi->dfInternalLeading = PUT_LE_WORD(fi->dfInternalLeading);
601 fi->dfExternalLeading = PUT_LE_WORD(fi->dfExternalLeading);
602 fi->dfWeight = PUT_LE_WORD(fi->dfWeight);
603 fi->dfPixWidth = PUT_LE_WORD(fi->dfPixWidth);
604 fi->dfPixHeight = PUT_LE_WORD(fi->dfPixHeight);
605 fi->dfAvgWidth = PUT_LE_WORD(fi->dfAvgWidth);
606 fi->dfMaxWidth = PUT_LE_WORD(fi->dfMaxWidth);
607 fi->dfWidthBytes = PUT_LE_WORD(fi->dfWidthBytes);
608 fi->dfAspace = PUT_LE_WORD(fi->dfAspace);
609 fi->dfBspace = PUT_LE_WORD(fi->dfBspace);
610 fi->dfCspace = PUT_LE_WORD(fi->dfCspace);
611 fi->dfDevice = PUT_LE_DWORD(fi->dfDevice);
612 fi->dfFace = PUT_LE_DWORD(fi->dfFace);
613 fi->dfBitsPointer = PUT_LE_DWORD(fi->dfBitsPointer);
614 fi->dfBitsOffset = PUT_LE_DWORD(fi->dfBitsOffset);
615 fi->dfFlags = PUT_LE_DWORD(fi->dfFlags);
616 fi->dfColorPointer = PUT_LE_DWORD(fi->dfColorPointer);
619 static void write_fontinfo( const struct fontinfo *info, FILE *fp )
623 CHAR_TABLE_ENTRY tmp_chartable[258];
624 memcpy(&tmp_hdr, &info->hdr, sizeof(info->hdr));
625 tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
626 tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
627 adjust_fontinfo(&(tmp_hdr.fi));
628 fwrite( &tmp_hdr, sizeof(info->hdr), 1, fp );
629 num_chars = ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar) + 3;
631 memcpy(&tmp_chartable, info->dfCharTable + info->hdr.fi.dfFirstChar, num_chars * sizeof(CHAR_TABLE_ENTRY));
632 for (i=0; i < num_chars; ++i) {
633 tmp_chartable[i].width = PUT_LE_WORD(tmp_chartable[i].width);
634 tmp_chartable[i].offset = PUT_LE_DWORD(tmp_chartable[i].offset);
636 fwrite( tmp_chartable, sizeof(CHAR_TABLE_ENTRY), num_chars, fp );
637 fwrite( info->data, info->hdr.dfSize - info->hdr.fi.dfBitsOffset, 1, fp );
640 /* parse options from the argv array and remove all the recognized ones */
641 static char **parse_options( int argc, char **argv )
645 while ((optc = getopt( argc, argv, "d:ho:qr:s" )) != -1)
650 option_defchar = atoi( optarg );
653 option_output = strdup( optarg );
659 option_dpi = atoi( optarg );
672 return &argv[optind];
675 int main(int argc, char **argv)
679 short align, num_files;
680 int resource_table_len, non_resident_name_len, resident_name_len;
681 unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, font_off;
682 char resident_name[200];
684 char non_resident_name[200];
685 unsigned short first_res = 0x0050, pad, res;
686 IMAGE_OS2_HEADER NE_hdr;
689 struct fontinfo **info;
694 args = parse_options( argc, argv );
696 input_file = *args++;
697 if (!input_file || !*args)
703 if(FT_Init_FreeType(&ft_library))
704 error("ft init failure\n");
706 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
707 FT_Library_Version(ft_library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
710 while (args[num_files]) num_files++;
712 if (option_fnt_mode && num_files > 1)
713 error( "can only specify one font in .fnt mode\n" );
715 info = malloc( num_files * sizeof(*info) );
716 for (i = 0; i < num_files; i++)
718 int ppem, enc, avg_width;
721 if (sscanf( args[i], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
726 if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
729 name = get_face_name( info[i] );
730 fontdir_len += 0x74 + strlen(name) + 1;
732 sprintf(non_resident_name, "FONTRES 100,%d,%d : %s %d",
733 info[i]->hdr.fi.dfVertRes, info[i]->hdr.fi.dfHorizRes,
734 name, info[i]->hdr.fi.dfPoints );
735 strcpy(resident_name, name);
737 sprintf(non_resident_name + strlen(non_resident_name), ",%d", info[i]->hdr.fi.dfPoints );
741 if (option_dpi <= 108)
742 strcat(non_resident_name, " (VGA res)");
744 strcat(non_resident_name, " (8514 res)");
745 non_resident_name_len = strlen(non_resident_name) + 4;
747 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
748 resource_table_len = sizeof(align) + sizeof("FONTDIR") +
749 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) +
750 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) * num_files +
752 resource_table_off = sizeof(NE_hdr);
753 resident_name_off = resource_table_off + resource_table_len;
754 resident_name_len = strlen(resident_name) + 4;
755 module_ref_off = resident_name_off + resident_name_len;
756 non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(align);
758 memset(&NE_hdr, 0, sizeof(NE_hdr));
759 NE_hdr.ne_magic = PUT_LE_WORD(0x454e);
762 NE_hdr.ne_flags = PUT_LE_WORD(NE_FFLAGS_LIBMODULE | NE_FFLAGS_GUI);
763 NE_hdr.ne_cbnrestab = PUT_LE_WORD(non_resident_name_len);
764 NE_hdr.ne_segtab = PUT_LE_WORD(sizeof(NE_hdr));
765 NE_hdr.ne_rsrctab = PUT_LE_WORD(sizeof(NE_hdr));
766 NE_hdr.ne_restab = PUT_LE_WORD(resident_name_off);
767 NE_hdr.ne_modtab = PUT_LE_WORD(module_ref_off);
768 NE_hdr.ne_imptab = PUT_LE_WORD(module_ref_off);
769 NE_hdr.ne_enttab = NE_hdr.ne_modtab;
770 NE_hdr.ne_nrestab = PUT_LE_DWORD(non_resident_name_off);
771 NE_hdr.ne_align = PUT_LE_WORD(4);
772 NE_hdr.ne_exetyp = NE_OSFLAGS_WINDOWS;
773 NE_hdr.ne_expver = PUT_LE_WORD(0x400);
775 fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
776 font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
779 signal( SIGTERM, exit_on_signal );
780 signal( SIGINT, exit_on_signal );
782 signal( SIGHUP, exit_on_signal );
785 if (!option_output) /* build a default output name */
787 char *p = strrchr( input_file, '/' );
790 option_output = malloc( strlen(p) + sizeof(".fon") );
791 strcpy( option_output, p );
792 p = strrchr( option_output, '.' );
793 if (!p) p = option_output + strlen(option_output);
794 strcpy( p, option_fnt_mode ? ".fnt" : ".fon" );
797 if (!(ofp = fopen(option_output, "wb")))
799 perror( option_output );
802 output_name = option_output;
805 write_fontinfo( info[0], ofp );
809 fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
810 fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
812 align = PUT_LE_WORD(4);
813 fwrite(&align, sizeof(align), 1, ofp);
815 rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONTDIR);
816 rc_type.count = PUT_LE_WORD(1);
817 rc_type.resloader = 0;
818 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
820 rc_name.offset = PUT_LE_WORD(fontdir_off >> 4);
821 rc_name.length = PUT_LE_WORD((fontdir_len + 15) >> 4);
822 rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD);
823 rc_name.id = PUT_LE_WORD(resident_name_off - sizeof("FONTDIR") - sizeof(NE_hdr));
826 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
828 rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONT);
829 rc_type.count = PUT_LE_WORD(num_files);
830 rc_type.resloader = 0;
831 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
833 for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
834 int len = (info[i]->hdr.dfSize + 15) & ~0xf;
836 rc_name.offset = PUT_LE_WORD(font_off >> 4);
837 rc_name.length = PUT_LE_WORD(len >> 4);
838 rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_SHAREABLE | NE_SEGFLAGS_DISCARDABLE);
839 rc_name.id = PUT_LE_WORD(res);
842 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
847 /* empty type info */
848 memset(&rc_type, 0, sizeof(rc_type));
849 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
851 fputc(strlen("FONTDIR"), ofp);
852 fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp);
853 fputc(strlen(resident_name), ofp);
854 fwrite(resident_name, strlen(resident_name), 1, ofp);
856 fputc(0x00, ofp); fputc(0x00, ofp);
858 fputc(0x00, ofp); fputc(0x00, ofp);
860 fputc(strlen(non_resident_name), ofp);
861 fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
862 fputc(0x00, ofp); /* terminator */
864 /* empty ne_modtab and ne_imptab */
868 pad = ftell(ofp) & 0xf;
871 for(i = 0; i < pad; i++)
874 /* FONTDIR resource */
875 tmp16 = PUT_LE_WORD(num_files);
876 fwrite(&tmp16, sizeof(tmp16), 1, ofp);
878 for(res = first_res, i = 0; i < num_files; i++, res++) {
881 const char *name = get_face_name( info[i] );
882 tmp16 = PUT_LE_WORD(res);
883 fwrite(&tmp16, sizeof(tmp16), 1, ofp);
884 sz = FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset);
885 memcpy(&tmp_hdr, &info[i]->hdr, sz);
886 tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
887 tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
888 adjust_fontinfo(&(tmp_hdr.fi));
889 fwrite(&tmp_hdr, FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset), 1, ofp);
891 fwrite(name, strlen(name) + 1, 1, ofp);
894 pad = ftell(ofp) & 0xf;
897 for(i = 0; i < pad; i++)
900 for(res = first_res, i = 0; i < num_files; i++, res++) {
901 write_fontinfo( info[i], ofp );
902 pad = info[i]->hdr.dfSize & 0xf;
905 for(j = 0; j < pad; j++)
914 #else /* HAVE_FREETYPE */
916 int main(int argc, char **argv)
918 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
922 #endif /* HAVE_FREETYPE */