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