widl: Add support for structures.
[wine.git] / tools / sfnt2fon / sfnt2fon.c
blob2c307dcce8a3c6764d08f4c2ec8b720bb6dc2077
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 <stdio.h>
27 #include <stdlib.h>
29 #ifdef HAVE_FREETYPE
31 #ifdef HAVE_FT2BUILD_H
32 #include <ft2build.h>
33 #endif
34 #include FT_FREETYPE_H
35 #include FT_SFNT_NAMES_H
36 #include FT_TRUETYPE_TABLES_H
37 #include FT_TRUETYPE_TAGS_H
39 #include "windef.h"
40 #include "winbase.h"
41 #include "wingdi.h"
42 #include "basetsd.h"
43 #include "../tools.h"
45 #include "pshpack1.h"
47 typedef struct
49 INT16 dfType;
50 INT16 dfPoints;
51 INT16 dfVertRes;
52 INT16 dfHorizRes;
53 INT16 dfAscent;
54 INT16 dfInternalLeading;
55 INT16 dfExternalLeading;
56 BYTE dfItalic;
57 BYTE dfUnderline;
58 BYTE dfStrikeOut;
59 INT16 dfWeight;
60 BYTE dfCharSet;
61 INT16 dfPixWidth;
62 INT16 dfPixHeight;
63 BYTE dfPitchAndFamily;
64 INT16 dfAvgWidth;
65 INT16 dfMaxWidth;
66 BYTE dfFirstChar;
67 BYTE dfLastChar;
68 BYTE dfDefaultChar;
69 BYTE dfBreakChar;
70 INT16 dfWidthBytes;
71 LONG dfDevice;
72 LONG dfFace;
73 LONG dfBitsPointer;
74 LONG dfBitsOffset;
75 BYTE dfReserved;
76 LONG dfFlags;
77 INT16 dfAspace;
78 INT16 dfBspace;
79 INT16 dfCspace;
80 LONG dfColorPointer;
81 LONG dfReserved1[4];
82 } FONTINFO16;
84 typedef struct
86 WORD dfVersion;
87 DWORD dfSize;
88 char dfCopyright[60];
89 FONTINFO16 fi;
90 } FNT_HEADER;
92 typedef struct {
93 WORD width;
94 DWORD offset;
95 } CHAR_TABLE_ENTRY;
97 typedef struct {
98 DWORD version;
99 ULONG numSizes;
100 } eblcHeader_t;
102 typedef struct {
103 CHAR ascender;
104 CHAR descender;
105 BYTE widthMax;
106 CHAR caretSlopeNumerator;
107 CHAR caretSlopeDenominator;
108 CHAR caretOffset;
109 CHAR minOriginSB;
110 CHAR minAdvanceSB;
111 CHAR maxBeforeBL;
112 CHAR maxAfterBL;
113 CHAR pad1;
114 CHAR pad2;
115 } sbitLineMetrics_t;
117 typedef struct {
118 ULONG indexSubTableArrayOffset;
119 ULONG indexTableSize;
120 ULONG numberOfIndexSubTables;
121 ULONG colorRef;
122 sbitLineMetrics_t hori;
123 sbitLineMetrics_t vert;
124 USHORT startGlyphIndex;
125 USHORT endGlyphIndex;
126 BYTE ppemX;
127 BYTE ppemY;
128 BYTE bitDepth;
129 CHAR flags;
130 } bitmapSizeTable_t;
132 typedef struct
134 FT_Int major;
135 FT_Int minor;
136 FT_Int patch;
137 } FT_Version_t;
138 static FT_Version_t FT_Version;
140 #include "poppack.h"
142 unsigned char *output_buffer = NULL;
143 size_t output_buffer_pos = 0;
144 size_t output_buffer_size = 0;
146 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
147 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
148 GET_BE_WORD(&((WORD *)(ptr))[0]) ))
150 struct fontinfo
152 FNT_HEADER hdr;
153 CHAR_TABLE_ENTRY dfCharTable[258];
154 BYTE *data;
157 static const BYTE MZ_hdr[] =
159 'M', 'Z', 0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
160 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
163 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
164 'i', 's', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n', 'n', 'o',
165 't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O', 'S', ' ',
166 'm', 'o', 'd', 'e', 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
169 static const WCHAR encoding_1250[128] =
171 0x20ac, 0x0081, 0x201a, 0x0083, 0x201e, 0x2026, 0x2020, 0x2021,
172 0x0088, 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
173 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
174 0x0098, 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
175 0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7,
176 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
177 0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
178 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
179 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
180 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
181 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
182 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
183 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
184 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
185 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
186 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9
189 static const WCHAR encoding_1251[128] =
191 0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, 0x2021,
192 0x20ac, 0x2030, 0x0409, 0x2039, 0x040a, 0x040c, 0x040b, 0x040f,
193 0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
194 0x0098, 0x2122, 0x0459, 0x203a, 0x045a, 0x045c, 0x045b, 0x045f,
195 0x00a0, 0x040e, 0x045e, 0x0408, 0x00a4, 0x0490, 0x00a6, 0x00a7,
196 0x0401, 0x00a9, 0x0404, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0407,
197 0x00b0, 0x00b1, 0x0406, 0x0456, 0x0491, 0x00b5, 0x00b6, 0x00b7,
198 0x0451, 0x2116, 0x0454, 0x00bb, 0x0458, 0x0405, 0x0455, 0x0457,
199 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
200 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
201 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
202 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
203 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
204 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
205 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
206 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f
209 static const WCHAR encoding_1252[128] =
211 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
212 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
213 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
214 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178,
215 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
216 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
217 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
218 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
219 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
220 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
221 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
222 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
223 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
224 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
225 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
226 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
229 static const WCHAR encoding_1253[128] =
231 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
232 0x0088, 0x2030, 0x008a, 0x2039, 0x008c, 0x008d, 0x008e, 0x008f,
233 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
234 0x0098, 0x2122, 0x009a, 0x203a, 0x009c, 0x009d, 0x009e, 0x009f,
235 0x00a0, 0x0385, 0x0386, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
236 0x00a8, 0x00a9, 0xf8f9, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x2015,
237 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x0384, 0x00b5, 0x00b6, 0x00b7,
238 0x0388, 0x0389, 0x038a, 0x00bb, 0x038c, 0x00bd, 0x038e, 0x038f,
239 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
240 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
241 0x03a0, 0x03a1, 0xf8fa, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
242 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,
243 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
244 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
245 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
246 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0xf8fb
249 static const WCHAR encoding_1254[128] =
251 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
252 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x008e, 0x008f,
253 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
254 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x009e, 0x0178,
255 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
256 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
257 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
258 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
259 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
260 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
261 0x011e, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
262 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x0130, 0x015e, 0x00df,
263 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
264 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
265 0x011f, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
266 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x0131, 0x015f, 0x00ff
269 static const WCHAR encoding_1255[128] =
271 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
272 0x02c6, 0x2030, 0x008a, 0x2039, 0x008c, 0x008d, 0x008e, 0x008f,
273 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
274 0x02dc, 0x2122, 0x009a, 0x203a, 0x009c, 0x009d, 0x009e, 0x009f,
275 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20aa, 0x00a5, 0x00a6, 0x00a7,
276 0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
277 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
278 0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
279 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7,
280 0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf,
281 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05f0, 0x05f1, 0x05f2, 0x05f3,
282 0x05f4, 0xf88d, 0xf88e, 0xf88f, 0xf890, 0xf891, 0xf892, 0xf893,
283 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
284 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
285 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
286 0x05e8, 0x05e9, 0x05ea, 0xf894, 0xf895, 0x200e, 0x200f, 0xf896
289 static const WCHAR encoding_1256[128] =
291 0x20ac, 0x067e, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
292 0x02c6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
293 0x06af, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
294 0x06a9, 0x2122, 0x0691, 0x203a, 0x0153, 0x200c, 0x200d, 0x06ba,
295 0x00a0, 0x060c, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
296 0x00a8, 0x00a9, 0x06be, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
297 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
298 0x00b8, 0x00b9, 0x061b, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x061f,
299 0x06c1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
300 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f,
301 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00d7,
302 0x0637, 0x0638, 0x0639, 0x063a, 0x0640, 0x0641, 0x0642, 0x0643,
303 0x00e0, 0x0644, 0x00e2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00e7,
304 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x0649, 0x064a, 0x00ee, 0x00ef,
305 0x064b, 0x064c, 0x064d, 0x064e, 0x00f4, 0x064f, 0x0650, 0x00f7,
306 0x0651, 0x00f9, 0x0652, 0x00fb, 0x00fc, 0x200e, 0x200f, 0x06d2
309 static const WCHAR encoding_1257[128] =
311 0x20ac, 0x0081, 0x201a, 0x0083, 0x201e, 0x2026, 0x2020, 0x2021,
312 0x0088, 0x2030, 0x008a, 0x2039, 0x008c, 0x00a8, 0x02c7, 0x00b8,
313 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
314 0x0098, 0x2122, 0x009a, 0x203a, 0x009c, 0x00af, 0x02db, 0x009f,
315 0x00a0, 0xf8fc, 0x00a2, 0x00a3, 0x00a4, 0xf8fd, 0x00a6, 0x00a7,
316 0x00d8, 0x00a9, 0x0156, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00c6,
317 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
318 0x00f8, 0x00b9, 0x0157, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00e6,
319 0x0104, 0x012e, 0x0100, 0x0106, 0x00c4, 0x00c5, 0x0118, 0x0112,
320 0x010c, 0x00c9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012a, 0x013b,
321 0x0160, 0x0143, 0x0145, 0x00d3, 0x014c, 0x00d5, 0x00d6, 0x00d7,
322 0x0172, 0x0141, 0x015a, 0x016a, 0x00dc, 0x017b, 0x017d, 0x00df,
323 0x0105, 0x012f, 0x0101, 0x0107, 0x00e4, 0x00e5, 0x0119, 0x0113,
324 0x010d, 0x00e9, 0x017a, 0x0117, 0x0123, 0x0137, 0x012b, 0x013c,
325 0x0161, 0x0144, 0x0146, 0x00f3, 0x014d, 0x00f5, 0x00f6, 0x00f7,
326 0x0173, 0x0142, 0x015b, 0x016b, 0x00fc, 0x017c, 0x017e, 0x02d9
329 static const WCHAR encoding_874[128] =
331 0x20ac, 0x0081, 0x0082, 0x0083, 0x0084, 0x2026, 0x0086, 0x0087,
332 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
333 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
334 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
335 0x00a0, 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07,
336 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f,
337 0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17,
338 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f,
339 0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27,
340 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f,
341 0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37,
342 0x0e38, 0x0e39, 0x0e3a, 0xf8c1, 0xf8c2, 0xf8c3, 0xf8c4, 0x0e3f,
343 0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47,
344 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0e4e, 0x0e4f,
345 0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57,
346 0x0e58, 0x0e59, 0x0e5a, 0x0e5b, 0xf8c5, 0xf8c6, 0xf8c7, 0xf8c8
349 static const struct { int codepage; const WCHAR *table; } encodings[] =
351 { 874, encoding_874 },
352 { 1250, encoding_1250 },
353 { 1251, encoding_1251 },
354 { 1252, encoding_1252 },
355 { 1253, encoding_1253 },
356 { 1254, encoding_1254 },
357 { 1255, encoding_1255 },
358 { 1256, encoding_1256 },
359 { 1257, encoding_1257 },
360 { 0, encoding_1252 }, /* default encoding */
363 static int option_defchar = ' ';
364 static int option_dpi = 96;
365 static int option_fnt_mode = 0;
366 static int option_quiet = 0;
368 static const char *output_name;
370 static FT_Library ft_library;
372 static const char *argv0;
374 static void usage(void)
376 fprintf(stderr, "%s [options] input.ttf ppem,enc,avg_width ...\n", argv0);
377 fprintf(stderr, "Options:\n");
378 fprintf(stderr, " -h Display help\n" );
379 fprintf(stderr, " -d char Set the font default char\n" );
380 fprintf(stderr, " -o file Set output file name\n" );
381 fprintf(stderr, " -q Quiet mode\n" );
382 fprintf(stderr, " -r dpi Set resolution in DPI (default: 96)\n" );
383 fprintf(stderr, " -s Single .fnt file mode\n" );
386 /* atexit handler to cleanup files */
387 static void cleanup(void)
389 if (output_name) unlink( output_name );
392 static void exit_on_signal( int sig )
394 exit(1); /* this will call the atexit functions */
397 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
399 static void error(const char *s, ...)
401 va_list ap;
402 va_start(ap, s);
403 fprintf(stderr, "Error: ");
404 vfprintf(stderr, s, ap);
405 va_end(ap);
406 exit(1);
409 static const char *get_face_name( const struct fontinfo *info )
411 return (const char *)info->data + info->hdr.fi.dfFace - info->hdr.fi.dfBitsOffset;
414 static int lookup_charset(int enc)
416 /* FIXME: make winelib app and use TranslateCharsetInfo */
417 switch(enc) {
418 case 1250:
419 return EE_CHARSET;
420 case 1251:
421 return RUSSIAN_CHARSET;
422 case 1252:
423 return ANSI_CHARSET;
424 case 1253:
425 return GREEK_CHARSET;
426 case 1254:
427 return TURKISH_CHARSET;
428 case 1255:
429 return HEBREW_CHARSET;
430 case 1256:
431 return ARABIC_CHARSET;
432 case 1257:
433 return BALTIC_CHARSET;
434 case 1258:
435 return VIETNAMESE_CHARSET;
436 case 437:
437 case 737:
438 case 775:
439 case 850:
440 case 852:
441 case 855:
442 case 857:
443 case 860:
444 case 861:
445 case 862:
446 case 863:
447 case 864:
448 case 865:
449 case 866:
450 case 869:
451 return OEM_CHARSET;
452 case 874:
453 return THAI_CHARSET;
454 case 932:
455 return SHIFTJIS_CHARSET;
456 case 936:
457 return GB2312_CHARSET;
458 case 949:
459 return HANGUL_CHARSET;
460 case 950:
461 return CHINESEBIG5_CHARSET;
463 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
465 return OEM_CHARSET;
468 static void get_char_table(int enc, WCHAR tableW[0x100])
470 unsigned int i;
472 for (i = 0; i < 128; i++) tableW[i] = i;
474 for (i = 0; encodings[i].codepage; i++) if (encodings[i].codepage == enc) break;
475 memcpy( tableW + 128, encodings[i].table, 128 * sizeof(WCHAR) );
477 /* Korean has the Won sign in place of '\\' */
478 if (enc == 949) tableW['\\'] = 0x20a9;
481 static struct fontinfo *fill_fontinfo( const char *face_name, int ppem, int enc, int dpi,
482 unsigned char def_char, int avg_width )
484 FT_Face face;
485 int ascent = 0, il, el, width_bytes = 0, space_size, max_width = 0;
486 BYTE left_byte, right_byte, byte;
487 DWORD start;
488 int i, x, y, x_off, x_end, first_char;
489 FT_UInt gi;
490 int num_names;
491 FT_SfntName sfntname;
492 TT_OS2 *os2;
493 FT_ULong needed;
494 eblcHeader_t *eblc;
495 bitmapSizeTable_t *size_table;
496 int num_sizes;
497 struct fontinfo *info;
498 size_t data_pos;
499 WCHAR table[0x100];
501 if (FT_New_Face(ft_library, face_name, 0, &face)) error( "Cannot open face %s\n", face_name );
502 if (FT_Set_Pixel_Sizes(face, ppem, ppem)) error( "cannot set face size to %u\n", ppem );
504 assert( face->size->metrics.y_ppem == ppem );
506 get_char_table( enc, table );
508 needed = 0;
509 if (FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
510 fprintf(stderr,"Can't find EBLC table\n");
511 else
513 eblc = xmalloc(needed);
514 FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
516 num_sizes = GET_BE_DWORD(&eblc->numSizes);
518 size_table = (bitmapSizeTable_t *)(eblc + 1);
519 for(i = 0; i < num_sizes; i++)
521 if( (signed char)size_table->hori.ascender - (signed char)size_table->hori.descender == ppem)
523 ascent = size_table->hori.ascender;
524 break;
526 size_table++;
529 free(eblc);
532 /* Versions of fontforge prior to early 2006 have incorrect
533 ascender values in the eblc table, so we won't find the
534 correct bitmapSizeTable. In this case use the height of
535 the Aring glyph instead. */
536 if(ascent == 0)
538 if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
539 error("Can't find Aring\n");
540 ascent = face->glyph->metrics.horiBearingY >> 6;
543 start = sizeof(FNT_HEADER);
545 if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
546 error("Can't find M\n");
547 il = ascent - (face->glyph->metrics.height >> 6);
549 /* Hack: Courier has no internal leading, nor do any Chinese or Japanese fonts */
550 if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950 || enc == 932)
551 il = 0;
552 else if (!strcmp(face->family_name, "Fixedsys"))
553 il = 3;
555 /* Japanese System font has an external leading */
556 if (!strcmp(face->family_name, "System") && enc == 932)
557 el = 2;
558 else
559 el = 0;
561 first_char = FT_Get_First_Char(face, &gi);
562 if(first_char < 0x20) /* Ignore glyphs below 0x20 */
563 first_char = 0x20; /* FT_Get_Next_Char for some reason returns too high
564 number in this case */
566 info = calloc( 1, sizeof(*info) );
568 info->hdr.fi.dfFirstChar = first_char;
569 info->hdr.fi.dfLastChar = 0xff;
570 start += ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar + 3 ) * sizeof(*info->dfCharTable);
572 num_names = FT_Get_Sfnt_Name_Count(face);
573 for(i = 0; i <num_names; i++) {
574 FT_Get_Sfnt_Name(face, i, &sfntname);
575 if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
576 sfntname.language_id == 0 && sfntname.name_id == 0) {
577 size_t len = min( sfntname.string_len, sizeof(info->hdr.dfCopyright)-1 );
578 memcpy(info->hdr.dfCopyright, sfntname.string, len);
579 info->hdr.dfCopyright[len] = 0;
583 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
584 for(i = first_char; i < 0x100; i++) {
585 gi = FT_Get_Char_Index(face, table[i]);
586 if(gi == 0 && !option_quiet)
587 fprintf(stderr, "warning: %s %u: missing glyph for char %04x\n",
588 face->family_name, ppem, table[i]);
589 if(FT_Load_Char(face, table[i], FT_LOAD_DEFAULT)) {
590 fprintf(stderr, "error loading char %d - bad news!\n", i);
591 continue;
593 info->dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
594 info->dfCharTable[i].offset = start + (width_bytes * ppem);
595 width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
596 if(max_width < (face->glyph->metrics.horiAdvance >> 6))
597 max_width = face->glyph->metrics.horiAdvance >> 6;
599 /* space */
600 space_size = (ppem + 3) / 4;
601 info->dfCharTable[i].width = space_size;
602 info->dfCharTable[i].offset = start + (width_bytes * ppem);
603 width_bytes += (space_size + 7) >> 3;
604 /* sentinel */
605 info->dfCharTable[++i].width = 0;
606 info->dfCharTable[i].offset = start + (width_bytes * ppem);
608 info->hdr.fi.dfType = 0;
609 info->hdr.fi.dfPoints = ((ppem - il - el) * 72 + dpi/2) / dpi;
610 info->hdr.fi.dfVertRes = dpi;
611 info->hdr.fi.dfHorizRes = dpi;
612 info->hdr.fi.dfAscent = ascent;
613 info->hdr.fi.dfInternalLeading = il;
614 info->hdr.fi.dfExternalLeading = el;
615 info->hdr.fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
616 info->hdr.fi.dfUnderline = 0;
617 info->hdr.fi.dfStrikeOut = 0;
618 info->hdr.fi.dfWeight = os2->usWeightClass;
619 info->hdr.fi.dfCharSet = lookup_charset(enc);
620 info->hdr.fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ? avg_width : 0;
621 info->hdr.fi.dfPixHeight = ppem;
622 info->hdr.fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
623 switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
624 case PAN_FAMILY_SCRIPT:
625 info->hdr.fi.dfPitchAndFamily |= FF_SCRIPT;
626 break;
627 case PAN_FAMILY_DECORATIVE:
628 case PAN_FAMILY_PICTORIAL:
629 info->hdr.fi.dfPitchAndFamily |= FF_DECORATIVE;
630 break;
631 case PAN_FAMILY_TEXT_DISPLAY:
632 if(info->hdr.fi.dfPitchAndFamily == 0) /* fixed */
633 info->hdr.fi.dfPitchAndFamily = FF_MODERN;
634 else {
635 switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
636 case PAN_SERIF_NORMAL_SANS:
637 case PAN_SERIF_OBTUSE_SANS:
638 case PAN_SERIF_PERP_SANS:
639 info->hdr.fi.dfPitchAndFamily |= FF_SWISS;
640 break;
641 default:
642 info->hdr.fi.dfPitchAndFamily |= FF_ROMAN;
645 break;
646 default:
647 info->hdr.fi.dfPitchAndFamily |= FF_DONTCARE;
650 info->hdr.fi.dfAvgWidth = avg_width;
651 info->hdr.fi.dfMaxWidth = (enc == 932) ? avg_width * 2 : max_width;
652 info->hdr.fi.dfDefaultChar = def_char - info->hdr.fi.dfFirstChar;
653 info->hdr.fi.dfBreakChar = ' ' - info->hdr.fi.dfFirstChar;
654 info->hdr.fi.dfWidthBytes = (width_bytes + 1) & ~1;
656 info->hdr.fi.dfFace = start + info->hdr.fi.dfWidthBytes * ppem;
657 info->hdr.fi.dfBitsOffset = start;
658 info->hdr.fi.dfFlags = 0x10; /* DFF_1COLOR */
659 info->hdr.fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
661 info->hdr.dfVersion = 0x300;
662 info->hdr.dfSize = start + info->hdr.fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
664 info->data = calloc( info->hdr.dfSize - start, 1 );
665 data_pos = 0;
667 for(i = first_char; i < 0x100; i++) {
668 if(FT_Load_Char(face, table[i], FT_LOAD_DEFAULT)) {
669 continue;
671 assert(info->dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
673 for(x = 0; x < ((info->dfCharTable[i].width + 7) / 8); x++) {
674 for(y = 0; y < ppem; y++) {
675 if(y < ascent - face->glyph->bitmap_top ||
676 y >= (int)face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
677 info->data[data_pos++] = 0;
678 continue;
680 x_off = face->glyph->bitmap_left / 8;
681 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
682 if(x < x_off || x > x_end) {
683 info->data[data_pos++] = 0;
684 continue;
686 if(x == x_off)
687 left_byte = 0;
688 else
689 left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
691 /* On the last non-trivial output byte (x == x_end) have we got one or two input bytes */
692 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)))
693 right_byte = 0;
694 else
695 right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
697 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
698 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
699 info->data[data_pos++] = byte;
703 data_pos += ((space_size + 7) / 8) * ppem;
704 if (width_bytes & 1) data_pos += ppem;
706 memcpy( info->data + data_pos, face->family_name, strlen( face->family_name ));
707 data_pos += strlen( face->family_name ) + 1;
708 assert( start + data_pos == info->hdr.dfSize );
710 FT_Done_Face( face );
711 return info;
714 static void put_fontdir( const struct fontinfo *info )
716 const char *name = get_face_name( info );
718 put_word( info->hdr.dfVersion );
719 put_dword( info->hdr.dfSize );
720 put_data( info->hdr.dfCopyright, sizeof(info->hdr.dfCopyright) );
721 put_word( info->hdr.fi.dfType );
722 put_word( info->hdr.fi.dfPoints );
723 put_word( info->hdr.fi.dfVertRes );
724 put_word( info->hdr.fi.dfHorizRes );
725 put_word( info->hdr.fi.dfAscent );
726 put_word( info->hdr.fi.dfInternalLeading );
727 put_word( info->hdr.fi.dfExternalLeading );
728 put_byte( info->hdr.fi.dfItalic );
729 put_byte( info->hdr.fi.dfUnderline );
730 put_byte( info->hdr.fi.dfStrikeOut );
731 put_word( info->hdr.fi.dfWeight );
732 put_byte( info->hdr.fi.dfCharSet );
733 put_word( info->hdr.fi.dfPixWidth );
734 put_word( info->hdr.fi.dfPixHeight );
735 put_byte( info->hdr.fi.dfPitchAndFamily );
736 put_word( info->hdr.fi.dfAvgWidth );
737 put_word( info->hdr.fi.dfMaxWidth );
738 put_byte( info->hdr.fi.dfFirstChar );
739 put_byte( info->hdr.fi.dfLastChar );
740 put_byte( info->hdr.fi.dfDefaultChar );
741 put_byte( info->hdr.fi.dfBreakChar );
742 put_word( info->hdr.fi.dfWidthBytes );
743 put_dword( info->hdr.fi.dfDevice );
744 put_dword( info->hdr.fi.dfFace );
745 put_dword( 0 ); /* dfReserved */
746 put_byte( 0 ); /* szDeviceName */
747 put_data( name, strlen(name) + 1 ); /* szFaceName */
750 static void put_font( const struct fontinfo *info )
752 int num_chars, i;
754 put_word( info->hdr.dfVersion );
755 put_dword( info->hdr.dfSize );
756 put_data( info->hdr.dfCopyright, sizeof(info->hdr.dfCopyright) );
757 put_word( info->hdr.fi.dfType );
758 put_word( info->hdr.fi.dfPoints );
759 put_word( info->hdr.fi.dfVertRes );
760 put_word( info->hdr.fi.dfHorizRes );
761 put_word( info->hdr.fi.dfAscent );
762 put_word( info->hdr.fi.dfInternalLeading );
763 put_word( info->hdr.fi.dfExternalLeading );
764 put_byte( info->hdr.fi.dfItalic );
765 put_byte( info->hdr.fi.dfUnderline );
766 put_byte( info->hdr.fi.dfStrikeOut );
767 put_word( info->hdr.fi.dfWeight );
768 put_byte( info->hdr.fi.dfCharSet );
769 put_word( info->hdr.fi.dfPixWidth );
770 put_word( info->hdr.fi.dfPixHeight );
771 put_byte( info->hdr.fi.dfPitchAndFamily );
772 put_word( info->hdr.fi.dfAvgWidth );
773 put_word( info->hdr.fi.dfMaxWidth );
774 put_byte( info->hdr.fi.dfFirstChar );
775 put_byte( info->hdr.fi.dfLastChar );
776 put_byte( info->hdr.fi.dfDefaultChar );
777 put_byte( info->hdr.fi.dfBreakChar );
778 put_word( info->hdr.fi.dfWidthBytes );
779 put_dword( info->hdr.fi.dfDevice );
780 put_dword( info->hdr.fi.dfFace );
781 put_dword( info->hdr.fi.dfBitsPointer );
782 put_dword( info->hdr.fi.dfBitsOffset );
783 put_byte( info->hdr.fi.dfReserved );
784 put_dword( info->hdr.fi.dfFlags );
785 put_word( info->hdr.fi.dfAspace );
786 put_word( info->hdr.fi.dfBspace );
787 put_word( info->hdr.fi.dfCspace );
788 put_dword( info->hdr.fi.dfColorPointer );
789 put_dword( info->hdr.fi.dfReserved1[0] );
790 put_dword( info->hdr.fi.dfReserved1[1] );
791 put_dword( info->hdr.fi.dfReserved1[2] );
792 put_dword( info->hdr.fi.dfReserved1[3] );
793 num_chars = ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar) + 3;
794 for (i = 0; i < num_chars; i++)
796 put_word( info->dfCharTable[info->hdr.fi.dfFirstChar + i].width );
797 put_dword( info->dfCharTable[info->hdr.fi.dfFirstChar + i].offset );
799 put_data( info->data, info->hdr.dfSize - info->hdr.fi.dfBitsOffset );
802 static void option_callback( int optc, char *optarg )
804 switch(optc)
806 case 'd':
807 option_defchar = atoi( optarg );
808 break;
809 case 'o':
810 output_name = xstrdup( optarg );
811 break;
812 case 'q':
813 option_quiet = 1;
814 break;
815 case 'r':
816 option_dpi = atoi( optarg );
817 break;
818 case 's':
819 option_fnt_mode = 1;
820 break;
821 case 'h':
822 usage();
823 exit(0);
824 case '?':
825 fprintf( stderr, "%s: %s\n\n", argv0, optarg );
826 usage();
827 exit(1);
832 int main(int argc, char **argv)
834 int i, num_files;
835 const int typeinfo_size = 4 * sizeof(WORD);
836 const int nameinfo_size = 6 * sizeof(WORD);
837 int resource_table_len, non_resident_name_len, resident_name_len;
838 unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, font_off;
839 char resident_name[200];
840 int fontdir_len = 2;
841 char non_resident_name[200];
842 unsigned short first_res = 0x0050, res;
843 struct fontinfo **info;
844 const char *input_file;
845 struct strarray args;
847 argv0 = argv[0];
848 args = parse_options( argc, argv, "d:ho:qr:s", NULL, 0, option_callback );
850 if (!args.count)
852 usage();
853 exit(1);
855 input_file = args.str[0];
857 if(FT_Init_FreeType(&ft_library))
858 error("ft init failure\n");
860 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
861 FT_Library_Version(ft_library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
863 num_files = args.count - 1;
864 if (option_fnt_mode && num_files > 1)
865 error( "can only specify one font in .fnt mode\n" );
867 info = xmalloc( num_files * sizeof(*info) );
868 for (i = 0; i < num_files; i++)
870 int ppem, enc, avg_width;
871 const char *name;
873 if (sscanf( args.str[i + 1], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
875 usage();
876 exit(1);
878 if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
879 exit(1);
881 name = get_face_name( info[i] );
882 fontdir_len += 0x74 + strlen(name) + 1;
883 if(i == 0) {
884 sprintf(non_resident_name, "FONTRES 100,%d,%d : %s %d",
885 info[i]->hdr.fi.dfVertRes, info[i]->hdr.fi.dfHorizRes,
886 name, info[i]->hdr.fi.dfPoints );
887 strcpy(resident_name, name);
888 } else {
889 sprintf(non_resident_name + strlen(non_resident_name), ",%d", info[i]->hdr.fi.dfPoints );
893 if (option_dpi <= 108)
894 strcat(non_resident_name, " (VGA res)");
895 else
896 strcat(non_resident_name, " (8514 res)");
897 non_resident_name_len = strlen(non_resident_name) + 4;
899 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
900 resource_table_len = sizeof(WORD) /* align */ + sizeof("FONTDIR") +
901 typeinfo_size + nameinfo_size +
902 typeinfo_size + nameinfo_size * num_files +
903 typeinfo_size;
904 resource_table_off = sizeof(IMAGE_OS2_HEADER);
905 resident_name_off = resource_table_off + resource_table_len;
906 resident_name_len = strlen(resident_name) + 4;
907 module_ref_off = resident_name_off + resident_name_len;
908 non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(WORD) /* align */;
910 fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
911 font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
913 atexit( cleanup );
914 init_signals( exit_on_signal );
916 if (!output_name) /* build a default output name */
917 output_name = strmake( "%s%s", get_basename_noext( input_file ),
918 option_fnt_mode ? ".fnt" : ".fon" );
920 init_output_buffer();
921 if (option_fnt_mode)
923 put_font( info[0] );
924 goto done;
927 put_data(MZ_hdr, sizeof(MZ_hdr));
929 /* NE header */
930 put_word( 0x454e ); /* ne_magic */
931 put_byte( 5 ); /* ne_ver */
932 put_byte( 1 ); /* ne_rev */
933 put_word( module_ref_off ); /* ne_enttab */
934 put_word( 0 ); /* ne_cbenttab */
935 put_dword( 0 ); /* ne_crc */
936 put_word( 0x8300 ); /* ne_flags = NE_FFLAGS_LIBMODULE | NE_FFLAGS_GUI */
937 put_word( 0 ); /* ne_autodata */
938 put_word( 0 ); /* ne_heap */
939 put_word( 0 ); /* ne_stack */
940 put_dword( 0 ); /* ne_csip */
941 put_dword( 0 ); /* ne_sssp */
942 put_word( 0 ); /* ne_cseg */
943 put_word( 0 ); /* ne_cmod */
944 put_word( non_resident_name_len ); /* ne_cbnrestab */
945 put_word( sizeof(IMAGE_OS2_HEADER) ); /* ne_segtab */
946 put_word( sizeof(IMAGE_OS2_HEADER) ); /* ne_rsrctab */
947 put_word( resident_name_off ); /* ne_restab */
948 put_word( module_ref_off ); /* ne_modtab */
949 put_word( module_ref_off ); /* ne_imptab */
950 put_dword( non_resident_name_off ); /* ne_nrestab */
951 put_word( 0 ); /* ne_cmovent */
952 put_word( 4 ); /* ne_align */
953 put_word( 0 ); /* ne_cres */
954 put_byte( 2 ); /* ne_exetyp = NE_OSFLAGS_WINDOWS */
955 put_byte( 0 ); /* ne_flagsothers */
956 put_word( 0 ); /* ne_pretthunks */
957 put_word( 0 ); /* ne_psegrefbytes */
958 put_word( 0 ); /* ne_swaparea */
959 put_word( 0x400 ); /* ne_expver */
961 put_word( 4 ); /* align */
963 /* resources */
965 put_word( 0x8007 ); /* type_id = NE_RSCTYPE_FONTDIR */
966 put_word( 1 ); /* count */
967 put_dword( 0 ); /* resloader */
969 put_word( fontdir_off >> 4 ); /* offset */
970 put_word( (fontdir_len + 15) >> 4 ); /* length */
971 put_word( 0x0050 ); /* flags = NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD */
972 put_word( resident_name_off - sizeof("FONTDIR") - sizeof(IMAGE_OS2_HEADER) ); /* id */
973 put_word( 0 ); /* handle */
974 put_word( 0 ); /* usage */
976 put_word( 0x8008 ); /* type_id = NE_RSCTYPE_FONT */
977 put_word( num_files ); /* count */
978 put_dword( 0 ); /* resloader */
980 for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
981 int len = (info[i]->hdr.dfSize + 15) & ~0xf;
983 put_word( font_off >> 4 ); /* offset */
984 put_word( len >> 4 ); /* length */
985 put_word( 0x1030 ); /* flags = NE_SEGFLAGS_MOVEABLE|NE_SEGFLAGS_SHAREABLE|NE_SEGFLAGS_DISCARDABLE */
986 put_word( res ); /* id */
987 put_word( 0 ); /* handle */
988 put_word( 0 ); /* usage */
989 font_off += len;
992 put_word( 0 ); /* type_id */
993 put_word( 0 ); /* count */
994 put_dword( 0 ); /* resloader */
996 put_byte( strlen("FONTDIR") );
997 put_data( "FONTDIR", strlen("FONTDIR") );
998 put_byte( strlen(resident_name) );
999 put_data( resident_name, strlen(resident_name) );
1000 put_byte( 0 );
1001 put_byte( 0 );
1002 put_byte( 0 );
1003 put_byte( 0 );
1004 put_byte( 0 );
1005 put_byte( strlen(non_resident_name) );
1006 put_data( non_resident_name, strlen(non_resident_name) );
1007 put_byte( 0 );
1009 /* empty ne_modtab and ne_imptab */
1010 put_byte( 0 );
1011 put_byte( 0 );
1012 align_output( 16 );
1014 /* FONTDIR resource */
1015 put_word( num_files );
1017 for (i = 0; i < num_files; i++)
1019 put_word( first_res + i );
1020 put_fontdir( info[i] );
1022 align_output( 16 );
1024 for(i = 0; i < num_files; i++)
1026 put_font( info[i] );
1027 align_output( 16 );
1030 done:
1031 flush_output_buffer( output_name );
1032 output_name = NULL;
1033 exit(0);
1036 #else /* HAVE_FREETYPE */
1038 int main(int argc, char **argv)
1040 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
1041 exit(1);
1044 #endif /* HAVE_FREETYPE */