msi: Introduce msi_record_stream_name helper.
[wine.git] / tools / sfnt2fon / sfnt2fon.c
blob0d59bfc1db25ba499f426b584afd1ea02332e909
1 /*
2 * sfnt2fon. Bitmap-only ttf to Windows font 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
44 #include "windef.h"
45 #include "winbase.h"
46 #include "wingdi.h"
47 #include "basetsd.h"
49 #include "pshpack1.h"
51 typedef struct
53 INT16 dfType;
54 INT16 dfPoints;
55 INT16 dfVertRes;
56 INT16 dfHorizRes;
57 INT16 dfAscent;
58 INT16 dfInternalLeading;
59 INT16 dfExternalLeading;
60 BYTE dfItalic;
61 BYTE dfUnderline;
62 BYTE dfStrikeOut;
63 INT16 dfWeight;
64 BYTE dfCharSet;
65 INT16 dfPixWidth;
66 INT16 dfPixHeight;
67 BYTE dfPitchAndFamily;
68 INT16 dfAvgWidth;
69 INT16 dfMaxWidth;
70 BYTE dfFirstChar;
71 BYTE dfLastChar;
72 BYTE dfDefaultChar;
73 BYTE dfBreakChar;
74 INT16 dfWidthBytes;
75 LONG dfDevice;
76 LONG dfFace;
77 LONG dfBitsPointer;
78 LONG dfBitsOffset;
79 BYTE dfReserved;
80 LONG dfFlags;
81 INT16 dfAspace;
82 INT16 dfBspace;
83 INT16 dfCspace;
84 LONG dfColorPointer;
85 LONG dfReserved1[4];
86 } FONTINFO16;
88 typedef struct
90 WORD dfVersion;
91 DWORD dfSize;
92 char dfCopyright[60];
93 FONTINFO16 fi;
94 } FNT_HEADER;
96 typedef struct
98 WORD offset;
99 WORD length;
100 WORD flags;
101 WORD id;
102 WORD handle;
103 WORD usage;
104 } NE_NAMEINFO;
106 typedef struct
108 WORD type_id;
109 WORD count;
110 DWORD resloader;
111 } NE_TYPEINFO;
113 #define NE_FFLAGS_SINGLEDATA 0x0001
114 #define NE_FFLAGS_MULTIPLEDATA 0x0002
115 #define NE_FFLAGS_WIN32 0x0010
116 #define NE_FFLAGS_FRAMEBUF 0x0100
117 #define NE_FFLAGS_CONSOLE 0x0200
118 #define NE_FFLAGS_GUI 0x0300
119 #define NE_FFLAGS_SELFLOAD 0x0800
120 #define NE_FFLAGS_LINKERROR 0x2000
121 #define NE_FFLAGS_CALLWEP 0x4000
122 #define NE_FFLAGS_LIBMODULE 0x8000
124 #define NE_OSFLAGS_WINDOWS 0x02
126 #define NE_RSCTYPE_FONTDIR 0x8007
127 #define NE_RSCTYPE_FONT 0x8008
128 #define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
130 #define NE_SEGFLAGS_DATA 0x0001
131 #define NE_SEGFLAGS_ALLOCATED 0x0002
132 #define NE_SEGFLAGS_LOADED 0x0004
133 #define NE_SEGFLAGS_ITERATED 0x0008
134 #define NE_SEGFLAGS_MOVEABLE 0x0010
135 #define NE_SEGFLAGS_SHAREABLE 0x0020
136 #define NE_SEGFLAGS_PRELOAD 0x0040
137 #define NE_SEGFLAGS_EXECUTEONLY 0x0080
138 #define NE_SEGFLAGS_READONLY 0x0080
139 #define NE_SEGFLAGS_RELOC_DATA 0x0100
140 #define NE_SEGFLAGS_SELFLOAD 0x0800
141 #define NE_SEGFLAGS_DISCARDABLE 0x1000
142 #define NE_SEGFLAGS_32BIT 0x2000
144 typedef struct {
145 WORD width;
146 DWORD offset;
147 } CHAR_TABLE_ENTRY;
149 typedef struct {
150 DWORD version;
151 ULONG numSizes;
152 } eblcHeader_t;
154 typedef struct {
155 CHAR ascender;
156 CHAR descender;
157 BYTE widthMax;
158 CHAR caretSlopeNumerator;
159 CHAR caretSlopeDenominator;
160 CHAR caretOffset;
161 CHAR minOriginSB;
162 CHAR minAdvanceSB;
163 CHAR maxBeforeBL;
164 CHAR maxAfterBL;
165 CHAR pad1;
166 CHAR pad2;
167 } sbitLineMetrics_t;
169 typedef struct {
170 ULONG indexSubTableArrayOffset;
171 ULONG indexTableSize;
172 ULONG numberOfIndexSubTables;
173 ULONG colorRef;
174 sbitLineMetrics_t hori;
175 sbitLineMetrics_t vert;
176 USHORT startGlyphIndex;
177 USHORT endGlyphIndex;
178 BYTE ppemX;
179 BYTE ppemY;
180 BYTE bitDepth;
181 CHAR flags;
182 } bitmapSizeTable_t;
184 typedef struct
186 FT_Int major;
187 FT_Int minor;
188 FT_Int patch;
189 } FT_Version_t;
190 static FT_Version_t FT_Version;
192 #include "poppack.h"
194 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
195 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
196 GET_BE_WORD(&((WORD *)(ptr))[0]) ))
197 #ifdef WORDS_BIGENDIAN
198 static WORD byteswap_word(WORD x)
200 return ( ( (x & 0xff) << 8) |
201 ( (x & 0xff00) >> 8) );
203 static DWORD byteswap_dword(DWORD x)
205 return ( ( (x & 0xff) << 24) |
206 ( (x & 0xff00) << 8) |
207 ( (x & 0xff0000) >> 8) |
208 ( (x & 0xff000000) >> 24) );
210 # define PUT_LE_WORD(x) byteswap_word(x)
211 # define PUT_LE_DWORD(x) byteswap_dword(x)
212 #else
213 # define PUT_LE_WORD(x) (x)
214 # define PUT_LE_DWORD(x) (x)
215 #endif
217 struct fontinfo
219 FNT_HEADER hdr;
220 CHAR_TABLE_ENTRY dfCharTable[258];
221 BYTE *data;
224 static const BYTE MZ_hdr[] =
226 'M', 'Z', 0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
227 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
230 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
231 'i', 's', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n', 'n', 'o',
232 't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O', 'S', ' ',
233 'm', 'o', 'd', 'e', 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
236 static const WCHAR encoding_1250[128] =
238 0x20ac, 0x0081, 0x201a, 0x0083, 0x201e, 0x2026, 0x2020, 0x2021,
239 0x0088, 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
240 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
241 0x0098, 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
242 0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7,
243 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
244 0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
245 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
246 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
247 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
248 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
249 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
250 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
251 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
252 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
253 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9
256 static const WCHAR encoding_1251[128] =
258 0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, 0x2021,
259 0x20ac, 0x2030, 0x0409, 0x2039, 0x040a, 0x040c, 0x040b, 0x040f,
260 0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
261 0x0098, 0x2122, 0x0459, 0x203a, 0x045a, 0x045c, 0x045b, 0x045f,
262 0x00a0, 0x040e, 0x045e, 0x0408, 0x00a4, 0x0490, 0x00a6, 0x00a7,
263 0x0401, 0x00a9, 0x0404, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0407,
264 0x00b0, 0x00b1, 0x0406, 0x0456, 0x0491, 0x00b5, 0x00b6, 0x00b7,
265 0x0451, 0x2116, 0x0454, 0x00bb, 0x0458, 0x0405, 0x0455, 0x0457,
266 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
267 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
268 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
269 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
270 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
271 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
272 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
273 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f
276 static const WCHAR encoding_1252[128] =
278 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
279 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
280 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
281 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178,
282 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
283 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
284 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
285 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
286 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
287 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
288 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
289 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
290 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
291 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
292 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
293 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
296 static const WCHAR encoding_1253[128] =
298 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
299 0x0088, 0x2030, 0x008a, 0x2039, 0x008c, 0x008d, 0x008e, 0x008f,
300 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
301 0x0098, 0x2122, 0x009a, 0x203a, 0x009c, 0x009d, 0x009e, 0x009f,
302 0x00a0, 0x0385, 0x0386, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
303 0x00a8, 0x00a9, 0xf8f9, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x2015,
304 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x0384, 0x00b5, 0x00b6, 0x00b7,
305 0x0388, 0x0389, 0x038a, 0x00bb, 0x038c, 0x00bd, 0x038e, 0x038f,
306 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
307 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
308 0x03a0, 0x03a1, 0xf8fa, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
309 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,
310 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
311 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
312 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
313 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0xf8fb
316 static const WCHAR encoding_1254[128] =
318 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
319 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x008e, 0x008f,
320 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
321 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x009e, 0x0178,
322 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
323 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
324 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
325 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
326 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
327 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
328 0x011e, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
329 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x0130, 0x015e, 0x00df,
330 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
331 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
332 0x011f, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
333 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x0131, 0x015f, 0x00ff
336 static const WCHAR encoding_1255[128] =
338 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
339 0x02c6, 0x2030, 0x008a, 0x2039, 0x008c, 0x008d, 0x008e, 0x008f,
340 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
341 0x02dc, 0x2122, 0x009a, 0x203a, 0x009c, 0x009d, 0x009e, 0x009f,
342 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20aa, 0x00a5, 0x00a6, 0x00a7,
343 0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
344 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
345 0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
346 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7,
347 0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf,
348 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05f0, 0x05f1, 0x05f2, 0x05f3,
349 0x05f4, 0xf88d, 0xf88e, 0xf88f, 0xf890, 0xf891, 0xf892, 0xf893,
350 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
351 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
352 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
353 0x05e8, 0x05e9, 0x05ea, 0xf894, 0xf895, 0x200e, 0x200f, 0xf896
356 static const WCHAR encoding_1256[128] =
358 0x20ac, 0x067e, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
359 0x02c6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
360 0x06af, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
361 0x06a9, 0x2122, 0x0691, 0x203a, 0x0153, 0x200c, 0x200d, 0x06ba,
362 0x00a0, 0x060c, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
363 0x00a8, 0x00a9, 0x06be, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
364 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
365 0x00b8, 0x00b9, 0x061b, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x061f,
366 0x06c1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
367 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f,
368 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00d7,
369 0x0637, 0x0638, 0x0639, 0x063a, 0x0640, 0x0641, 0x0642, 0x0643,
370 0x00e0, 0x0644, 0x00e2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00e7,
371 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x0649, 0x064a, 0x00ee, 0x00ef,
372 0x064b, 0x064c, 0x064d, 0x064e, 0x00f4, 0x064f, 0x0650, 0x00f7,
373 0x0651, 0x00f9, 0x0652, 0x00fb, 0x00fc, 0x200e, 0x200f, 0x06d2
376 static const WCHAR encoding_1257[128] =
378 0x20ac, 0x0081, 0x201a, 0x0083, 0x201e, 0x2026, 0x2020, 0x2021,
379 0x0088, 0x2030, 0x008a, 0x2039, 0x008c, 0x00a8, 0x02c7, 0x00b8,
380 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
381 0x0098, 0x2122, 0x009a, 0x203a, 0x009c, 0x00af, 0x02db, 0x009f,
382 0x00a0, 0xf8fc, 0x00a2, 0x00a3, 0x00a4, 0xf8fd, 0x00a6, 0x00a7,
383 0x00d8, 0x00a9, 0x0156, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00c6,
384 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
385 0x00f8, 0x00b9, 0x0157, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00e6,
386 0x0104, 0x012e, 0x0100, 0x0106, 0x00c4, 0x00c5, 0x0118, 0x0112,
387 0x010c, 0x00c9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012a, 0x013b,
388 0x0160, 0x0143, 0x0145, 0x00d3, 0x014c, 0x00d5, 0x00d6, 0x00d7,
389 0x0172, 0x0141, 0x015a, 0x016a, 0x00dc, 0x017b, 0x017d, 0x00df,
390 0x0105, 0x012f, 0x0101, 0x0107, 0x00e4, 0x00e5, 0x0119, 0x0113,
391 0x010d, 0x00e9, 0x017a, 0x0117, 0x0123, 0x0137, 0x012b, 0x013c,
392 0x0161, 0x0144, 0x0146, 0x00f3, 0x014d, 0x00f5, 0x00f6, 0x00f7,
393 0x0173, 0x0142, 0x015b, 0x016b, 0x00fc, 0x017c, 0x017e, 0x02d9
396 static const WCHAR encoding_874[128] =
398 0x20ac, 0x0081, 0x0082, 0x0083, 0x0084, 0x2026, 0x0086, 0x0087,
399 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
400 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
401 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
402 0x00a0, 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07,
403 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f,
404 0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17,
405 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f,
406 0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27,
407 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f,
408 0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37,
409 0x0e38, 0x0e39, 0x0e3a, 0xf8c1, 0xf8c2, 0xf8c3, 0xf8c4, 0x0e3f,
410 0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47,
411 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0e4e, 0x0e4f,
412 0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57,
413 0x0e58, 0x0e59, 0x0e5a, 0x0e5b, 0xf8c5, 0xf8c6, 0xf8c7, 0xf8c8
416 static const struct { int codepage; const WCHAR *table; } encodings[] =
418 { 874, encoding_874 },
419 { 1250, encoding_1250 },
420 { 1251, encoding_1251 },
421 { 1252, encoding_1252 },
422 { 1253, encoding_1253 },
423 { 1254, encoding_1254 },
424 { 1255, encoding_1255 },
425 { 1256, encoding_1256 },
426 { 1257, encoding_1257 },
427 { 0, encoding_1252 }, /* default encoding */
430 static char *option_output;
431 static int option_defchar = ' ';
432 static int option_dpi = 96;
433 static int option_fnt_mode = 0;
434 static int option_quiet = 0;
436 static const char *output_name;
438 static FT_Library ft_library;
440 static void usage(char **argv)
442 fprintf(stderr, "%s [options] input.ttf ppem,enc,avg_width ...\n", argv[0]);
443 fprintf(stderr, "Options:\n");
444 fprintf(stderr, " -h Display help\n" );
445 fprintf(stderr, " -d char Set the font default char\n" );
446 fprintf(stderr, " -o file Set output file name\n" );
447 fprintf(stderr, " -q Quiet mode\n" );
448 fprintf(stderr, " -r dpi Set resolution in DPI (default: 96)\n" );
449 fprintf(stderr, " -s Single .fnt file mode\n" );
452 #ifndef __GNUC__
453 #define __attribute__(X)
454 #endif
456 /* atexit handler to cleanup files */
457 static void cleanup(void)
459 if (output_name) unlink( output_name );
462 static void exit_on_signal( int sig )
464 exit(1); /* this will call the atexit functions */
467 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
469 static void error(const char *s, ...)
471 va_list ap;
472 va_start(ap, s);
473 fprintf(stderr, "Error: ");
474 vfprintf(stderr, s, ap);
475 va_end(ap);
476 exit(1);
479 static const char *get_face_name( const struct fontinfo *info )
481 return (const char *)info->data + info->hdr.fi.dfFace - info->hdr.fi.dfBitsOffset;
484 static int lookup_charset(int enc)
486 /* FIXME: make winelib app and use TranslateCharsetInfo */
487 switch(enc) {
488 case 1250:
489 return EE_CHARSET;
490 case 1251:
491 return RUSSIAN_CHARSET;
492 case 1252:
493 return ANSI_CHARSET;
494 case 1253:
495 return GREEK_CHARSET;
496 case 1254:
497 return TURKISH_CHARSET;
498 case 1255:
499 return HEBREW_CHARSET;
500 case 1256:
501 return ARABIC_CHARSET;
502 case 1257:
503 return BALTIC_CHARSET;
504 case 1258:
505 return VIETNAMESE_CHARSET;
506 case 437:
507 case 737:
508 case 775:
509 case 850:
510 case 852:
511 case 855:
512 case 857:
513 case 860:
514 case 861:
515 case 862:
516 case 863:
517 case 864:
518 case 865:
519 case 866:
520 case 869:
521 return OEM_CHARSET;
522 case 874:
523 return THAI_CHARSET;
524 case 932:
525 return SHIFTJIS_CHARSET;
526 case 936:
527 return GB2312_CHARSET;
528 case 949:
529 return HANGUL_CHARSET;
530 case 950:
531 return CHINESEBIG5_CHARSET;
533 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
535 return OEM_CHARSET;
538 static void get_char_table(int enc, WCHAR tableW[0x100])
540 unsigned int i;
542 for (i = 0; i < 128; i++) tableW[i] = i;
544 for (i = 0; encodings[i].codepage; i++) if (encodings[i].codepage == enc) break;
545 memcpy( tableW + 128, encodings[i].table, 128 * sizeof(WCHAR) );
547 /* Korean has the Won sign in place of '\\' */
548 if (enc == 949) tableW['\\'] = 0x20a9;
551 static struct fontinfo *fill_fontinfo( const char *face_name, int ppem, int enc, int dpi,
552 unsigned char def_char, int avg_width )
554 FT_Face face;
555 int ascent = 0, il, el, width_bytes = 0, space_size, max_width = 0;
556 BYTE left_byte, right_byte, byte;
557 DWORD start;
558 int i, x, y, x_off, x_end, first_char;
559 FT_UInt gi;
560 int num_names;
561 FT_SfntName sfntname;
562 TT_OS2 *os2;
563 FT_ULong needed;
564 eblcHeader_t *eblc;
565 bitmapSizeTable_t *size_table;
566 int num_sizes;
567 struct fontinfo *info;
568 size_t data_pos;
569 WCHAR table[0x100];
571 if (FT_New_Face(ft_library, face_name, 0, &face)) error( "Cannot open face %s\n", face_name );
572 if (FT_Set_Pixel_Sizes(face, ppem, ppem)) error( "cannot set face size to %u\n", ppem );
574 assert( face->size->metrics.y_ppem == ppem );
576 get_char_table( enc, table );
578 needed = 0;
579 if (FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
580 fprintf(stderr,"Can't find EBLC table\n");
581 else
583 eblc = malloc(needed);
584 FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
586 num_sizes = GET_BE_DWORD(&eblc->numSizes);
588 size_table = (bitmapSizeTable_t *)(eblc + 1);
589 for(i = 0; i < num_sizes; i++)
591 if( (signed char)size_table->hori.ascender - (signed char)size_table->hori.descender == ppem)
593 ascent = size_table->hori.ascender;
594 break;
596 size_table++;
599 free(eblc);
602 /* Versions of fontforge prior to early 2006 have incorrect
603 ascender values in the eblc table, so we won't find the
604 correct bitmapSizeTable. In this case use the height of
605 the Aring glyph instead. */
606 if(ascent == 0)
608 if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
609 error("Can't find Aring\n");
610 ascent = face->glyph->metrics.horiBearingY >> 6;
613 start = sizeof(FNT_HEADER);
615 if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
616 error("Can't find M\n");
617 il = ascent - (face->glyph->metrics.height >> 6);
619 /* Hack: Courier has no internal leading, nor do any Chinese or Japanese fonts */
620 if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950 || enc == 932)
621 il = 0;
622 else if (!strcmp(face->family_name, "Fixedsys"))
623 il = 3;
625 /* Japanese System font has an external leading */
626 if (!strcmp(face->family_name, "System") && enc == 932)
627 el = 2;
628 else
629 el = 0;
631 first_char = FT_Get_First_Char(face, &gi);
632 if(first_char < 0x20) /* Ignore glyphs below 0x20 */
633 first_char = 0x20; /* FT_Get_Next_Char for some reason returns too high
634 number in this case */
636 info = calloc( 1, sizeof(*info) );
638 info->hdr.fi.dfFirstChar = first_char;
639 info->hdr.fi.dfLastChar = 0xff;
640 start += ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar + 3 ) * sizeof(*info->dfCharTable);
642 num_names = FT_Get_Sfnt_Name_Count(face);
643 for(i = 0; i <num_names; i++) {
644 FT_Get_Sfnt_Name(face, i, &sfntname);
645 if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
646 sfntname.language_id == 0 && sfntname.name_id == 0) {
647 size_t len = min( sfntname.string_len, sizeof(info->hdr.dfCopyright)-1 );
648 memcpy(info->hdr.dfCopyright, sfntname.string, len);
649 info->hdr.dfCopyright[len] = 0;
653 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
654 for(i = first_char; i < 0x100; i++) {
655 gi = FT_Get_Char_Index(face, table[i]);
656 if(gi == 0 && !option_quiet)
657 fprintf(stderr, "warning: %s %u: missing glyph for char %04x\n",
658 face->family_name, ppem, table[i]);
659 if(FT_Load_Char(face, table[i], FT_LOAD_DEFAULT)) {
660 fprintf(stderr, "error loading char %d - bad news!\n", i);
661 continue;
663 info->dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
664 info->dfCharTable[i].offset = start + (width_bytes * ppem);
665 width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
666 if(max_width < (face->glyph->metrics.horiAdvance >> 6))
667 max_width = face->glyph->metrics.horiAdvance >> 6;
669 /* space */
670 space_size = (ppem + 3) / 4;
671 info->dfCharTable[i].width = space_size;
672 info->dfCharTable[i].offset = start + (width_bytes * ppem);
673 width_bytes += (space_size + 7) >> 3;
674 /* sentinel */
675 info->dfCharTable[++i].width = 0;
676 info->dfCharTable[i].offset = start + (width_bytes * ppem);
678 info->hdr.fi.dfType = 0;
679 info->hdr.fi.dfPoints = ((ppem - il - el) * 72 + dpi/2) / dpi;
680 info->hdr.fi.dfVertRes = dpi;
681 info->hdr.fi.dfHorizRes = dpi;
682 info->hdr.fi.dfAscent = ascent;
683 info->hdr.fi.dfInternalLeading = il;
684 info->hdr.fi.dfExternalLeading = el;
685 info->hdr.fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
686 info->hdr.fi.dfUnderline = 0;
687 info->hdr.fi.dfStrikeOut = 0;
688 info->hdr.fi.dfWeight = os2->usWeightClass;
689 info->hdr.fi.dfCharSet = lookup_charset(enc);
690 info->hdr.fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ? avg_width : 0;
691 info->hdr.fi.dfPixHeight = ppem;
692 info->hdr.fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
693 switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
694 case PAN_FAMILY_SCRIPT:
695 info->hdr.fi.dfPitchAndFamily |= FF_SCRIPT;
696 break;
697 case PAN_FAMILY_DECORATIVE:
698 case PAN_FAMILY_PICTORIAL:
699 info->hdr.fi.dfPitchAndFamily |= FF_DECORATIVE;
700 break;
701 case PAN_FAMILY_TEXT_DISPLAY:
702 if(info->hdr.fi.dfPitchAndFamily == 0) /* fixed */
703 info->hdr.fi.dfPitchAndFamily = FF_MODERN;
704 else {
705 switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
706 case PAN_SERIF_NORMAL_SANS:
707 case PAN_SERIF_OBTUSE_SANS:
708 case PAN_SERIF_PERP_SANS:
709 info->hdr.fi.dfPitchAndFamily |= FF_SWISS;
710 break;
711 default:
712 info->hdr.fi.dfPitchAndFamily |= FF_ROMAN;
715 break;
716 default:
717 info->hdr.fi.dfPitchAndFamily |= FF_DONTCARE;
720 info->hdr.fi.dfAvgWidth = avg_width;
721 info->hdr.fi.dfMaxWidth = (enc == 932) ? avg_width * 2 : max_width;
722 info->hdr.fi.dfDefaultChar = def_char - info->hdr.fi.dfFirstChar;
723 info->hdr.fi.dfBreakChar = ' ' - info->hdr.fi.dfFirstChar;
724 info->hdr.fi.dfWidthBytes = (width_bytes + 1) & ~1;
726 info->hdr.fi.dfFace = start + info->hdr.fi.dfWidthBytes * ppem;
727 info->hdr.fi.dfBitsOffset = start;
728 info->hdr.fi.dfFlags = 0x10; /* DFF_1COLOR */
729 info->hdr.fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
731 info->hdr.dfVersion = 0x300;
732 info->hdr.dfSize = start + info->hdr.fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
734 info->data = calloc( info->hdr.dfSize - start, 1 );
735 data_pos = 0;
737 for(i = first_char; i < 0x100; i++) {
738 if(FT_Load_Char(face, table[i], FT_LOAD_DEFAULT)) {
739 continue;
741 assert(info->dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
743 for(x = 0; x < ((info->dfCharTable[i].width + 7) / 8); x++) {
744 for(y = 0; y < ppem; y++) {
745 if(y < ascent - face->glyph->bitmap_top ||
746 y >= face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
747 info->data[data_pos++] = 0;
748 continue;
750 x_off = face->glyph->bitmap_left / 8;
751 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
752 if(x < x_off || x > x_end) {
753 info->data[data_pos++] = 0;
754 continue;
756 if(x == x_off)
757 left_byte = 0;
758 else
759 left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
761 /* On the last non-trivial output byte (x == x_end) have we got one or two input bytes */
762 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)))
763 right_byte = 0;
764 else
765 right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
767 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
768 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
769 info->data[data_pos++] = byte;
773 data_pos += ((space_size + 7) / 8) * ppem;
774 if (width_bytes & 1) data_pos += ppem;
776 memcpy( info->data + data_pos, face->family_name, strlen( face->family_name ));
777 data_pos += strlen( face->family_name ) + 1;
778 assert( start + data_pos == info->hdr.dfSize );
780 FT_Done_Face( face );
781 return info;
784 static void adjust_fontinfo( FONTINFO16 * fi )
786 fi->dfType = PUT_LE_WORD(fi->dfType);
787 fi->dfPoints = PUT_LE_WORD(fi->dfPoints);
788 fi->dfVertRes = PUT_LE_WORD(fi->dfVertRes);
789 fi->dfHorizRes = PUT_LE_WORD(fi->dfHorizRes);
790 fi->dfAscent = PUT_LE_WORD(fi->dfAscent);
791 fi->dfInternalLeading = PUT_LE_WORD(fi->dfInternalLeading);
792 fi->dfExternalLeading = PUT_LE_WORD(fi->dfExternalLeading);
793 fi->dfWeight = PUT_LE_WORD(fi->dfWeight);
794 fi->dfPixWidth = PUT_LE_WORD(fi->dfPixWidth);
795 fi->dfPixHeight = PUT_LE_WORD(fi->dfPixHeight);
796 fi->dfAvgWidth = PUT_LE_WORD(fi->dfAvgWidth);
797 fi->dfMaxWidth = PUT_LE_WORD(fi->dfMaxWidth);
798 fi->dfWidthBytes = PUT_LE_WORD(fi->dfWidthBytes);
799 fi->dfAspace = PUT_LE_WORD(fi->dfAspace);
800 fi->dfBspace = PUT_LE_WORD(fi->dfBspace);
801 fi->dfCspace = PUT_LE_WORD(fi->dfCspace);
802 fi->dfDevice = PUT_LE_DWORD(fi->dfDevice);
803 fi->dfFace = PUT_LE_DWORD(fi->dfFace);
804 fi->dfBitsPointer = PUT_LE_DWORD(fi->dfBitsPointer);
805 fi->dfBitsOffset = PUT_LE_DWORD(fi->dfBitsOffset);
806 fi->dfFlags = PUT_LE_DWORD(fi->dfFlags);
807 fi->dfColorPointer = PUT_LE_DWORD(fi->dfColorPointer);
810 static void write_fontinfo( const struct fontinfo *info, FILE *fp )
812 FNT_HEADER tmp_hdr;
813 int num_chars, i;
814 CHAR_TABLE_ENTRY tmp_chartable[258];
815 memcpy(&tmp_hdr, &info->hdr, sizeof(info->hdr));
816 tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
817 tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
818 adjust_fontinfo(&(tmp_hdr.fi));
819 fwrite( &tmp_hdr, sizeof(info->hdr), 1, fp );
820 num_chars = ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar) + 3;
822 memcpy(&tmp_chartable, info->dfCharTable + info->hdr.fi.dfFirstChar, num_chars * sizeof(CHAR_TABLE_ENTRY));
823 for (i=0; i < num_chars; ++i) {
824 tmp_chartable[i].width = PUT_LE_WORD(tmp_chartable[i].width);
825 tmp_chartable[i].offset = PUT_LE_DWORD(tmp_chartable[i].offset);
827 fwrite( tmp_chartable, sizeof(CHAR_TABLE_ENTRY), num_chars, fp );
828 fwrite( info->data, info->hdr.dfSize - info->hdr.fi.dfBitsOffset, 1, fp );
831 /* parse options from the argv array and remove all the recognized ones */
832 static char **parse_options( int argc, char **argv )
834 int optc;
836 while ((optc = getopt_long( argc, argv, "d:ho:qr:s", NULL, NULL )) != -1)
838 switch(optc)
840 case 'd':
841 option_defchar = atoi( optarg );
842 break;
843 case 'o':
844 option_output = strdup( optarg );
845 break;
846 case 'q':
847 option_quiet = 1;
848 break;
849 case 'r':
850 option_dpi = atoi( optarg );
851 break;
852 case 's':
853 option_fnt_mode = 1;
854 break;
855 case 'h':
856 usage(argv);
857 exit(0);
858 case '?':
859 usage(argv);
860 exit(1);
863 return &argv[optind];
866 int main(int argc, char **argv)
868 int i, j;
869 FILE *ofp;
870 short align, num_files;
871 int resource_table_len, non_resident_name_len, resident_name_len;
872 unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, font_off;
873 char resident_name[200];
874 int fontdir_len = 2;
875 char non_resident_name[200];
876 unsigned short first_res = 0x0050, pad, res;
877 IMAGE_OS2_HEADER NE_hdr;
878 NE_TYPEINFO rc_type;
879 NE_NAMEINFO rc_name;
880 struct fontinfo **info;
881 char *input_file;
882 char **args;
883 short tmp16;
885 args = parse_options( argc, argv );
887 input_file = *args++;
888 if (!input_file || !*args)
890 usage(argv);
891 exit(1);
894 if(FT_Init_FreeType(&ft_library))
895 error("ft init failure\n");
897 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
898 FT_Library_Version(ft_library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
900 num_files = 0;
901 while (args[num_files]) num_files++;
903 if (option_fnt_mode && num_files > 1)
904 error( "can only specify one font in .fnt mode\n" );
906 info = malloc( num_files * sizeof(*info) );
907 for (i = 0; i < num_files; i++)
909 int ppem, enc, avg_width;
910 const char *name;
912 if (sscanf( args[i], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
914 usage(argv);
915 exit(1);
917 if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
918 exit(1);
920 name = get_face_name( info[i] );
921 fontdir_len += 0x74 + strlen(name) + 1;
922 if(i == 0) {
923 sprintf(non_resident_name, "FONTRES 100,%d,%d : %s %d",
924 info[i]->hdr.fi.dfVertRes, info[i]->hdr.fi.dfHorizRes,
925 name, info[i]->hdr.fi.dfPoints );
926 strcpy(resident_name, name);
927 } else {
928 sprintf(non_resident_name + strlen(non_resident_name), ",%d", info[i]->hdr.fi.dfPoints );
932 if (option_dpi <= 108)
933 strcat(non_resident_name, " (VGA res)");
934 else
935 strcat(non_resident_name, " (8514 res)");
936 non_resident_name_len = strlen(non_resident_name) + 4;
938 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
939 resource_table_len = sizeof(align) + sizeof("FONTDIR") +
940 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) +
941 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) * num_files +
942 sizeof(NE_TYPEINFO);
943 resource_table_off = sizeof(NE_hdr);
944 resident_name_off = resource_table_off + resource_table_len;
945 resident_name_len = strlen(resident_name) + 4;
946 module_ref_off = resident_name_off + resident_name_len;
947 non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(align);
949 memset(&NE_hdr, 0, sizeof(NE_hdr));
950 NE_hdr.ne_magic = PUT_LE_WORD(0x454e);
951 NE_hdr.ne_ver = 5;
952 NE_hdr.ne_rev = 1;
953 NE_hdr.ne_flags = PUT_LE_WORD(NE_FFLAGS_LIBMODULE | NE_FFLAGS_GUI);
954 NE_hdr.ne_cbnrestab = PUT_LE_WORD(non_resident_name_len);
955 NE_hdr.ne_segtab = PUT_LE_WORD(sizeof(NE_hdr));
956 NE_hdr.ne_rsrctab = PUT_LE_WORD(sizeof(NE_hdr));
957 NE_hdr.ne_restab = PUT_LE_WORD(resident_name_off);
958 NE_hdr.ne_modtab = PUT_LE_WORD(module_ref_off);
959 NE_hdr.ne_imptab = PUT_LE_WORD(module_ref_off);
960 NE_hdr.ne_enttab = NE_hdr.ne_modtab;
961 NE_hdr.ne_nrestab = PUT_LE_DWORD(non_resident_name_off);
962 NE_hdr.ne_align = PUT_LE_WORD(4);
963 NE_hdr.ne_exetyp = NE_OSFLAGS_WINDOWS;
964 NE_hdr.ne_expver = PUT_LE_WORD(0x400);
966 fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
967 font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
969 atexit( cleanup );
970 signal( SIGTERM, exit_on_signal );
971 signal( SIGINT, exit_on_signal );
972 #ifdef SIGHUP
973 signal( SIGHUP, exit_on_signal );
974 #endif
976 if (!option_output) /* build a default output name */
978 char *p = strrchr( input_file, '/' );
979 if (p) p++;
980 else p = input_file;
981 option_output = malloc( strlen(p) + sizeof(".fon") );
982 strcpy( option_output, p );
983 p = strrchr( option_output, '.' );
984 if (!p) p = option_output + strlen(option_output);
985 strcpy( p, option_fnt_mode ? ".fnt" : ".fon" );
988 if (!(ofp = fopen(option_output, "wb")))
990 perror( option_output );
991 exit(1);
993 output_name = option_output;
994 if (option_fnt_mode)
996 write_fontinfo( info[0], ofp );
997 goto done;
1000 fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
1001 fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
1003 align = PUT_LE_WORD(4);
1004 fwrite(&align, sizeof(align), 1, ofp);
1006 rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONTDIR);
1007 rc_type.count = PUT_LE_WORD(1);
1008 rc_type.resloader = 0;
1009 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
1011 rc_name.offset = PUT_LE_WORD(fontdir_off >> 4);
1012 rc_name.length = PUT_LE_WORD((fontdir_len + 15) >> 4);
1013 rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD);
1014 rc_name.id = PUT_LE_WORD(resident_name_off - sizeof("FONTDIR") - sizeof(NE_hdr));
1015 rc_name.handle = 0;
1016 rc_name.usage = 0;
1017 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
1019 rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONT);
1020 rc_type.count = PUT_LE_WORD(num_files);
1021 rc_type.resloader = 0;
1022 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
1024 for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
1025 int len = (info[i]->hdr.dfSize + 15) & ~0xf;
1027 rc_name.offset = PUT_LE_WORD(font_off >> 4);
1028 rc_name.length = PUT_LE_WORD(len >> 4);
1029 rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_SHAREABLE | NE_SEGFLAGS_DISCARDABLE);
1030 rc_name.id = PUT_LE_WORD(res);
1031 rc_name.handle = 0;
1032 rc_name.usage = 0;
1033 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
1035 font_off += len;
1038 /* empty type info */
1039 memset(&rc_type, 0, sizeof(rc_type));
1040 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
1042 fputc(strlen("FONTDIR"), ofp);
1043 fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp);
1044 fputc(strlen(resident_name), ofp);
1045 fwrite(resident_name, strlen(resident_name), 1, ofp);
1047 fputc(0x00, ofp); fputc(0x00, ofp);
1048 fputc(0x00, ofp);
1049 fputc(0x00, ofp); fputc(0x00, ofp);
1051 fputc(strlen(non_resident_name), ofp);
1052 fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
1053 fputc(0x00, ofp); /* terminator */
1055 /* empty ne_modtab and ne_imptab */
1056 fputc(0x00, ofp);
1057 fputc(0x00, ofp);
1059 pad = ftell(ofp) & 0xf;
1060 if(pad != 0)
1061 pad = 0x10 - pad;
1062 for(i = 0; i < pad; i++)
1063 fputc(0x00, ofp);
1065 /* FONTDIR resource */
1066 tmp16 = PUT_LE_WORD(num_files);
1067 fwrite(&tmp16, sizeof(tmp16), 1, ofp);
1069 for(res = first_res, i = 0; i < num_files; i++, res++) {
1070 FNT_HEADER tmp_hdr;
1071 int sz;
1072 const char *name = get_face_name( info[i] );
1073 tmp16 = PUT_LE_WORD(res);
1074 fwrite(&tmp16, sizeof(tmp16), 1, ofp);
1075 sz = FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset);
1076 memcpy(&tmp_hdr, &info[i]->hdr, sz);
1077 tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
1078 tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
1079 adjust_fontinfo(&(tmp_hdr.fi));
1080 fwrite(&tmp_hdr, FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset), 1, ofp);
1081 fputc(0x00, ofp);
1082 fwrite(name, strlen(name) + 1, 1, ofp);
1085 pad = ftell(ofp) & 0xf;
1086 if(pad != 0)
1087 pad = 0x10 - pad;
1088 for(i = 0; i < pad; i++)
1089 fputc(0x00, ofp);
1091 for(res = first_res, i = 0; i < num_files; i++, res++) {
1092 write_fontinfo( info[i], ofp );
1093 pad = info[i]->hdr.dfSize & 0xf;
1094 if(pad != 0)
1095 pad = 0x10 - pad;
1096 for(j = 0; j < pad; j++)
1097 fputc(0x00, ofp);
1099 done:
1100 fclose(ofp);
1101 output_name = NULL;
1102 exit(0);
1105 #else /* HAVE_FREETYPE */
1107 int main(int argc, char **argv)
1109 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
1110 exit(1);
1113 #endif /* HAVE_FREETYPE */