gdi32: Fixed loop end setting (Coverity).
[wine] / tools / fnt2fon.c
1 /*
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
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
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
36
37 #include "windef.h"
38 #include "pshpack1.h"
39
40 typedef 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
77 typedef struct
78 {
79     WORD  offset;
80     WORD  length;
81     WORD  flags;
82     WORD  id;
83     WORD  handle;
84     WORD  usage;
85 } NE_NAMEINFO;
86
87 typedef 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
125 struct _fnt_header
126 {
127     SHORT dfVersion;
128     LONG dfSize;
129     char dfCopyright[60];
130     FONTINFO16 fi;
131 };
132 #include "poppack.h"
133
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
142 };
143
144 static const char *output_file;
145
146 static void cleanup_files(void)
147 {
148     if (output_file) unlink( output_file );
149 }
150
151 static void exit_on_signal( int sig )
152 {
153     exit(1);  /* this will call the atexit functions */
154 }
155
156 static void usage(char **argv)
157 {
158     fprintf(stderr, "%s fntfiles output.fon\n", argv[0]);
159     return;
160 }
161
162 #ifndef __GNUC__
163 #define __attribute__(X)
164 #endif
165
166 int main(int argc, char **argv)
167 {
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;
187
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++) {
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);
201         }
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);
206         }
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);
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 */
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);
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;
262
263     fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
264     font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
265
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
272
273     output_file = argv[argc - 1];
274     ofp = fopen(output_file, "wb");
275
276     fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
277     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
300     for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
301         int len = (file_lens[i] + 15) & ~0xf;
302
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
311         font_off += len;
312     }
313
314     /* empty type info */
315     memset(&rc_type, 0, sizeof(rc_type));
316     fwrite(&rc_type, sizeof(rc_type), 1, ofp);
317
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);
322
323     fputc(0x00, ofp);    fputc(0x00, ofp);
324     fputc(0x00, ofp);
325     fputc(0x00, ofp);    fputc(0x00, ofp);
326
327     fputc(strlen(non_resident_name), ofp);
328     fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
329     fputc(0x00, ofp); /* terminator */
330
331     /* empty ne_modtab and ne_imptab */
332     fputc(0x00, ofp);
333     fputc(0x00, ofp);
334
335     pad = ftell(ofp) & 0xf;
336     if(pad != 0)
337         pad = 0x10 - pad;
338     for(i = 0; i < pad; i++)
339         fputc(0x00, ofp);
340
341     /* FONTDIR resource */
342     fwrite(&num_files, sizeof(num_files), 1, ofp);
343     
344     for(res = first_res, i = 0; i < num_files; i++, res++) {
345         fp = fopen(argv[i+1], "rb");
346
347         fwrite(&res, sizeof(res), 1, ofp);
348         fread(buf, 0x72, 1, fp);
349
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);
354
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);
361     }
362
363     pad = ftell(ofp) & 0xf;
364     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++) {
370         fp = fopen(argv[i+1], "rb");
371
372         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);
385     output_file = NULL;
386
387     return 0;
388 }