blob: a292e50b4733099b96f28d4bb70665e390b447f4 [file] [log] [blame]
Huw Davies00acb5f2004-08-17 22:33:14 +00001/*
2 * fnttofon. Combine several fnt files in one fon file
3 *
4 * Copyright 2004 Huw Davies
5 *
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.
10 *
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.
15 *
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
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Huw Davies00acb5f2004-08-17 22:33:14 +000019 */
20
Dmitry Timoshkovdace4662005-05-20 09:41:49 +000021#include "config.h"
Alexandre Julliard49b7fdc2005-08-03 21:25:10 +000022#include "wine/port.h"
Dmitry Timoshkovdace4662005-05-20 09:41:49 +000023
Alexandre Julliard411fe292006-05-27 13:24:13 +020024#include <signal.h>
Huw Davies00acb5f2004-08-17 22:33:14 +000025#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
Dmitry Timoshkovdace4662005-05-20 09:41:49 +000028#ifdef HAVE_UNISTD_H
29# include <unistd.h>
30#endif
Francois Gougeteb9c53a2007-10-18 17:05:11 +020031#include <errno.h>
Dmitry Timoshkovdace4662005-05-20 09:41:49 +000032#include <fcntl.h>
33#ifdef HAVE_IO_H
34# include <io.h>
35#endif
Huw Davies00acb5f2004-08-17 22:33:14 +000036
Alexandre Julliard1f220db2009-08-29 21:06:19 +020037#include "windef.h"
Dmitry Timoshkovdace4662005-05-20 09:41:49 +000038#include "pshpack1.h"
Alexandre Julliard1f220db2009-08-29 21:06:19 +020039
40typedef struct
41{
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;
76
77typedef struct
78{
79 WORD offset;
80 WORD length;
81 WORD flags;
82 WORD id;
83 WORD handle;
84 WORD usage;
85} NE_NAMEINFO;
86
87typedef struct
88{
89 WORD type_id;
90 WORD count;
91 DWORD resloader;
92} NE_TYPEINFO;
93
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
104
105#define NE_OSFLAGS_WINDOWS 0x02
106
107#define NE_RSCTYPE_FONTDIR 0x8007
108#define NE_RSCTYPE_FONT 0x8008
109#define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
110
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
124
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000125struct _fnt_header
126{
Dmitry Timoshkov7ab35472008-04-11 16:56:33 +0900127 SHORT dfVersion;
128 LONG dfSize;
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000129 char dfCopyright[60];
130 FONTINFO16 fi;
131};
132#include "poppack.h"
133
134static const BYTE MZ_hdr[] = {'M', 'Z', 0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
Huw Davies00acb5f2004-08-17 22:33:14 +0000135 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
142};
143
Alexandre Julliard411fe292006-05-27 13:24:13 +0200144static const char *output_file;
145
146static void cleanup_files(void)
147{
148 if (output_file) unlink( output_file );
149}
150
151static void exit_on_signal( int sig )
152{
153 exit(1); /* this will call the atexit functions */
154}
155
Huw Davies00acb5f2004-08-17 22:33:14 +0000156static void usage(char **argv)
157{
158 fprintf(stderr, "%s fntfiles output.fon\n", argv[0]);
159 return;
160}
161
Vincent Béron2e5da5f2005-12-07 12:44:17 +0100162#ifndef __GNUC__
163#define __attribute__(X)
164#endif
165
Huw Davies00acb5f2004-08-17 22:33:14 +0000166int main(int argc, char **argv)
167{
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000168 int i, j;
Huw Davies00acb5f2004-08-17 22:33:14 +0000169 FILE *fp, *ofp;
170 long off;
171 char name[200];
172 int c;
173 char *cp;
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000174 short pt, ver, dpi[2], align, num_files;
Huw Davies00acb5f2004-08-17 22:33:14 +0000175 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] = "";
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000178 int fontdir_len = 2;
Huw Davies00acb5f2004-08-17 22:33:14 +0000179 char non_resident_name[200] = "";
180 int *file_lens, nread;
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000181 unsigned short first_res = 0x0050, pad, res;
182 struct _fnt_header *fnt_header;
Huw Davies00acb5f2004-08-17 22:33:14 +0000183 char buf[0x1000];
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000184 IMAGE_OS2_HEADER NE_hdr;
185 NE_TYPEINFO rc_type;
186 NE_NAMEINFO rc_name;
Huw Davies00acb5f2004-08-17 22:33:14 +0000187
188 if(argc < 3) {
189 usage(argv);
190 exit(1);
191 }
192
193 num_files = argc - 2;
194 file_lens = malloc(num_files * sizeof(int));
195 for(i = 0; i < num_files; i++) {
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000196 fp = fopen(argv[i+1], "rb");
Huw Davies00acb5f2004-08-17 22:33:14 +0000197 if(!fp) {
Francois Gougeteb9c53a2007-10-18 17:05:11 +0200198 fprintf(stderr, "error: unable to open %s for reading: %s\n", argv[i+1], strerror(errno));
Huw Davies00acb5f2004-08-17 22:33:14 +0000199 usage(argv);
200 exit(1);
201 }
202 fread(&ver, sizeof(short), 1, fp);
203 if(ver != 0x200 && ver != 0x300) {
Francois Gougeteb9c53a2007-10-18 17:05:11 +0200204 fprintf(stderr, "error: invalid fnt file %s ver %d\n", argv[i+1], ver);
205 exit(1);
Huw Davies00acb5f2004-08-17 22:33:14 +0000206 }
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);
Dmitry Timoshkovac2096d2005-05-23 09:51:12 +0000220 /* fontdir entries for version 3 fonts are the same as for version 2 */
221 fontdir_len += 0x74 + strlen(name) + 1;
Huw Davies00acb5f2004-08-17 22:33:14 +0000222 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);
227 }
228 }
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;
234
235 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000236 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);
Huw Davies00acb5f2004-08-17 22:33:14 +0000241 resident_name_off = resource_table_off + resource_table_len;
Huw Davies00acb5f2004-08-17 22:33:14 +0000242 resident_name_len = strlen(resident_name) + 4;
243 module_ref_off = resident_name_off + resident_name_len;
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000244 non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(align);
245
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;
Huw Davies00acb5f2004-08-17 22:33:14 +0000262
263 fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
264 font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000265
Alexandre Julliard411fe292006-05-27 13:24:13 +0200266 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
272
273 output_file = argv[argc - 1];
274 ofp = fopen(output_file, "wb");
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000275
Huw Davies00acb5f2004-08-17 22:33:14 +0000276 fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000277 fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
278
279 align = 4;
280 fwrite(&align, sizeof(align), 1, ofp);
281
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);
286
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);
294
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);
299
Huw Davies00acb5f2004-08-17 22:33:14 +0000300 for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
301 int len = (file_lens[i] + 15) & ~0xf;
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000302
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);
310
Huw Davies00acb5f2004-08-17 22:33:14 +0000311 font_off += len;
Huw Davies00acb5f2004-08-17 22:33:14 +0000312 }
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000313
314 /* empty type info */
315 memset(&rc_type, 0, sizeof(rc_type));
316 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
317
Huw Davies00acb5f2004-08-17 22:33:14 +0000318 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);
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000322
Huw Davies00acb5f2004-08-17 22:33:14 +0000323 fputc(0x00, ofp); fputc(0x00, ofp);
324 fputc(0x00, ofp);
325 fputc(0x00, ofp); fputc(0x00, ofp);
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000326
Huw Davies00acb5f2004-08-17 22:33:14 +0000327 fputc(strlen(non_resident_name), ofp);
328 fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000329 fputc(0x00, ofp); /* terminator */
330
331 /* empty ne_modtab and ne_imptab */
Huw Davies00acb5f2004-08-17 22:33:14 +0000332 fputc(0x00, ofp);
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000333 fputc(0x00, ofp);
334
335 pad = ftell(ofp) & 0xf;
Huw Davies00acb5f2004-08-17 22:33:14 +0000336 if(pad != 0)
337 pad = 0x10 - pad;
338 for(i = 0; i < pad; i++)
339 fputc(0x00, ofp);
340
341 /* FONTDIR resource */
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000342 fwrite(&num_files, sizeof(num_files), 1, ofp);
Huw Davies00acb5f2004-08-17 22:33:14 +0000343
344 for(res = first_res, i = 0; i < num_files; i++, res++) {
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000345 fp = fopen(argv[i+1], "rb");
346
347 fwrite(&res, sizeof(res), 1, ofp);
348 fread(buf, 0x72, 1, fp);
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000349
350 fnt_header = (struct _fnt_header *)buf;
351 fseek(fp, fnt_header->fi.dfFace, SEEK_SET);
Dmitry Timoshkovac2096d2005-05-23 09:51:12 +0000352 fnt_header->fi.dfBitsOffset = 0;
353 fwrite(buf, 0x72, 1, ofp);
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000354
Huw Davies00acb5f2004-08-17 22:33:14 +0000355 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);
361 }
Dmitry Timoshkovac2096d2005-05-23 09:51:12 +0000362
363 pad = ftell(ofp) & 0xf;
Huw Davies00acb5f2004-08-17 22:33:14 +0000364 if(pad != 0)
365 pad = 0x10 - pad;
366 for(i = 0; i < pad; i++)
367 fputc(0x00, ofp);
368
369 for(res = first_res, i = 0; i < num_files; i++, res++) {
Dmitry Timoshkovdace4662005-05-20 09:41:49 +0000370 fp = fopen(argv[i+1], "rb");
371
Huw Davies00acb5f2004-08-17 22:33:14 +0000372 while(1) {
373 nread = read(fileno(fp), buf, sizeof(buf));
374 if(!nread) break;
375 fwrite(buf, nread, 1, ofp);
376 }
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);
383 }
384 fclose(ofp);
Alexandre Julliard411fe292006-05-27 13:24:13 +0200385 output_file = NULL;
Huw Davies00acb5f2004-08-17 22:33:14 +0000386
387 return 0;
388}