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
43 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
44 #include <freetype/internal/sfnt.h>
47 #include "wine/unicode.h"
59 INT16 dfInternalLeading;
60 INT16 dfExternalLeading;
68 BYTE dfPitchAndFamily;
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
159 CHAR caretSlopeNumerator;
160 CHAR caretSlopeDenominator;
171 ULONG indexSubTableArrayOffset;
172 ULONG indexTableSize;
173 ULONG numberOfIndexSubTables;
175 sbitLineMetrics_t hori;
176 sbitLineMetrics_t vert;
177 USHORT startGlyphIndex;
178 USHORT endGlyphIndex;
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]) ))
202 CHAR_TABLE_ENTRY dfCharTable[258];
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" );
241 #define __attribute__(X)
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, ...)
261 fprintf(stderr, "Error: ");
262 vfprintf(stderr, s, ap);
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 */
279 return RUSSIAN_CHARSET;
283 return GREEK_CHARSET;
285 return TURKISH_CHARSET;
287 return HEBREW_CHARSET;
289 return ARABIC_CHARSET;
291 return BALTIC_CHARSET;
293 return VIETNAMESE_CHARSET;
313 return SHIFTJIS_CHARSET;
315 return GB2312_CHARSET;
317 return HANGUL_CHARSET;
319 return CHINESEBIG5_CHARSET;
321 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
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 == '\\')
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)
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)
350 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
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);
359 err = FT_Err_Unimplemented_Feature;
364 static struct fontinfo *fill_fontinfo( const char *face_name, int ppem, int enc, int dpi,
365 unsigned char def_char, int avg_width )
368 int ascent = 0, il, el, width_bytes = 0, space_size, max_width = 0;
369 BYTE left_byte, right_byte, byte;
371 int i, x, y, x_off, x_end, first_char;
374 const union cptable *cptable;
375 FT_SfntName sfntname;
379 bitmapSizeTable_t *size_table;
381 struct fontinfo *info;
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);
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);
395 error("Can't find codepage 1252\n");
398 assert( face->size->metrics.y_ppem == ppem );
401 if (load_sfnt_table(face, TTAG_EBLC, 0, NULL, &needed))
402 fprintf(stderr,"Can't find EBLC table\n");
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;
424 /* Versions of fontforge prior to early 2006 have incorrect
425 ascender values in the eblc table, so we won't find the
426 correct bitmapSizeTable. In this case use the height of
427 the Aring glyph instead. */
430 if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
431 error("Can't find Aring\n");
432 ascent = face->glyph->metrics.horiBearingY >> 6;
435 start = sizeof(FNT_HEADER);
437 if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
438 error("Can't find M\n");
439 il = ascent - (face->glyph->metrics.height >> 6);
441 /* Hack: Courier has no internal leading, nor do any Chinese or Japanese fonts */
442 if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950 || enc == 932)
444 /* Japanese system fonts have an external leading (not small font) */
445 if (enc == 932 && ppem > 11)
450 first_char = FT_Get_First_Char(face, &gi);
451 if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
452 first_char = 32; /* FT_Get_Next_Char for some reason returns too high
453 number in this case */
455 info = calloc( 1, sizeof(*info) );
457 info->hdr.fi.dfFirstChar = first_char;
458 info->hdr.fi.dfLastChar = 0xff;
459 start += ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar + 3 ) * sizeof(*info->dfCharTable);
461 num_names = FT_Get_Sfnt_Name_Count(face);
462 for(i = 0; i <num_names; i++) {
463 FT_Get_Sfnt_Name(face, i, &sfntname);
464 if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
465 sfntname.language_id == 0 && sfntname.name_id == 0) {
466 size_t len = min( sfntname.string_len, sizeof(info->hdr.dfCopyright)-1 );
467 memcpy(info->hdr.dfCopyright, sfntname.string, len);
468 info->hdr.dfCopyright[len] = 0;
472 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
473 for(i = first_char; i < 0x100; i++) {
474 int c = get_char(cptable, enc, i);
475 gi = FT_Get_Char_Index(face, c);
476 if(gi == 0 && !option_quiet)
477 fprintf(stderr, "warning: %s %u: missing glyph for char %04x\n",
478 face->family_name, ppem, cptable->sbcs.cp2uni[i]);
479 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
480 fprintf(stderr, "error loading char %d - bad news!\n", i);
483 info->dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
484 info->dfCharTable[i].offset = start + (width_bytes * ppem);
485 width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
486 if(max_width < (face->glyph->metrics.horiAdvance >> 6))
487 max_width = face->glyph->metrics.horiAdvance >> 6;
490 space_size = (ppem + 3) / 4;
491 info->dfCharTable[i].width = space_size;
492 info->dfCharTable[i].offset = start + (width_bytes * ppem);
493 width_bytes += (space_size + 7) >> 3;
495 info->dfCharTable[++i].width = 0;
496 info->dfCharTable[i].offset = start + (width_bytes * ppem);
498 info->hdr.fi.dfType = 0;
499 info->hdr.fi.dfPoints = ((ppem - il - el) * 72 + dpi/2) / dpi;
500 info->hdr.fi.dfVertRes = dpi;
501 info->hdr.fi.dfHorizRes = dpi;
502 info->hdr.fi.dfAscent = ascent;
503 info->hdr.fi.dfInternalLeading = il;
504 info->hdr.fi.dfExternalLeading = el;
505 info->hdr.fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
506 info->hdr.fi.dfUnderline = 0;
507 info->hdr.fi.dfStrikeOut = 0;
508 info->hdr.fi.dfWeight = os2->usWeightClass;
509 info->hdr.fi.dfCharSet = lookup_charset(enc);
510 info->hdr.fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ? avg_width : 0;
511 info->hdr.fi.dfPixHeight = ppem;
512 info->hdr.fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
513 switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
514 case PAN_FAMILY_SCRIPT:
515 info->hdr.fi.dfPitchAndFamily |= FF_SCRIPT;
517 case PAN_FAMILY_DECORATIVE:
518 case PAN_FAMILY_PICTORIAL:
519 info->hdr.fi.dfPitchAndFamily |= FF_DECORATIVE;
521 case PAN_FAMILY_TEXT_DISPLAY:
522 if(info->hdr.fi.dfPitchAndFamily == 0) /* fixed */
523 info->hdr.fi.dfPitchAndFamily = FF_MODERN;
525 switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
526 case PAN_SERIF_NORMAL_SANS:
527 case PAN_SERIF_OBTUSE_SANS:
528 case PAN_SERIF_PERP_SANS:
529 info->hdr.fi.dfPitchAndFamily |= FF_SWISS;
532 info->hdr.fi.dfPitchAndFamily |= FF_ROMAN;
537 info->hdr.fi.dfPitchAndFamily |= FF_DONTCARE;
540 info->hdr.fi.dfAvgWidth = avg_width;
541 info->hdr.fi.dfMaxWidth = max_width;
542 info->hdr.fi.dfDefaultChar = def_char - info->hdr.fi.dfFirstChar;
543 info->hdr.fi.dfBreakChar = ' ' - info->hdr.fi.dfFirstChar;
544 info->hdr.fi.dfWidthBytes = (width_bytes + 1) & ~1;
546 info->hdr.fi.dfFace = start + info->hdr.fi.dfWidthBytes * ppem;
547 info->hdr.fi.dfBitsOffset = start;
548 info->hdr.fi.dfFlags = 0x10; /* DFF_1COLOR */
549 info->hdr.fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
551 info->hdr.dfVersion = 0x300;
552 info->hdr.dfSize = start + info->hdr.fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
554 info->data = calloc( info->hdr.dfSize - start, 1 );
557 for(i = first_char; i < 0x100; i++) {
558 int c = get_char(cptable, enc, i);
559 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
562 assert(info->dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
564 for(x = 0; x < ((info->dfCharTable[i].width + 7) / 8); x++) {
565 for(y = 0; y < ppem; y++) {
566 if(y < ascent - face->glyph->bitmap_top ||
567 y >= face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
568 info->data[data_pos++] = 0;
571 x_off = face->glyph->bitmap_left / 8;
572 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
573 if(x < x_off || x > x_end) {
574 info->data[data_pos++] = 0;
580 left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
582 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
583 if(x == x_end && (face->glyph->bitmap_left % 8 != 0) && ((face->glyph->bitmap.width % 8 == 0) || (x != (((face->glyph->bitmap.width) & ~0x7) + face->glyph->bitmap_left) / 8)))
586 right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
588 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
589 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
590 info->data[data_pos++] = byte;
594 data_pos += ((space_size + 7) / 8) * ppem;
595 if (width_bytes & 1) data_pos += ppem;
597 memcpy( info->data + data_pos, face->family_name, strlen( face->family_name ));
598 data_pos += strlen( face->family_name ) + 1;
599 assert( start + data_pos == info->hdr.dfSize );
601 FT_Done_Face( face );
605 static void write_fontinfo( const struct fontinfo *info, FILE *fp )
607 fwrite( &info->hdr, sizeof(info->hdr), 1, fp );
608 fwrite( info->dfCharTable + info->hdr.fi.dfFirstChar, sizeof(*info->dfCharTable),
609 ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar) + 3, fp );
610 fwrite( info->data, info->hdr.dfSize - info->hdr.fi.dfBitsOffset, 1, fp );
613 /* parse options from the argv array and remove all the recognized ones */
614 static char **parse_options( int argc, char **argv )
618 while ((optc = getopt( argc, argv, "d:ho:qr:s" )) != -1)
623 option_defchar = atoi( optarg );
626 option_output = strdup( optarg );
632 option_dpi = atoi( optarg );
645 return &argv[optind];
648 int main(int argc, char **argv)
652 short align, num_files;
653 int resource_table_len, non_resident_name_len, resident_name_len;
654 unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, font_off;
655 char resident_name[200];
657 char non_resident_name[200];
658 unsigned short first_res = 0x0050, pad, res;
659 IMAGE_OS2_HEADER NE_hdr;
662 struct fontinfo **info;
666 args = parse_options( argc, argv );
668 input_file = *args++;
669 if (!input_file || !*args)
675 if(FT_Init_FreeType(&ft_library))
676 error("ft init failure\n");
678 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
679 FT_Library_Version(ft_library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
682 while (args[num_files]) num_files++;
684 if (option_fnt_mode && num_files > 1)
685 error( "can only specify one font in .fnt mode\n" );
687 info = malloc( num_files * sizeof(*info) );
688 for (i = 0; i < num_files; i++)
690 int ppem, enc, avg_width;
693 if (sscanf( args[i], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
698 if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
701 name = get_face_name( info[i] );
702 fontdir_len += 0x74 + strlen(name) + 1;
704 sprintf(non_resident_name, "FONTRES 100,%d,%d : %s %d",
705 info[i]->hdr.fi.dfVertRes, info[i]->hdr.fi.dfHorizRes,
706 name, info[i]->hdr.fi.dfPoints );
707 strcpy(resident_name, name);
709 sprintf(non_resident_name + strlen(non_resident_name), ",%d", info[i]->hdr.fi.dfPoints );
713 if (option_dpi <= 108)
714 strcat(non_resident_name, " (VGA res)");
716 strcat(non_resident_name, " (8514 res)");
717 non_resident_name_len = strlen(non_resident_name) + 4;
719 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
720 resource_table_len = sizeof(align) + sizeof("FONTDIR") +
721 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) +
722 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) * num_files +
724 resource_table_off = sizeof(NE_hdr);
725 resident_name_off = resource_table_off + resource_table_len;
726 resident_name_len = strlen(resident_name) + 4;
727 module_ref_off = resident_name_off + resident_name_len;
728 non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(align);
730 memset(&NE_hdr, 0, sizeof(NE_hdr));
731 NE_hdr.ne_magic = 0x454e;
734 NE_hdr.ne_flags = NE_FFLAGS_LIBMODULE | NE_FFLAGS_GUI;
735 NE_hdr.ne_cbnrestab = non_resident_name_len;
736 NE_hdr.ne_segtab = sizeof(NE_hdr);
737 NE_hdr.ne_rsrctab = sizeof(NE_hdr);
738 NE_hdr.ne_restab = resident_name_off;
739 NE_hdr.ne_modtab = module_ref_off;
740 NE_hdr.ne_imptab = module_ref_off;
741 NE_hdr.ne_enttab = NE_hdr.ne_modtab;
742 NE_hdr.ne_nrestab = non_resident_name_off;
744 NE_hdr.ne_exetyp = NE_OSFLAGS_WINDOWS;
745 NE_hdr.ne_expver = 0x400;
747 fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
748 font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
751 signal( SIGTERM, exit_on_signal );
752 signal( SIGINT, exit_on_signal );
754 signal( SIGHUP, exit_on_signal );
757 if (!option_output) /* build a default output name */
759 char *p = strrchr( input_file, '/' );
762 option_output = malloc( strlen(p) + sizeof(".fon") );
763 strcpy( option_output, p );
764 p = strrchr( option_output, '.' );
765 if (!p) p = option_output + strlen(option_output);
766 strcpy( p, option_fnt_mode ? ".fnt" : ".fon" );
769 if (!(ofp = fopen(option_output, "wb")))
771 perror( option_output );
774 output_name = option_output;
777 write_fontinfo( info[0], ofp );
781 fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
782 fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
785 fwrite(&align, sizeof(align), 1, ofp);
787 rc_type.type_id = NE_RSCTYPE_FONTDIR;
789 rc_type.resloader = 0;
790 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
792 rc_name.offset = fontdir_off >> 4;
793 rc_name.length = (fontdir_len + 15) >> 4;
794 rc_name.flags = NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD;
795 rc_name.id = resident_name_off - sizeof("FONTDIR") - NE_hdr.ne_rsrctab;
798 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
800 rc_type.type_id = NE_RSCTYPE_FONT;
801 rc_type.count = num_files;
802 rc_type.resloader = 0;
803 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
805 for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
806 int len = (info[i]->hdr.dfSize + 15) & ~0xf;
808 rc_name.offset = font_off >> 4;
809 rc_name.length = len >> 4;
810 rc_name.flags = NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_SHAREABLE | NE_SEGFLAGS_DISCARDABLE;
814 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
819 /* empty type info */
820 memset(&rc_type, 0, sizeof(rc_type));
821 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
823 fputc(strlen("FONTDIR"), ofp);
824 fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp);
825 fputc(strlen(resident_name), ofp);
826 fwrite(resident_name, strlen(resident_name), 1, ofp);
828 fputc(0x00, ofp); fputc(0x00, ofp);
830 fputc(0x00, ofp); fputc(0x00, ofp);
832 fputc(strlen(non_resident_name), ofp);
833 fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
834 fputc(0x00, ofp); /* terminator */
836 /* empty ne_modtab and ne_imptab */
840 pad = ftell(ofp) & 0xf;
843 for(i = 0; i < pad; i++)
846 /* FONTDIR resource */
847 fwrite(&num_files, sizeof(num_files), 1, ofp);
849 for(res = first_res, i = 0; i < num_files; i++, res++) {
850 const char *name = get_face_name( info[i] );
851 fwrite(&res, sizeof(res), 1, ofp);
852 fwrite(&info[i]->hdr, FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset), 1, ofp);
854 fwrite(name, strlen(name) + 1, 1, ofp);
857 pad = ftell(ofp) & 0xf;
860 for(i = 0; i < pad; i++)
863 for(res = first_res, i = 0; i < num_files; i++, res++) {
864 write_fontinfo( info[i], ofp );
865 pad = info[i]->hdr.dfSize & 0xf;
868 for(j = 0; j < pad; j++)
877 #else /* HAVE_FREETYPE */
879 int main(int argc, char **argv)
881 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
885 #endif /* HAVE_FREETYPE */