winebuild: Copy the strmake function from winegcc to simplify string formatting.
[wine/hramrach.git] / tools / fnt2fon.c
bloba292e50b4733099b96f28d4bb70665e390b447f4
1 /*
2 * fnttofon. Combine several fnt files in one fon file
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 <signal.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31 #include <errno.h>
32 #include <fcntl.h>
33 #ifdef HAVE_IO_H
34 # include <io.h>
35 #endif
37 #include "windef.h"
38 #include "pshpack1.h"
40 typedef struct
42 INT16 dfType;
43 INT16 dfPoints;
44 INT16 dfVertRes;
45 INT16 dfHorizRes;
46 INT16 dfAscent;
47 INT16 dfInternalLeading;
48 INT16 dfExternalLeading;
49 BYTE dfItalic;
50 BYTE dfUnderline;
51 BYTE dfStrikeOut;
52 INT16 dfWeight;
53 BYTE dfCharSet;
54 INT16 dfPixWidth;
55 INT16 dfPixHeight;
56 BYTE dfPitchAndFamily;
57 INT16 dfAvgWidth;
58 INT16 dfMaxWidth;
59 BYTE dfFirstChar;
60 BYTE dfLastChar;
61 BYTE dfDefaultChar;
62 BYTE dfBreakChar;
63 INT16 dfWidthBytes;
64 LONG dfDevice;
65 LONG dfFace;
66 LONG dfBitsPointer;
67 LONG dfBitsOffset;
68 BYTE dfReserved;
69 LONG dfFlags;
70 INT16 dfAspace;
71 INT16 dfBspace;
72 INT16 dfCspace;
73 LONG dfColorPointer;
74 LONG dfReserved1[4];
75 } FONTINFO16;
77 typedef struct
79 WORD offset;
80 WORD length;
81 WORD flags;
82 WORD id;
83 WORD handle;
84 WORD usage;
85 } NE_NAMEINFO;
87 typedef struct
89 WORD type_id;
90 WORD count;
91 DWORD resloader;
92 } NE_TYPEINFO;
94 #define NE_FFLAGS_SINGLEDATA 0x0001
95 #define NE_FFLAGS_MULTIPLEDATA 0x0002
96 #define NE_FFLAGS_WIN32 0x0010
97 #define NE_FFLAGS_FRAMEBUF 0x0100
98 #define NE_FFLAGS_CONSOLE 0x0200
99 #define NE_FFLAGS_GUI 0x0300
100 #define NE_FFLAGS_SELFLOAD 0x0800
101 #define NE_FFLAGS_LINKERROR 0x2000
102 #define NE_FFLAGS_CALLWEP 0x4000
103 #define NE_FFLAGS_LIBMODULE 0x8000
105 #define NE_OSFLAGS_WINDOWS 0x02
107 #define NE_RSCTYPE_FONTDIR 0x8007
108 #define NE_RSCTYPE_FONT 0x8008
109 #define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
111 #define NE_SEGFLAGS_DATA 0x0001
112 #define NE_SEGFLAGS_ALLOCATED 0x0002
113 #define NE_SEGFLAGS_LOADED 0x0004
114 #define NE_SEGFLAGS_ITERATED 0x0008
115 #define NE_SEGFLAGS_MOVEABLE 0x0010
116 #define NE_SEGFLAGS_SHAREABLE 0x0020
117 #define NE_SEGFLAGS_PRELOAD 0x0040
118 #define NE_SEGFLAGS_EXECUTEONLY 0x0080
119 #define NE_SEGFLAGS_READONLY 0x0080
120 #define NE_SEGFLAGS_RELOC_DATA 0x0100
121 #define NE_SEGFLAGS_SELFLOAD 0x0800
122 #define NE_SEGFLAGS_DISCARDABLE 0x1000
123 #define NE_SEGFLAGS_32BIT 0x2000
125 struct _fnt_header
127 SHORT dfVersion;
128 LONG dfSize;
129 char dfCopyright[60];
130 FONTINFO16 fi;
132 #include "poppack.h"
134 static const BYTE MZ_hdr[] = {'M', 'Z', 0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
135 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
138 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
139 'i', 's', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n', 'n', 'o',
140 't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O', 'S', ' ',
141 'm', 'o', 'd', 'e', 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
144 static const char *output_file;
146 static void cleanup_files(void)
148 if (output_file) unlink( output_file );
151 static void exit_on_signal( int sig )
153 exit(1); /* this will call the atexit functions */
156 static void usage(char **argv)
158 fprintf(stderr, "%s fntfiles output.fon\n", argv[0]);
159 return;
162 #ifndef __GNUC__
163 #define __attribute__(X)
164 #endif
166 int main(int argc, char **argv)
168 int i, j;
169 FILE *fp, *ofp;
170 long off;
171 char name[200];
172 int c;
173 char *cp;
174 short pt, ver, dpi[2], align, num_files;
175 int resource_table_len, non_resident_name_len, resident_name_len;
176 unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, font_off;
177 char resident_name[200] = "";
178 int fontdir_len = 2;
179 char non_resident_name[200] = "";
180 int *file_lens, nread;
181 unsigned short first_res = 0x0050, pad, res;
182 struct _fnt_header *fnt_header;
183 char buf[0x1000];
184 IMAGE_OS2_HEADER NE_hdr;
185 NE_TYPEINFO rc_type;
186 NE_NAMEINFO rc_name;
188 if(argc < 3) {
189 usage(argv);
190 exit(1);
193 num_files = argc - 2;
194 file_lens = malloc(num_files * sizeof(int));
195 for(i = 0; i < num_files; i++) {
196 fp = fopen(argv[i+1], "rb");
197 if(!fp) {
198 fprintf(stderr, "error: unable to open %s for reading: %s\n", argv[i+1], strerror(errno));
199 usage(argv);
200 exit(1);
202 fread(&ver, sizeof(short), 1, fp);
203 if(ver != 0x200 && ver != 0x300) {
204 fprintf(stderr, "error: invalid fnt file %s ver %d\n", argv[i+1], ver);
205 exit(1);
207 fread(file_lens + i, sizeof(int), 1, fp);
208 fseek(fp, 0x44, SEEK_SET);
209 fread(&pt, sizeof(short), 1, fp);
210 fread(dpi, sizeof(short), 2, fp);
211 fseek(fp, 0x69, SEEK_SET);
212 fread(&off, sizeof(long), 1, fp);
213 fseek(fp, off, SEEK_SET);
214 cp = name;
215 while((c = fgetc(fp)) != 0 && c != EOF)
216 *cp++ = c;
217 *cp = '\0';
218 fprintf(stderr, "%s %d pts %dx%d dpi\n", name, pt, dpi[0], dpi[1]);
219 fclose(fp);
220 /* fontdir entries for version 3 fonts are the same as for version 2 */
221 fontdir_len += 0x74 + strlen(name) + 1;
222 if(i == 0) {
223 sprintf(non_resident_name, "FONTRES 100,%d,%d : %s %d", dpi[0], dpi[1], name, pt);
224 strcpy(resident_name, name);
225 } else {
226 sprintf(non_resident_name + strlen(non_resident_name), ",%d", pt);
229 if(dpi[0] <= 108)
230 strcat(non_resident_name, " (VGA res)");
231 else
232 strcat(non_resident_name, " (8514 res)");
233 non_resident_name_len = strlen(non_resident_name) + 4;
235 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
236 resource_table_len = sizeof(align) + sizeof("FONTDIR") +
237 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) +
238 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) * num_files +
239 sizeof(NE_TYPEINFO);
240 resource_table_off = sizeof(NE_hdr);
241 resident_name_off = resource_table_off + resource_table_len;
242 resident_name_len = strlen(resident_name) + 4;
243 module_ref_off = resident_name_off + resident_name_len;
244 non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(align);
246 memset(&NE_hdr, 0, sizeof(NE_hdr));
247 NE_hdr.ne_magic = 0x454e;
248 NE_hdr.ne_ver = 5;
249 NE_hdr.ne_rev = 1;
250 NE_hdr.ne_flags = NE_FFLAGS_LIBMODULE | NE_FFLAGS_GUI;
251 NE_hdr.ne_cbnrestab = non_resident_name_len;
252 NE_hdr.ne_segtab = sizeof(NE_hdr);
253 NE_hdr.ne_rsrctab = sizeof(NE_hdr);
254 NE_hdr.ne_restab = resident_name_off;
255 NE_hdr.ne_modtab = module_ref_off;
256 NE_hdr.ne_imptab = module_ref_off;
257 NE_hdr.ne_enttab = NE_hdr.ne_modtab;
258 NE_hdr.ne_nrestab = non_resident_name_off;
259 NE_hdr.ne_align = 4;
260 NE_hdr.ne_exetyp = NE_OSFLAGS_WINDOWS;
261 NE_hdr.ne_expver = 0x400;
263 fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
264 font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
266 atexit( cleanup_files );
267 signal( SIGTERM, exit_on_signal );
268 signal( SIGINT, exit_on_signal );
269 #ifdef SIGHUP
270 signal( SIGHUP, exit_on_signal );
271 #endif
273 output_file = argv[argc - 1];
274 ofp = fopen(output_file, "wb");
276 fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
277 fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
279 align = 4;
280 fwrite(&align, sizeof(align), 1, ofp);
282 rc_type.type_id = NE_RSCTYPE_FONTDIR;
283 rc_type.count = 1;
284 rc_type.resloader = 0;
285 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
287 rc_name.offset = fontdir_off >> 4;
288 rc_name.length = (fontdir_len + 15) >> 4;
289 rc_name.flags = NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD;
290 rc_name.id = resident_name_off - sizeof("FONTDIR") - NE_hdr.ne_rsrctab;
291 rc_name.handle = 0;
292 rc_name.usage = 0;
293 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
295 rc_type.type_id = NE_RSCTYPE_FONT;
296 rc_type.count = num_files;
297 rc_type.resloader = 0;
298 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
300 for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
301 int len = (file_lens[i] + 15) & ~0xf;
303 rc_name.offset = font_off >> 4;
304 rc_name.length = len >> 4;
305 rc_name.flags = NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_SHAREABLE | NE_SEGFLAGS_DISCARDABLE;
306 rc_name.id = res;
307 rc_name.handle = 0;
308 rc_name.usage = 0;
309 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
311 font_off += len;
314 /* empty type info */
315 memset(&rc_type, 0, sizeof(rc_type));
316 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
318 fputc(strlen("FONTDIR"), ofp);
319 fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp);
320 fputc(strlen(resident_name), ofp);
321 fwrite(resident_name, strlen(resident_name), 1, ofp);
323 fputc(0x00, ofp); fputc(0x00, ofp);
324 fputc(0x00, ofp);
325 fputc(0x00, ofp); fputc(0x00, ofp);
327 fputc(strlen(non_resident_name), ofp);
328 fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
329 fputc(0x00, ofp); /* terminator */
331 /* empty ne_modtab and ne_imptab */
332 fputc(0x00, ofp);
333 fputc(0x00, ofp);
335 pad = ftell(ofp) & 0xf;
336 if(pad != 0)
337 pad = 0x10 - pad;
338 for(i = 0; i < pad; i++)
339 fputc(0x00, ofp);
341 /* FONTDIR resource */
342 fwrite(&num_files, sizeof(num_files), 1, ofp);
344 for(res = first_res, i = 0; i < num_files; i++, res++) {
345 fp = fopen(argv[i+1], "rb");
347 fwrite(&res, sizeof(res), 1, ofp);
348 fread(buf, 0x72, 1, fp);
350 fnt_header = (struct _fnt_header *)buf;
351 fseek(fp, fnt_header->fi.dfFace, SEEK_SET);
352 fnt_header->fi.dfBitsOffset = 0;
353 fwrite(buf, 0x72, 1, ofp);
355 cp = name;
356 while((c = fgetc(fp)) != 0 && c != EOF)
357 *cp++ = c;
358 *cp = '\0';
359 fwrite(name, strlen(name) + 1, 1, ofp);
360 fclose(fp);
363 pad = ftell(ofp) & 0xf;
364 if(pad != 0)
365 pad = 0x10 - pad;
366 for(i = 0; i < pad; i++)
367 fputc(0x00, ofp);
369 for(res = first_res, i = 0; i < num_files; i++, res++) {
370 fp = fopen(argv[i+1], "rb");
372 while(1) {
373 nread = read(fileno(fp), buf, sizeof(buf));
374 if(!nread) break;
375 fwrite(buf, nread, 1, ofp);
377 fclose(fp);
378 pad = file_lens[i] & 0xf;
379 if(pad != 0)
380 pad = 0x10 - pad;
381 for(j = 0; j < pad; j++)
382 fputc(0x00, ofp);
384 fclose(ofp);
385 output_file = NULL;
387 return 0;