~ubuntu-branches/ubuntu/jaunty/luatex/jaunty

« back to all changes in this revision

Viewing changes to src/libs/luafontforge/fontforge/fontforge/macbinary.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2007-09-24 12:56:11 UTC
  • Revision ID: james.westby@ubuntu.com-20070924125611-a8ge689azbptxvla
Tags: upstream-0.11.2
ImportĀ upstreamĀ versionĀ 0.11.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2007 by George Williams */
 
2
/*
 
3
 * Redistribution and use in source and binary forms, with or without
 
4
 * modification, are permitted provided that the following conditions are met:
 
5
 
 
6
 * Redistributions of source code must retain the above copyright notice, this
 
7
 * list of conditions and the following disclaimer.
 
8
 
 
9
 * Redistributions in binary form must reproduce the above copyright notice,
 
10
 * this list of conditions and the following disclaimer in the documentation
 
11
 * and/or other materials provided with the distribution.
 
12
 
 
13
 * The name of the author may not be used to endorse or promote products
 
14
 * derived from this software without specific prior written permission.
 
15
 
 
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 
17
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
18
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 
19
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
20
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
21
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
22
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
23
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
24
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
25
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
26
 */
 
27
#include "pfaeditui.h"
 
28
#include <stdlib.h>
 
29
#include <string.h>
 
30
#include <unistd.h>
 
31
#include <math.h>
 
32
#include <sys/types.h>
 
33
#include <sys/stat.h>
 
34
#include <time.h>
 
35
#include <ustring.h>
 
36
#include "ttf.h"
 
37
#include "psfont.h"
 
38
#if __Mac
 
39
# include <ctype.h>
 
40
# include </Developer/Headers/FlatCarbon/Files.h>
 
41
#else
 
42
# include <utype.h>
 
43
#undef __Mac
 
44
#define __Mac 0
 
45
#endif
 
46
 
 
47
 
 
48
#ifdef LUA_FF_LIB
 
49
/* no need for iconv here, since PS is 8-bit legacy */
 
50
#define Isspace(a) ((a)==' '|| ((a) >= '\t' &&  (a) <= '\r'))
 
51
#define Isdigit(a) ((a)>='0' && (a)<='9')
 
52
#define Isalpha(a) (((a)>='a' && (a)<='z') || ((a)>='A' && (a)<='Z'))
 
53
#define Islower(a) ((a)>='a' && (a)<='z')
 
54
#define Isupper(a) ((a)>='A' && (a)<='Z')
 
55
#define Isalnum(a) (Isalpha(a)||Isdigit(a))
 
56
#define Ishexdigit(a) (((a)>='0' && (a)<='9')||((a)>='a' && (a)<='f')||((a)>='A' && (a)<='F'))
 
57
static int Tolower (int c) {
 
58
  if (Isupper(c))
 
59
    return c-32;
 
60
  else 
 
61
    return c;
 
62
}
 
63
#else
 
64
#define Islower islower
 
65
#define Tolower tolower
 
66
#define Isspace isspace
 
67
#define Isdigit isdigit
 
68
#define Isalpha isalpha
 
69
#define Isalnum isalnum
 
70
#define Ishexdigit ishexdigit
 
71
#endif
 
72
 
 
73
 
 
74
 
 
75
 
 
76
const int mac_dpi = 72;
 
77
/* I had always assumed that the mac still believed in 72dpi screens, but I */
 
78
/*  see that in geneva under OS/9, the pointsize does not match the pixel */
 
79
/*  size of the font. But the dpi is not constant (and the differences */
 
80
/*  excede those supplied by rounding errors) varying between 96 and 84dpi */
 
81
 
 
82
/* A Mac Resource fork */
 
83
/*  http://developer.apple.com/techpubs/mac/MoreToolbox/MoreToolbox-9.html */
 
84
/*    begins with a 16 byte header containing: */
 
85
/*      resource start offset */
 
86
/*      map start offset */
 
87
/*      resource length */
 
88
/*      map length */
 
89
/*    then 256-16 bytes of zeros */
 
90
/*    the resource section consists of (many) */
 
91
/*      4 byte length count */
 
92
/*      resource data   */
 
93
/*    the map section contains */
 
94
/*      A copy of the 16 byte header */
 
95
/*      a 4 byte mac internal value (I hope) */
 
96
/*      another 4 bytes of mac internal values (I hope) */
 
97
/*      a 2 byte offset from the start of the map section to the list of resource types */
 
98
/*      a 2 byte offset from the start of the map section to the list of resource names */
 
99
/*      The resource type list consists of */
 
100
/*          a 2 byte count of the number of resource types (-1) */
 
101
/*          (many copies of) */
 
102
/*              a 4 byte resource type ('FOND' for example) */
 
103
/*              a 2 byte count of the number of resources of this type (-1) */
 
104
/*              a 2 byte offset from the type list start to the resource table */
 
105
/*          a resource table looks like */
 
106
/*              a 2 byte offset from the resource name table to a pascal */
 
107
/*                      string containing this resource's name (or 0xffff for none) */
 
108
/*              1 byte of resource flags */
 
109
/*              3 bytes of offset from the resource section to the length & */
 
110
/*                      data of this instance of the resource type */
 
111
/*              4 bytes of 0 */
 
112
/*      The resource name section consists of */
 
113
/*          a bunch of pascal strings (ie. preceded by a length byte) */
 
114
 
 
115
/* The POST resource isn't noticeably documented, it's pretty much a */
 
116
/*  straight copy of the pfb file cut up into 0x800 byte chunks. */
 
117
/*  (each section of the pfb file has it's own set of chunks, the last may be smaller than 0x800) */
 
118
/* The NFNT resource http://developer.apple.com/techpubs/mac/Text/Text-250.html */
 
119
/* The FOND resource http://developer.apple.com/techpubs/mac/Text/Text-269.html */
 
120
/* The sfnt resource is basically a copy of the ttf file */
 
121
 
 
122
/* A MacBinary file */
 
123
/*  http://www.lazerware.com/formats/macbinary.html */
 
124
/*    begins with a 128 byte header */
 
125
/*      (which specifies lengths for data/resource forks) */
 
126
/*      (and contains mac type/creator data) */
 
127
/*      (and other stuff) */
 
128
/*      (and finally a crc checksum) */
 
129
/*    is followed by the data section (padded to a mult of 128 bytes) */
 
130
/*    is followed by the resource section (padded to a mult of 128 bytes) */
 
131
 
 
132
/* Crc code taken from: */
 
133
/* http://www.ctan.org/tex-archive/tools/macutils/crc/ */
 
134
/* MacBinary files use the same CRC that binhex does (in the MacBinary header) */
 
135
extern unsigned long binhex_crc(unsigned char *buffer,int size);
 
136
 
 
137
/* ******************************** Creation ******************************** */
 
138
 
 
139
#ifndef LUA_FF_LIB
 
140
static uint16 HashToId(char *fontname,SplineFont *sf,EncMap *map) {
 
141
    int low = 128, high = 0x3fff;
 
142
    /* A FOND ID should be between these two numbers for roman script (I think) */
 
143
    uint32 hash = 0;
 
144
    int i, gid;
 
145
    SplineChar *sc;
 
146
 
 
147
    /* Figure out what language we've got */
 
148
    /*  I'm not bothering with all of the apple scripts, and I don't know */
 
149
    /*  what to do about cjk fonts */
 
150
    if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) {
 
151
        if ( sf->cidmaster != NULL ) sf = sf->cidmaster;
 
152
        if ( sf->ordering != NULL ) {
 
153
            if ( strstrmatch(sf->ordering,"Japan")!=NULL ) {
 
154
                low = 0x4000; high = 0x41ff;
 
155
            } else if ( strstrmatch(sf->ordering,"Korea")!=NULL ) {
 
156
                low = 0x4400; high = 0x45ff;
 
157
            } else if ( strstrmatch(sf->ordering,"CNS")!=NULL ) {
 
158
                low = 0x4200; high = 0x43ff;
 
159
            } else if ( strstrmatch(sf->ordering,"GB")!=NULL ) {
 
160
                low = 0x7200; high = 0x73ff;
 
161
            }
 
162
        }
 
163
    } else if ( map->enc->is_tradchinese ) {
 
164
        low = 0x4200; high = 0x43ff;
 
165
    } else if ( map->enc->is_japanese ) {
 
166
        low = 0x4000; high = 0x41ff;
 
167
    } else if ( map->enc->is_korean ) {
 
168
        low = 0x4400; high = 0x45ff;
 
169
    } else if ( map->enc->is_simplechinese ) {
 
170
        low = 0x7200; high = 0x73ff;
 
171
    } else for ( i=0; i<map->enccount && i<256; ++i ) if ( (gid=map->map[i])!=-1 && (sc = sf->glyphs[gid])!=NULL ) {
 
172
        /* Japanese between     0x4000 and 0x41ff */
 
173
        /* Trad Chinese         0x4200 and 0x43ff */
 
174
        /*  Simp Chinese        0x7200 and 0x73ff */
 
175
        /* Korean               0x4400 and 0x45ff */
 
176
        if (( sc->unicodeenc>=0x0600 && sc->unicodeenc<0x0700 ) ||
 
177
                ( sc->unicodeenc>=0xFB50 && sc->unicodeenc<0xfe00 )) {
 
178
            /* arabic */
 
179
            low = 0x4600; high = 0x47ff;
 
180
    break;
 
181
        } else if (( sc->unicodeenc>=0x0590 && sc->unicodeenc<0x0600 ) ||
 
182
                ( sc->unicodeenc>=0xFB1d && sc->unicodeenc<0xFB50 )) {
 
183
            /* hebrew */
 
184
            low = 0x4800; high = 0x49ff;
 
185
    break;
 
186
        } else if ((( sc->unicodeenc>=0x0370 && sc->unicodeenc<0x0400 ) ||
 
187
                ( sc->unicodeenc>=0x1f00 && sc->unicodeenc<0x2000 )) &&
 
188
                sc->unicodeenc!=0x3c0 ) {       /* In mac encoding */
 
189
            /* greek */
 
190
            low = 0x4a00; high = 0x4bff;
 
191
    break;
 
192
        } else if ( sc->unicodeenc>=0x0400 && sc->unicodeenc<0x0530 ) {
 
193
            /* cyrillic */
 
194
            low = 0x4c00; high = 0x4dff;
 
195
    break;
 
196
        /* hebrew/arabic symbols 4e00-4fff */
 
197
        } else if ( sc->unicodeenc>=0x0900 && sc->unicodeenc<0x0980 ) {
 
198
            /* devanagari */
 
199
            low = 0x5000; high = 0x51ff;
 
200
    break;
 
201
        } else if ( sc->unicodeenc>=0x0980 && sc->unicodeenc<0x0a00 ) {
 
202
            /* bengali: script=13 */
 
203
            low = 0x5800; high = 0x59ff;
 
204
    break;
 
205
        }
 
206
    }
 
207
    while ( *fontname ) {
 
208
        int temp = (hash>>28)&0xf;
 
209
        hash = (hash<<4) | temp;
 
210
        hash ^= *fontname++-' ';
 
211
    }
 
212
    hash %= (high-low+1);
 
213
    hash += low;
 
214
return( hash );
 
215
}
 
216
 
 
217
static int IsMacMonospaced(SplineFont *sf,EncMap *map) {
 
218
    /* Only look at first 256 */
 
219
    int i;
 
220
    double width = 0x80000000;
 
221
 
 
222
    for ( i=0; i<256 && i<map->enccount; ++i ) {
 
223
        int gid = map->map[i];
 
224
        if ( gid!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
 
225
            if ( width == 0x80000000 )
 
226
                width = sf->glyphs[gid]->width;
 
227
            else if ( sf->glyphs[gid]->width!=width )
 
228
return( false );
 
229
        }
 
230
    }
 
231
return( true );
 
232
}
 
233
 
 
234
SplineChar *SFFindExistingCharMac(SplineFont *sf,EncMap *map,int unienc) {
 
235
    int i, gid;
 
236
 
 
237
    for ( i=0; i<map->enccount && i<256; ++i )
 
238
        if ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && sf->glyphs[gid]->unicodeenc==unienc )
 
239
return( sf->glyphs[gid] );
 
240
return( NULL );
 
241
}
 
242
 
 
243
static double SFMacWidthMax(SplineFont *sf, EncMap *map) {
 
244
    /* Only look at first 256 */
 
245
    int i, gid;
 
246
    double width = -1;
 
247
 
 
248
    for ( i=0; i<256 && i<map->enccount; ++i ) {
 
249
        if ( (gid=map->map[i])!=-1 && SCWorthOutputting(sf->glyphs[gid]) ) {
 
250
            if ( sf->glyphs[gid]->width>width )
 
251
                width = sf->glyphs[gid]->width;
 
252
        }
 
253
    }
 
254
    if ( width<0 )      /* No chars, or widths the mac doesn't support */
 
255
return( 0 );
 
256
 
 
257
return( width );
 
258
}
 
259
 
 
260
static int SFMacAnyKerns(SplineFont *sf, EncMap *map) {
 
261
    /* Only look at first 256 */
 
262
    int i, cnt=0, gid;
 
263
    KernPair *kp;
 
264
 
 
265
    for ( i=0; i<256 && i<map->enccount; ++i ) {
 
266
        if ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
 
267
            for ( kp=sf->glyphs[gid]->kerns; kp!=NULL; kp=kp->next )
 
268
                if ( map->backmap[kp->sc->orig_pos]<256 )
 
269
                    ++cnt;
 
270
        }
 
271
    }
 
272
return( cnt );
 
273
}
 
274
 
 
275
struct resource {
 
276
    uint32 pos;
 
277
    uint8 flags;
 
278
    uint16 id;
 
279
    char *name;
 
280
    uint32 nameloc;
 
281
    uint32 nameptloc;
 
282
};
 
283
 
 
284
struct resourcetype {
 
285
    uint32 tag;
 
286
    struct resource *res;
 
287
    uint32 resloc;
 
288
};
 
289
 
 
290
struct macbinaryheader {
 
291
    char *macfilename;
 
292
    char *binfilename;          /* if macfilename is null and this is set we will figure out macfilename by removing .bin */
 
293
    uint32 type;
 
294
    uint32 creator;
 
295
};
 
296
            
 
297
static struct resource *PSToResources(FILE *res,FILE *pfbfile) {
 
298
    /* split the font up into as many small resources as we need and return */
 
299
    /*  an array pointing to the start of each */
 
300
    struct stat statb;
 
301
    int cnt, type;
 
302
    struct resource *resstarts;
 
303
    int len,i;
 
304
 
 
305
    fstat(fileno(pfbfile),&statb);
 
306
    cnt = 3*(statb.st_size+0x800)/(0x800-2)+1;          /* should be (usually) a vast over estimate */
 
307
    resstarts = gcalloc(cnt+1,sizeof(struct resource));
 
308
 
 
309
    cnt = 0;
 
310
    forever {
 
311
        if ( getc(pfbfile)!=0x80 ) {
 
312
            IError("We made a pfb file, but didn't get one. Hunh?" );
 
313
return( NULL );
 
314
        }
 
315
        type = getc(pfbfile);
 
316
        if ( type==3 ) {
 
317
        /* 501 appears to be magic */
 
318
        /* postscript resources seem to have flags of 0 */
 
319
            resstarts[cnt].id = 501+cnt;
 
320
            resstarts[cnt++].pos = ftell(res);
 
321
            putlong(res,2);     /* length */
 
322
            putc(5,res);        /* eof mark */
 
323
            putc(0,res);
 
324
    break;
 
325
        }
 
326
        len = getc(pfbfile);
 
327
        len |= (getc(pfbfile))<<8;
 
328
        len |= (getc(pfbfile))<<16;
 
329
        len |= (getc(pfbfile))<<24;
 
330
        while ( len>0 ) {
 
331
            int ilen = len;
 
332
            if ( ilen>0x800-2 )
 
333
                ilen = 0x800-2;
 
334
            len -= ilen;
 
335
            resstarts[cnt].id = 501+cnt;
 
336
            resstarts[cnt++].pos = ftell(res);
 
337
            putlong(res,ilen+2);        /* length */
 
338
            putc(type,res);             /* section type mark */
 
339
            putc(0,res);
 
340
            for ( i=0; i<ilen; ++i )
 
341
                putc(getc(pfbfile),res);
 
342
        }
 
343
    }
 
344
    resstarts[cnt].pos = 0;
 
345
return( resstarts );
 
346
}
 
347
            
 
348
static uint32 TTFToResource(FILE *res,FILE *ttffile) {
 
349
    /* A truetype font just gets dropped into a resource */
 
350
    struct stat statb;
 
351
    int ch;
 
352
    uint32 resstart;
 
353
 
 
354
    fstat(fileno(ttffile),&statb);
 
355
    resstart = ftell(res);
 
356
 
 
357
    putlong(res,statb.st_size);
 
358
    while ( (ch=getc(ttffile))!=EOF )
 
359
        putc(ch,res);
 
360
return( resstart );
 
361
}
 
362
 
 
363
static int BDFCCopyBitmaps(uint8 **rows,int offset,BDFChar *bdfc, BDFFont *bdf) {
 
364
    int i, r, y, ipos, j, c;
 
365
 
 
366
    y = bdf->ascent-1; r = i = 0;
 
367
    if ( bdfc->ymax > bdf->ascent-1 )
 
368
        i = bdfc->ymax-(bdf->ascent-1);
 
369
    else if ( bdfc->ymax<bdf->ascent-1 ) {
 
370
        r = bdf->ascent-1-bdfc->ymax;
 
371
        y = bdfc->ymax;
 
372
    }
 
373
    for ( ; y>=bdfc->ymin && y>=-bdf->descent; --y, ++i ) {
 
374
        /* Mac characters may not extend above the ascent or below the descent */
 
375
        /*  but bdf chars can, so if a bdf char does, just ignore that part */
 
376
        ipos = i*bdfc->bytes_per_line;
 
377
        for ( j=0,c=offset; j<=bdfc->xmax-bdfc->xmin; ++j, ++c ) {
 
378
            if ( bdfc->bitmap[ipos+(j>>3)] & (1<<(7-(j&7))) )
 
379
                rows[r][c>>3] |= (1<<(7-(c&7)));
 
380
        }
 
381
        ++r;
 
382
    }
 
383
return( offset + bdfc->xmax-bdfc->xmin+1 );
 
384
}
 
385
 
 
386
static uint32 BDFToNFNT(FILE *res, BDFFont *bdf, EncMap *map) {
 
387
    short widths[258], lbearings[258], locs[258]/*, idealwidths[256]*/;
 
388
    uint8 **rows = galloc(bdf->pixelsize*sizeof(uint8 *));
 
389
    int i, k, width, kernMax=1, descentMax=bdf->descent-1, rectMax=1, widMax=3;
 
390
    uint32 rlenpos = ftell(res), end, owloc, owpos;
 
391
    int gid;
 
392
 
 
393
    for ( i=width=0; i<256 && i<map->enccount; ++i ) {
 
394
        if ( (gid = map->map[i])!=-1 && gid<bdf->glyphcnt && bdf->glyphs[gid]!=NULL ) {
 
395
            width += bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
 
396
            if ( bdf->glyphs[gid]->width>widMax )
 
397
                widMax = bdf->glyphs[gid]->width;
 
398
            if ( bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin>rectMax )
 
399
                rectMax = bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
 
400
            if ( bdf->glyphs[gid]->xmin<kernMax )
 
401
                kernMax = bdf->glyphs[gid]->xmin;
 
402
            if ( bdf->glyphs[gid]->ymin<-descentMax )
 
403
                descentMax = -bdf->glyphs[gid]->ymin;
 
404
        }
 
405
    }
 
406
    if ( descentMax>bdf->descent ) descentMax = bdf->descent;
 
407
    ++width;                    /* For the "undefined character */
 
408
    for ( k=0; k<bdf->pixelsize; ++k )
 
409
        rows[k] = gcalloc((width+7)/8 + 4 , sizeof(uint8));
 
410
    for ( i=width=0; i<256 ; ++i ) {
 
411
        locs[i] = width;
 
412
        if ( i>=map->enccount || (gid=map->map[i])==-1 || gid>=bdf->glyphcnt || bdf->glyphs[gid]==NULL ||
 
413
                !SCWorthOutputting(bdf->glyphs[gid]->sc) ) {
 
414
            lbearings[i] = 0xff;
 
415
            widths[i] = 0xff;
 
416
            /*idealwidths[i] = 1<<12; */                /* 1 em */
 
417
        } else {
 
418
            lbearings[i] = bdf->glyphs[gid]->xmin-kernMax;
 
419
            widths[i] = bdf->glyphs[gid]->width<0?0:
 
420
                        bdf->glyphs[gid]->width>=256?255:
 
421
                        bdf->glyphs[gid]->width;
 
422
            /*idealwidths[i] = bdf->glyphs[gid]->sc->width*(1<<12)/(bdf->sf->ascent+bdf->sf->descent);*/
 
423
            width = BDFCCopyBitmaps(rows,width,bdf->glyphs[gid],bdf);
 
424
        }
 
425
    }
 
426
    /* Now for the "undefined character", just a simple vertical bar */
 
427
    locs[i] = width;
 
428
    lbearings[i] = 1;
 
429
    widths[i++] = 3;
 
430
    /*idealwidths[i++] = (3<<12)/bdf->pixelsize;*/
 
431
    for ( k = 1; k<bdf->pixelsize-1; ++k )
 
432
        rows[k][width>>3] |= (1<<(7-(width&7)));
 
433
    /* And one more entry to give a size to the last character */
 
434
    locs[i] = ++width;
 
435
    lbearings[i] = widths[i] = 0xff;
 
436
    /*idealwidths[i] = 0;*/
 
437
 
 
438
    /* Mac magic */
 
439
    lbearings[0] = widths[0] = 0;
 
440
    lbearings['\r'] = widths['\r'] = 0;
 
441
    lbearings['\t'] = 0; widths['\t'] = 6;
 
442
 
 
443
    /* We've finished the bitmap conversion, now save it... */
 
444
    putlong(res,0);             /* Length, to be filled in later */
 
445
    putshort(res,IsMacMonospaced(bdf->sf,map)?0xb000:0x9000);   /* fontType */
 
446
    putshort(res,0);
 
447
    putshort(res,255);
 
448
    putshort(res,widMax);
 
449
    putshort(res,kernMax);
 
450
    putshort(res,-descentMax);
 
451
    putshort(res,rectMax);
 
452
    putshort(res,bdf->pixelsize);
 
453
    owpos = ftell(res);
 
454
    putshort(res,0);
 
455
    putshort(res,bdf->ascent);
 
456
    putshort(res,bdf->descent);
 
457
    putshort(res,(short) (bdf->sf->pfminfo.linegap*bdf->pixelsize/(bdf->sf->ascent+bdf->sf->descent)) );
 
458
    putshort(res,(width+15)>>4);
 
459
    /* bitmaps */
 
460
    for ( k=0; k<bdf->pixelsize; ++k ) {
 
461
        for ( i=0; i<((width+15)>>4) ; ++i ) {
 
462
            putc(rows[k][2*i],res);
 
463
            putc(rows[k][2*i+1],res);
 
464
        }
 
465
    }
 
466
    for ( i=0; i<258; ++i )
 
467
        putshort(res,locs[i]);
 
468
    owloc = ftell(res);                 /* valgrind reports an error here (but not above). god knows why */
 
469
    for ( i=0; i<258; ++i ) {
 
470
        putc(lbearings[i],res);
 
471
        putc(widths[i],res);
 
472
    }
 
473
    end = ftell(res);
 
474
    fseek(res,rlenpos,SEEK_SET);
 
475
    putlong(res,end-rlenpos-4);
 
476
    fseek(res,owpos,SEEK_SET);
 
477
    putshort(res,(owloc-owpos)/2);
 
478
    fseek(res,0,SEEK_END);
 
479
 
 
480
    for ( k=0; k<bdf->pixelsize; ++k )
 
481
        free(rows[k]);
 
482
    free(rows);
 
483
 
 
484
return(rlenpos);
 
485
}
 
486
 
 
487
static uint32 DummyNFNT(FILE *res, BDFFont *bdf, EncMap *map) {
 
488
    /* This produces a stub NFNT which appears when the real data lives inside */
 
489
    /*  an sfnt (truetype) resource. We still need to produce an NFNT to tell */
 
490
    /*  the system that the pointsize is available. This NFNT has almost nothing */
 
491
    /*  in it, just the initial header, no metrics, no bitmaps */
 
492
    int i, width, kernMax=1, descentMax=bdf->descent-1, rectMax=1, widMax=3;
 
493
    uint32 rlenpos = ftell(res);
 
494
    int gid;
 
495
 
 
496
    for ( i=width=0; i<256 && i<map->enccount; ++i ) if ( (gid=map->map[i])!=-1 && gid<bdf->glyphcnt && bdf->glyphs[gid]!=NULL ) {
 
497
        width += bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
 
498
        if ( bdf->glyphs[gid]->width>widMax )
 
499
            widMax = bdf->glyphs[gid]->width;
 
500
        if ( bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin>rectMax )
 
501
            rectMax = bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
 
502
        if ( bdf->glyphs[gid]->xmin<kernMax )
 
503
            kernMax = bdf->glyphs[gid]->xmin;
 
504
        if ( bdf->glyphs[gid]->ymin<-descentMax )
 
505
            descentMax = -bdf->glyphs[gid]->ymin;
 
506
    }
 
507
    if ( descentMax>bdf->descent ) descentMax = bdf->descent;
 
508
 
 
509
    putlong(res,26);            /* Length */
 
510
    putshort(res,SFOneWidth(bdf->sf)!=-1?0xf000:0xd000);        /* fontType */
 
511
    putshort(res,0);
 
512
    putshort(res,255);
 
513
    putshort(res,widMax);
 
514
    putshort(res,kernMax);
 
515
    putshort(res,-descentMax);
 
516
    putshort(res,rectMax);
 
517
    putshort(res,bdf->pixelsize);
 
518
    putshort(res,0);
 
519
    putshort(res,bdf->ascent);
 
520
    putshort(res,bdf->descent);
 
521
    putshort(res,(short) (bdf->sf->pfminfo.linegap*bdf->pixelsize/(bdf->sf->ascent+bdf->sf->descent)) );
 
522
    putshort(res,0);
 
523
 
 
524
return(rlenpos);
 
525
}
 
526
 
 
527
static struct resource *SFToNFNTs(FILE *res, SplineFont *sf, int32 *sizes,
 
528
        EncMap *map) {
 
529
    int i, baseresid = HashToId(sf->fontname,sf,map);
 
530
    struct resource *resstarts;
 
531
    BDFFont *bdf;
 
532
 
 
533
    if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
 
534
 
 
535
    for ( i=0; sizes[i]!=0; ++i );
 
536
    resstarts = gcalloc(i+1,sizeof(struct resource));
 
537
 
 
538
    for ( i=0; sizes[i]!=0; ++i ) {
 
539
        if ( (sizes[i]>>16)!=1 )
 
540
    continue;
 
541
        if ( (sizes[i]&0xffff)>=256 )
 
542
    continue;
 
543
        for ( bdf=sf->bitmaps; bdf!=NULL && (bdf->pixelsize!=(sizes[i]&0xffff) || BDFDepth(bdf)!=1); bdf=bdf->next );
 
544
        if ( bdf==NULL )
 
545
    continue;
 
546
        resstarts[i].id = baseresid+bdf->pixelsize;
 
547
        resstarts[i].pos = BDFToNFNT(res,bdf,map);
 
548
        /* NFNTs seem to have resource flags of 0 */
 
549
    }
 
550
return(resstarts);
 
551
}
 
552
 
 
553
static struct resource *SFsToNFNTs(FILE *res, struct sflist *sfs,int baseresid) {
 
554
    int i, j, cnt;
 
555
    struct resource *resstarts;
 
556
    BDFFont *bdf;
 
557
    struct sflist *sfi;
 
558
    SplineFont *sf;
 
559
 
 
560
    cnt = 0;
 
561
    for ( sfi=sfs; sfi!=NULL; sfi=sfi->next ) {
 
562
        if ( sfi->sizes!=NULL ) {
 
563
            for ( i=0; sfi->sizes[i]!=0; ++i );
 
564
            cnt += i;
 
565
            sfi->ids = gcalloc(i+1,sizeof(int));
 
566
            sfi->bdfs = gcalloc(i+1,sizeof(BDFFont *));
 
567
        }
 
568
    }
 
569
 
 
570
    resstarts = gcalloc(cnt+1,sizeof(struct resource));
 
571
 
 
572
    cnt = 0;
 
573
    for ( sfi=sfs; sfi!=NULL; sfi=sfi->next ) {
 
574
        sf = sfi->sf;
 
575
        if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
 
576
        j=0;
 
577
        if ( sfi->sizes ) for ( i=0; sfi->sizes[i]!=0; ++i ) {
 
578
            if ( (sfi->sizes[i]>>16)!=1 )
 
579
        continue;
 
580
            if ( (sfi->sizes[i]&0xffff)>=256 )
 
581
        continue;
 
582
            for ( bdf=sf->bitmaps; bdf!=NULL && (bdf->pixelsize!=(sfi->sizes[i]&0xffff) || BDFDepth(bdf)!=1); bdf=bdf->next );
 
583
            if ( bdf==NULL )
 
584
        continue;
 
585
            sfi->ids[j] = baseresid;
 
586
            sfi->bdfs[j] = bdf;
 
587
            resstarts[cnt+j].id = baseresid++;
 
588
            resstarts[cnt+j++].pos = BDFToNFNT(res,bdf,sfi->map);
 
589
            /* NFNTs seem to have resource flags of 0 */
 
590
        }
 
591
        cnt += j;
 
592
    }
 
593
return(resstarts);
 
594
}
 
595
 
 
596
static struct resource *BuildDummyNFNTlist(FILE *res, SplineFont *sf,
 
597
        int32 *sizes, int baseresid, EncMap *map) {
 
598
    int i;
 
599
    struct resource *resstarts;
 
600
    BDFFont *bdf;
 
601
 
 
602
    if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
 
603
 
 
604
    for ( i=0; sizes[i]!=0; ++i );
 
605
    resstarts = gcalloc(i+1,sizeof(struct resource));
 
606
 
 
607
    for ( i=0; sizes[i]!=0; ++i ) {
 
608
        if ( (sizes[i]>>16)!=1 )
 
609
    continue;
 
610
        if ( (sizes[i]&0xffff)>=256 )
 
611
    continue;
 
612
        for ( bdf=sf->bitmaps; bdf!=NULL && (bdf->pixelsize!=(sizes[i]&0xffff) || BDFDepth(bdf)!=1); bdf=bdf->next );
 
613
        if ( bdf==NULL )
 
614
    continue;
 
615
        resstarts[i].id = baseresid+(sizes[i]&0xffff);
 
616
        resstarts[i].pos = DummyNFNT(res,bdf,map);
 
617
        /* NFNTs seem to have resource flags of 0 */
 
618
    }
 
619
return(resstarts);
 
620
}
 
621
 
 
622
static struct resource *BuildDummyNFNTfamilyList(FILE *res, struct sflist *sfs,
 
623
        int baseresid) {
 
624
    int i,j,cnt;
 
625
    struct resource *resstarts;
 
626
    BDFFont *bdf;
 
627
    struct sflist *sfi;
 
628
    SplineFont *sf;
 
629
 
 
630
    cnt = 0;
 
631
    for ( sfi=sfs; sfi!=NULL; sfi=sfi->next ) {
 
632
        if ( sfi->sizes!=NULL ) {
 
633
            for ( i=0; sfi->sizes[i]!=0; ++i );
 
634
            cnt += i;
 
635
            sfi->ids = gcalloc(i+1,sizeof(int));
 
636
            sfi->bdfs = gcalloc(i+1,sizeof(BDFFont *));
 
637
        }
 
638
    }
 
639
 
 
640
    resstarts = gcalloc(cnt+1,sizeof(struct resource));
 
641
 
 
642
    cnt = 0;
 
643
    for ( sfi=sfs; sfi!=NULL; sfi=sfi->next ) {
 
644
        sf = sfi->sf;
 
645
        j = 0;
 
646
        if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
 
647
        if ( sfi->sizes ) for ( i=0; sfi->sizes[i]!=0; ++i ) {
 
648
            if ( (sfi->sizes[i]>>16)!=1 )
 
649
        continue;
 
650
            for ( bdf=sf->bitmaps; bdf!=NULL && (bdf->pixelsize!=(sfi->sizes[i]&0xffff) || BDFDepth(bdf)!=1); bdf=bdf->next );
 
651
            if ( bdf==NULL )
 
652
        continue;
 
653
            sfi->ids[j] = baseresid;
 
654
            sfi->bdfs[j] = bdf;
 
655
            resstarts[cnt+j].id = baseresid++;
 
656
            resstarts[cnt+j++].pos = DummyNFNT(res,bdf,sfi->map);
 
657
            /* NFNTs seem to have resource flags of 0 */
 
658
        }
 
659
        cnt += j;
 
660
    }
 
661
return(resstarts);
 
662
}
 
663
#endif
 
664
 
 
665
enum psstyle_flags { psf_bold = 1, psf_italic = 2, psf_outline = 4,
 
666
        psf_shadow = 0x8, psf_condense = 0x10, psf_extend = 0x20 };
 
667
 
 
668
uint16 _MacStyleCode( char *styles, SplineFont *sf, uint16 *psstylecode ) {
 
669
    unsigned short stylecode= 0, psstyle=0;
 
670
 
 
671
    if ( strstrmatch( styles, "Bold" ) || strstrmatch(styles,"Demi") ||
 
672
            strstrmatch( styles,"Heav") || strstrmatch(styles,"Blac") ||
 
673
/* A few fonts have German/French styles in their names */
 
674
            strstrmatch( styles,"Fett") || strstrmatch(styles,"Gras") ) {
 
675
        stylecode = sf_bold;
 
676
        psstyle = psf_bold;
 
677
    } else if ( sf!=NULL && sf->weight!=NULL &&
 
678
            (strstrmatch( sf->weight, "Bold" ) || strstrmatch(sf->weight,"Demi") ||
 
679
             strstrmatch( sf->weight,"Heav") || strstrmatch(sf->weight,"Blac") ||
 
680
             strstrmatch( sf->weight,"Fett") || strstrmatch(sf->weight,"Gras")) ) {
 
681
        stylecode = sf_bold;
 
682
        psstyle = psf_bold;
 
683
    }
 
684
    /* URW uses four leter abbreviations of Italic and Oblique */
 
685
    /* Somebody else uses two letter abbrevs */
 
686
    if ( (sf!=NULL && sf->italicangle!=0) ||
 
687
            strstrmatch( styles, "Ital" ) ||
 
688
            strstrmatch( styles, "Obli" ) ||
 
689
            strstrmatch(styles, "Slanted") ||
 
690
            strstrmatch(styles, "Kurs") ||
 
691
            strstr( styles,"It" ) ) {
 
692
        stylecode |= sf_italic;
 
693
        psstyle |= psf_italic;
 
694
    }
 
695
    if ( strstrmatch( styles, "Underline" ) ) {
 
696
        stylecode |= sf_underline;
 
697
    }
 
698
    if ( strstrmatch( styles, "Outl" ) ) {
 
699
        stylecode |= sf_outline;
 
700
        psstyle |= psf_outline;
 
701
    }
 
702
    if ( strstr(styles,"Shadow")!=NULL ) {
 
703
        stylecode |= sf_shadow;
 
704
        psstyle |= psf_shadow;
 
705
    }
 
706
    if ( strstrmatch( styles, "Cond" ) || strstr( styles,"Cn") ||
 
707
            strstrmatch( styles, "Narrow") ) {
 
708
        stylecode |= sf_condense;
 
709
        psstyle |= psf_condense;
 
710
    }
 
711
    if ( strstrmatch( styles, "Exte" ) || strstr( styles,"Ex") ) {
 
712
        stylecode |= sf_extend;
 
713
        psstyle |= psf_extend;
 
714
    }
 
715
    if ( (psstyle&psf_extend) && (psstyle&psf_condense) ) {
 
716
        if ( sf!=NULL )
 
717
            LogError( _("Warning: %s(%s) is both extended and condensed. That's impossible.\n"),
 
718
                    sf->fontname, sf->origname );
 
719
        else
 
720
            LogError( _("Warning: Both extended and condensed. That's impossible.\n") );
 
721
        psstyle &= ~psf_extend;
 
722
        stylecode &= ~sf_extend;
 
723
    }
 
724
    if ( psstylecode!=NULL )
 
725
        *psstylecode = psstyle;
 
726
return( stylecode );
 
727
}
 
728
 
 
729
uint16 MacStyleCode( SplineFont *sf, uint16 *psstylecode ) {
 
730
    char *styles;
 
731
 
 
732
    if ( sf->cidmaster!=NULL )
 
733
        sf = sf->cidmaster;
 
734
 
 
735
    if ( sf->macstyle!=-1 ) {
 
736
        if ( psstylecode!=NULL )
 
737
            *psstylecode = (sf->macstyle&0x3)|((sf->macstyle&0x6c)>>1);
 
738
return( sf->macstyle );
 
739
    }
 
740
 
 
741
    styles = SFGetModifiers(sf);
 
742
return( _MacStyleCode(styles,sf,psstylecode));
 
743
}
 
744
 
 
745
#ifndef LUA_FF_LIB
 
746
static uint32 SFToFOND(FILE *res,SplineFont *sf,uint32 id,int dottf,
 
747
        int32 *sizes, EncMap *map) {
 
748
    uint32 rlenpos = ftell(res), widoffpos, widoffloc, kernloc, styleloc, end;
 
749
    int i,j,k,cnt, strcnt, fontclass, stylecode, glyphenc, geoffset, realstylecode;
 
750
    int gid;
 
751
    KernPair *kp;
 
752
    DBounds b;
 
753
    char *pt;
 
754
    /* Fonds are generally marked system heap and sometimes purgeable (resource flags) */
 
755
 
 
756
    putlong(res,0);                     /* Fill in length later */
 
757
    putshort(res,IsMacMonospaced(sf,map)?0x9000:0x1000);
 
758
    putshort(res,id);
 
759
    putshort(res,0);                    /* First character */
 
760
    putshort(res,255);                  /* Last character */
 
761
    putshort(res,(short) ((sf->ascent*(1<<12))/(sf->ascent+sf->descent)));
 
762
    putshort(res,-(short) ((sf->descent*(1<<12))/(sf->ascent+sf->descent)));
 
763
    putshort(res,(short) ((sf->pfminfo.linegap*(1<<12))/(sf->ascent+sf->descent)));
 
764
    putshort(res,(short) ((SFMacWidthMax(sf,map)*(1<<12))/(sf->ascent+sf->descent)));
 
765
    widoffpos = ftell(res);
 
766
    putlong(res,0);                     /* Fill in width offset later */
 
767
    putlong(res,0);                     /* Fill in kern offset later */
 
768
    putlong(res,0);                     /* Fill in style offset later */
 
769
    for ( i=0; i<9; ++i )
 
770
        putshort(res,0);                /* Extra width values */
 
771
    putlong(res,0);                     /* Script for international */
 
772
    putshort(res,2);                    /* FOND version */
 
773
 
 
774
    /* Font association table */
 
775
    stylecode = realstylecode = MacStyleCode( sf, NULL );
 
776
    stylecode = 0;              /* Debug !!!! */
 
777
    for ( i=j=0; sizes!=NULL && sizes[i]!=0; ++i )
 
778
        if ( (sizes[i]>>16)==1 && (sizes[i]&0xffff)<256 )
 
779
            ++j;
 
780
    if ( dottf ) {
 
781
        putshort(res,j+1-1);            /* Number of faces */
 
782
        putshort(res,0);                /* it's scaleable */
 
783
        putshort(res,stylecode);
 
784
        putshort(res,id);               /* Give it the same ID as the fond */
 
785
    } else
 
786
        putshort(res,j-1);              /* Number of faces */
 
787
    if ( sizes!=NULL ) {
 
788
        for ( i=0; sizes[i]!=0; ++i ) if (( sizes[i]>>16) == 1 ) {
 
789
            putshort(res,sizes[i]&0xffff);
 
790
            putshort(res,stylecode);
 
791
            putshort(res,id+(sizes[i]&0xffff)); /* make up a unique ID */
 
792
        }
 
793
    }
 
794
 
 
795
    /* offset table */
 
796
    putshort(res,1-1);                  /* One table */
 
797
    putlong(res,6);                     /* Offset from start of otab to next byte */
 
798
 
 
799
    /* bounding box table */
 
800
    putshort(res,1-1);                  /* One bounding box */
 
801
    SplineFontFindBounds(sf,&b);
 
802
    putshort(res,stylecode);
 
803
    putshort(res,b.minx*(1<<12)/(sf->ascent+sf->descent));
 
804
    putshort(res,b.miny*(1<<12)/(sf->ascent+sf->descent));
 
805
    putshort(res,b.maxx*(1<<12)/(sf->ascent+sf->descent));
 
806
    putshort(res,b.maxy*(1<<12)/(sf->ascent+sf->descent));
 
807
 
 
808
    widoffloc = ftell(res);
 
809
    putshort(res,1-1);                  /* One style in the width table too */
 
810
    putshort(res,stylecode);
 
811
    for ( k=0; k<=256; ++k ) {
 
812
        if ( k>=map->enccount || k==256 || (gid=map->map[k])==-1 || sf->glyphs[gid]==NULL )
 
813
            putshort(res,1<<12);        /* 1 em is default size */
 
814
        else
 
815
            putshort(res,sf->glyphs[gid]->width*(1<<12)/(sf->ascent+sf->descent));
 
816
    }
 
817
 
 
818
    kernloc = 0;
 
819
    if (( cnt = SFMacAnyKerns(sf,map))>0 ) {
 
820
        kernloc = ftell(res);
 
821
        putshort(res,1-1);              /* One style in the width table too */
 
822
        putshort(res,stylecode);        /* style */
 
823
        putshort(res,cnt);              /* Count of kerning pairs */
 
824
        for ( k=0; k<256 && k<map->enccount; ++k ) {
 
825
            if ( (gid=map->map[k])!=-1 && sf->glyphs[gid]!=NULL ) {
 
826
                for ( kp=sf->glyphs[gid]->kerns; kp!=NULL; kp=kp->next )
 
827
                    if ( map->backmap[kp->sc->orig_pos]<256 ) {
 
828
                        putc(k,res);
 
829
                        putc(map->backmap[kp->sc->orig_pos],res);
 
830
                        putshort(res,kp->off*(1<<12)/(sf->ascent+sf->descent));
 
831
                    }
 
832
            }
 
833
        }
 
834
    }
 
835
 
 
836
    /* Fontographer referenced a postscript font even in truetype FONDs */
 
837
    styleloc = ftell(res);
 
838
    fontclass = 0x1;            /* font name needs coordinating? Font has its own encoding */
 
839
    if ( !(realstylecode&sf_outline) ) fontclass |= 4;
 
840
    if ( realstylecode&sf_bold ) fontclass |= 0x18;
 
841
    if ( realstylecode&psf_italic ) fontclass |= 0x40;
 
842
    if ( realstylecode&psf_condense ) fontclass |= 0x80;
 
843
    if ( realstylecode&psf_extend ) fontclass |= 0x100;
 
844
    putshort(res,fontclass);            /* fontClass */
 
845
    geoffset = ftell(res);
 
846
    putlong(res,0);                     /* Offset to glyph encoding table */ /* Fill in later */
 
847
    putlong(res,0);                     /* Reserved, MBZ */
 
848
    if ( strnmatch(sf->familyname,sf->fontname,strlen(sf->familyname))!=0 )
 
849
        strcnt = 1;
 
850
    else if ( strmatch(sf->familyname,sf->fontname)==0 )
 
851
        strcnt = 1;
 
852
    else if ( sf->fontname[strlen(sf->familyname)]=='-' )
 
853
        strcnt = 4;
 
854
    else
 
855
        strcnt = 3;
 
856
    for ( k=0; k<48; ++k )
 
857
        putc(strcnt==1?1:2,res);        /* All indeces point to this font */
 
858
    putshort(res,strcnt);               /* strcnt strings */
 
859
    pt = sf->fontname+strlen(sf->familyname);
 
860
    if ( strcnt==1 ) {
 
861
        putc(strlen(sf->fontname),res); /* basename is full name */
 
862
        /* Mac expects this to be upper case */
 
863
        if ( Islower(*sf->fontname)) putc(toupper(*sf->fontname),res);
 
864
        else putc(*sf->fontname,res);
 
865
        fwrite(sf->fontname+1,1,strlen(sf->fontname+1),res);
 
866
    } else {
 
867
        putc(strlen(sf->familyname),res);/* basename */
 
868
        if ( Islower(*sf->familyname)) putc(toupper(*sf->familyname),res);
 
869
        else putc(*sf->familyname,res);
 
870
        fwrite(sf->familyname+1,1,strlen(sf->familyname+1),res);
 
871
        if ( strcnt==3 ) {
 
872
            putc(1,res);                        /* index string is one byte long */
 
873
            putc(3,res);                        /* plain name is basename with string 2 */
 
874
            putc(strlen(pt),res);               /* length of... */
 
875
            fwrite(pt,1,strlen(pt),res);        /* everything else */
 
876
        } else {
 
877
            putc(2,res);                        /* index string is two bytes long */
 
878
            putc(3,res);                        /* plain name is basename with hyphen */
 
879
            putc(4,res);                        /* and everything else */
 
880
            putc(1,res);                        /* Length of ... */
 
881
            putc('-',res);                      /* String containing hyphen */
 
882
            ++pt;                       /* skip over hyphen */
 
883
            putc(strlen(pt),res);               /* length of ... */
 
884
            fwrite(pt,1,strlen(pt),res);        /* everything else */
 
885
        }
 
886
    }
 
887
    /* Greg: record offset for glyph encoding table */
 
888
    /* We assume that the bitmap and postscript fonts are encoded similarly */
 
889
    /*  and so a null vector will do. */
 
890
    /* GWW: Hmm. ATM refuses to use postscript fonts that have */
 
891
    /*  glyph encoding tables. Printer drivers use them ok. ATM will only */
 
892
    /*  work on fonts with mac roman encodings */
 
893
    if ( strmatch(map->enc->enc_name,"mac")!=0 &&
 
894
            strmatch(map->enc->enc_name,"macintosh")!=0 &&
 
895
            strmatch(map->enc->enc_name,"macroman")!=0 ) {
 
896
#if !defined(FONTFORGE_CONFIG_NO_WINDOWING_UI)
 
897
        if ( !dottf ) ff_post_notice(_("The generated font won't work with ATM"),_("ATM requires that fonts be encoded with the Macintosh Latin encoding. This postscript font will print fine, but only the bitmap versions will be displayed on the screen"));
 
898
#endif
 
899
        glyphenc = ftell( res );
 
900
        fseek(res,geoffset,SEEK_SET);
 
901
        putlong(res,glyphenc-geoffset+2);
 
902
        fseek(res,glyphenc,SEEK_SET);
 
903
#if 1
 
904
        putshort(res,0);
 
905
#else
 
906
        putshort(res,sf->charcnt>256?128:sf->charcnt-128);
 
907
        for ( i=0x80; i<sf->charcnt && i<256; ++i ) {
 
908
            SplineChar *sc, dummy;
 
909
            putc(i,res);
 
910
            sc = SCBuildDummy(&dummy,sf,i);
 
911
            putc(strlen(sc->name),res);
 
912
            fwrite(sc->name,1,strlen(sc->name),res);
 
913
        }
 
914
#endif
 
915
    }
 
916
 
 
917
    end = ftell(res);
 
918
    fseek(res,widoffpos,SEEK_SET);
 
919
    putlong(res,widoffloc-rlenpos-4);   /* Fill in width offset */
 
920
    putlong(res,kernloc!=0?kernloc-rlenpos-4:0);        /* Fill in kern offset */
 
921
    putlong(res,styleloc!=0?styleloc-rlenpos-4:0);      /* Fill in style offset */
 
922
 
 
923
    fseek(res,rlenpos,SEEK_SET);
 
924
    putlong(res,end-rlenpos-4);         /* resource length */
 
925
    fseek(res,end,SEEK_SET);
 
926
return(rlenpos);
 
927
}
 
928
 
 
929
static void putpnsstring(FILE *res,char *fontname,int len) {
 
930
    putc(len,res);
 
931
    if ( *fontname && len>0 ) {
 
932
        if ( Islower(*fontname))
 
933
            putc(toupper(*fontname),res);
 
934
        else
 
935
            putc(*fontname,res);
 
936
        --len;
 
937
        for ( ++fontname; *fontname && len>0; ++fontname, --len )
 
938
            putc(*fontname,res);
 
939
    }
 
940
}
 
941
 
 
942
static void putpsstring(FILE *res,char *fontname) {
 
943
    putc(strlen(fontname),res);
 
944
    if ( *fontname ) {
 
945
        for ( ; *fontname; ++fontname )
 
946
            putc(*fontname,res);
 
947
    }
 
948
}
 
949
 
 
950
struct sflistlist {
 
951
    struct sflist *sfs;
 
952
    struct sflistlist *next;
 
953
    char *fondname;
 
954
};
 
955
 
 
956
static struct sflistlist *FondSplitter(struct sflist *sfs,int *fondcnt) {
 
957
    struct sflist *psfaces[48], *sfi, *last, *start;
 
958
    struct sflistlist *sfsl=NULL, *lastl=NULL, *cur, *test;
 
959
    uint16 psstyle;
 
960
    int fc = 0;
 
961
 
 
962
    sfi = sfs;
 
963
    if ( sfi->sf->fondname==NULL ) {
 
964
        memset(psfaces,0,sizeof(psfaces));
 
965
        MacStyleCode(sfi->sf,&psstyle);
 
966
        last = NULL;
 
967
        while ( sfi->sf->fondname==NULL && psfaces[psstyle]==NULL ) {
 
968
            psfaces[psstyle] = sfi;
 
969
            last = sfi;
 
970
            sfi = sfi->next;
 
971
            if ( sfi==NULL )
 
972
        break;
 
973
            MacStyleCode(sfi->sf,&psstyle);
 
974
        }
 
975
        cur = gcalloc(1,sizeof(struct sflistlist));
 
976
        cur->sfs = sfs;
 
977
        last->next = NULL;
 
978
        for ( last=sfi; last!=NULL; last=last->next )
 
979
            if ( last->sf->fondname!=NULL && strcmp(last->sf->fondname,sfs->sf->familyname)==0 )
 
980
        break;
 
981
        cur->fondname = copy( last==NULL ? sfs->sf->familyname : sfs->sf->fontname );
 
982
        lastl = sfsl = cur;
 
983
        ++fc;
 
984
    }
 
985
    while ( sfi!=NULL ) {
 
986
        start = sfi;
 
987
        if ( sfi->sf->fondname==NULL ) {
 
988
            last = sfi;
 
989
            sfi = sfi->next;
 
990
        } else {
 
991
            memset(psfaces,0,sizeof(psfaces));
 
992
            MacStyleCode(sfi->sf,&psstyle);
 
993
            while ( sfi!=NULL && sfi->sf->fondname!=NULL &&
 
994
                    strcmp(sfi->sf->fondname,start->sf->fondname)==0 &&
 
995
                    psfaces[psstyle]==NULL ) {
 
996
                psfaces[psstyle] = sfi;
 
997
                last = sfi;
 
998
                sfi = sfi->next;
 
999
                if ( sfi==NULL )
 
1000
            break;
 
1001
                MacStyleCode(sfi->sf,&psstyle);
 
1002
            }
 
1003
        }
 
1004
        cur = gcalloc(1,sizeof(struct sflistlist));
 
1005
        test = NULL;
 
1006
        if ( start->sf->fondname!=NULL ) {
 
1007
            for ( test = sfsl; test!=NULL; test=test->next )
 
1008
                if ( strcmp(test->fondname,start->sf->fondname)==0 )
 
1009
            break;
 
1010
            if ( test==NULL )
 
1011
                cur->fondname = copy(start->sf->fondname);
 
1012
        }
 
1013
        if ( cur->fondname==NULL )
 
1014
            cur->fondname = copy(start->sf->fontname);
 
1015
        if ( lastl!=NULL ) lastl->next = cur;
 
1016
        lastl = cur;
 
1017
        cur->sfs = start;
 
1018
        last->next = NULL;
 
1019
        if ( sfsl==NULL )
 
1020
            sfsl = cur;
 
1021
        ++fc;
 
1022
    }
 
1023
    *fondcnt = fc;
 
1024
return( sfsl );
 
1025
}
 
1026
 
 
1027
static void SFListListFree(struct sflistlist *sfsl) {
 
1028
    struct sflist *last = NULL;
 
1029
    struct sflistlist *sfli, *sflnext;
 
1030
    /* free the fond list and restore the sfs list */
 
1031
 
 
1032
    for ( sfli=sfsl; sfli!=NULL; sfli = sflnext ) {
 
1033
        sflnext = sfli->next;
 
1034
        if ( last!=NULL )
 
1035
            last->next = sfli->sfs;
 
1036
        for ( last = sfli->sfs; last->next!=NULL; last = last->next );
 
1037
        free(sfli->fondname);
 
1038
        free(sfli);
 
1039
    }
 
1040
}
 
1041
 
 
1042
static uint32 SFsToFOND(FILE *res,struct sflist *sfs,uint32 id,int format,int bf) {
 
1043
    uint32 rlenpos = ftell(res), widoffpos, widoffloc, kernloc, styleloc, end;
 
1044
    int i,j,k,cnt, scnt, kcnt, pscnt, strcnt, fontclass, glyphenc, geoffset;
 
1045
    int gid;
 
1046
    int size;
 
1047
    uint16 psstyle, stylecode;
 
1048
    int exact, famlen, has_hyphen;
 
1049
    char *familyname;
 
1050
    KernPair *kp;
 
1051
    DBounds b;
 
1052
    /* Fonds are generally marked system heap and sometimes purgeable (resource flags) */
 
1053
    struct sflist *faces[96];
 
1054
    struct sflist *psfaces[48];
 
1055
    SplineFont *sf;
 
1056
    struct sflist *sfi;
 
1057
    char *pt;
 
1058
 
 
1059
    memset(faces,0,sizeof(faces));
 
1060
    memset(psfaces,0,sizeof(psfaces));
 
1061
    for ( sfi = sfs ; sfi!=NULL; sfi = sfi->next ) {
 
1062
        stylecode = MacStyleCode(sfi->sf,&psstyle);
 
1063
        if ( sfs->next==NULL )          /* FONDs with a single entry should make that entry be "regular" no matter what we think it really is */
 
1064
            stylecode = psstyle = 0;
 
1065
        if ( faces[stylecode]==NULL )
 
1066
            faces[stylecode] = sfi;
 
1067
        if ( psfaces[psstyle]==NULL )
 
1068
            psfaces[psstyle] = sfi;
 
1069
    }
 
1070
    sf = faces[0]->sf;
 
1071
    
 
1072
    putlong(res,0);                     /* Fill in length later */
 
1073
    putshort(res,IsMacMonospaced(sf,faces[0]->map)?0x9000:0x1000);
 
1074
    putshort(res,id);
 
1075
    putshort(res,0);                    /* First character */
 
1076
    putshort(res,255);                  /* Last character */
 
1077
    putshort(res,(short) ((sf->ascent*(1<<12))/(sf->ascent+sf->descent)));
 
1078
    putshort(res,-(short) ((sf->descent*(1<<12))/(sf->ascent+sf->descent)));
 
1079
    putshort(res,(short) ((sf->pfminfo.linegap*(1<<12))/(sf->ascent+sf->descent)));
 
1080
    putshort(res,(short) ((SFMacWidthMax(sf,faces[0]->map)*(1<<12))/(sf->ascent+sf->descent)));
 
1081
    widoffpos = ftell(res);
 
1082
    putlong(res,0);                     /* Fill in width offset later */
 
1083
    putlong(res,0);                     /* Fill in kern offset later */
 
1084
    putlong(res,0);                     /* Fill in style offset later */
 
1085
    for ( i=0; i<9; ++i )
 
1086
        putshort(res,0);                /* Extra width values */
 
1087
    putlong(res,0);                     /* Script for international */
 
1088
    putshort(res,2);                    /* FOND version */
 
1089
 
 
1090
    /* Font association table */
 
1091
    for ( i=cnt=scnt=kcnt=0; i<96; ++i ) if ( faces[i]!=NULL ) {
 
1092
        ++scnt;
 
1093
        if ( faces[i]->id!=0 ) ++cnt;
 
1094
        if ( faces[i]->ids!=NULL )
 
1095
            for ( j=0; faces[i]->ids[j]!=0; ++j ) ++cnt;
 
1096
        if ( SFMacAnyKerns(faces[i]->sf,faces[i]->map)>0 )
 
1097
            ++kcnt;
 
1098
    }
 
1099
    putshort(res,cnt-1);                /* Number of faces */
 
1100
    /* do ttf faces (if any) first */
 
1101
    for ( i=cnt=0; i<96; ++i ) if ( faces[i]!=NULL && faces[i]->id!=0 ) {
 
1102
        putshort(res,0);                /* it's scaleable */
 
1103
        putshort(res,i);                /* style */
 
1104
        putshort(res,faces[i]->id);
 
1105
    }
 
1106
    /* then do bitmap faces (if any) */ /* Ordered by size damn it */
 
1107
    for ( size=1; size<256; ++size ) {
 
1108
        for ( i=0; i<96; ++i ) if ( faces[i]!=NULL && faces[i]->ids!=NULL ) {
 
1109
            for ( j=0; faces[i]->ids[j]!=0 ; ++j ) {
 
1110
                int pointsize = rint( (faces[i]->bdfs[j]->pixelsize*72.0/mac_dpi) );
 
1111
                if ( pointsize==size ) {
 
1112
                    putshort(res,size);
 
1113
                    putshort(res,i);            /* style */
 
1114
                    putshort(res,faces[i]->ids[j]);
 
1115
                }
 
1116
            }
 
1117
        }
 
1118
    }
 
1119
 
 
1120
    /* offset table */
 
1121
    putshort(res,1-1);                  /* One table */
 
1122
    putlong(res,6);                     /* Offset from start of otab to next byte */
 
1123
 
 
1124
    /* bounding box table */
 
1125
    putshort(res,scnt-1);               /* One bounding box per style */
 
1126
    for ( i=0; i<96; ++i ) if ( faces[i]!=NULL ) {
 
1127
        SplineFontFindBounds(faces[i]->sf,&b);
 
1128
        putshort(res,i);                        /* style */
 
1129
        putshort(res,b.minx*(1<<12)/(faces[i]->sf->ascent+faces[i]->sf->descent));
 
1130
        putshort(res,b.miny*(1<<12)/(faces[i]->sf->ascent+faces[i]->sf->descent));
 
1131
        putshort(res,b.maxx*(1<<12)/(faces[i]->sf->ascent+faces[i]->sf->descent));
 
1132
        putshort(res,b.maxy*(1<<12)/(faces[i]->sf->ascent+faces[i]->sf->descent));
 
1133
    }
 
1134
 
 
1135
    widoffloc = ftell(res);
 
1136
    putshort(res,scnt-1);               /* One set of width metrics per style */
 
1137
    for ( i=0; i<96; ++i ) if ( faces[i]!=NULL ) {
 
1138
        putshort(res,i);
 
1139
        for ( k=0; k<=257; ++k ) {
 
1140
            if ( k>=faces[i]->map->enccount || k>=256 ||
 
1141
                    (gid=faces[i]->map->map[k])==-1 || faces[i]->sf->glyphs[gid]==NULL )
 
1142
                putshort(res,1<<12);    /* 1 em is default size */
 
1143
            else
 
1144
                putshort(res,faces[i]->sf->glyphs[gid]->width*(1<<12)/(faces[i]->sf->ascent+faces[i]->sf->descent));
 
1145
        }
 
1146
    }
 
1147
 
 
1148
    kernloc = 0;
 
1149
    if ( kcnt>0 ) {
 
1150
        kernloc = ftell(res);
 
1151
        putshort(res,kcnt-1);           /* Number of styles with kern pairs */
 
1152
        for ( i=0; i<96; ++i ) if ( faces[i]!=NULL && ( cnt = SFMacAnyKerns(faces[i]->sf,faces[i]->map))>0 ) {
 
1153
            putshort(res,i);            /* style */
 
1154
            putshort(res,cnt);          /* Count of kerning pairs */
 
1155
            for ( k=0; k<256 && k<faces[i]->map->enccount; ++k ) {
 
1156
                if ( (gid=faces[i]->map->map[k])!=-1 && faces[i]->sf->glyphs[gid]!=NULL ) {
 
1157
                    for ( kp=faces[i]->sf->glyphs[gid]->kerns; kp!=NULL; kp=kp->next )
 
1158
                        if ( faces[i]->map->backmap[kp->sc->orig_pos]<256 ) {
 
1159
                            putc(k,res);
 
1160
                            putc(faces[i]->map->backmap[kp->sc->orig_pos],res);
 
1161
                            putshort(res,kp->off*(1<<12)/(sf->ascent+sf->descent));
 
1162
                        }
 
1163
                }
 
1164
            }
 
1165
        }
 
1166
    }
 
1167
 
 
1168
    /* Fontographer referenced a postscript font even in truetype FONDs */
 
1169
    styleloc = ftell(res);
 
1170
 
 
1171
    exact = false;
 
1172
    familyname = psfaces[0]->sf->fontname;
 
1173
    famlen = strlen(familyname);
 
1174
    if ( (pt=strchr(familyname,'-'))!=NULL )
 
1175
        famlen = pt-familyname;
 
1176
    else if ( strnmatch(psfaces[0]->sf->familyname,psfaces[0]->sf->fontname,
 
1177
            strlen(psfaces[0]->sf->familyname))==0 )
 
1178
        famlen = strlen(psfaces[0]->sf->familyname);
 
1179
    has_hyphen = (familyname[famlen]=='-');
 
1180
    for ( i=pscnt=0; i<48; ++i ) if ( psfaces[i]!=NULL ) {
 
1181
        ++pscnt;
 
1182
        if ( strncmp(psfaces[i]->sf->fontname,familyname,famlen)!=0 ) {
 
1183
            while ( famlen>0 ) {
 
1184
                --famlen;
 
1185
                if ( strncmp(psfaces[i]->sf->fontname,familyname,famlen)==0 )
 
1186
            break;
 
1187
            }
 
1188
        }
 
1189
    }
 
1190
    if ( famlen!=0 ) for ( i=0; i<48; ++i ) if ( psfaces[i]!=NULL ) {
 
1191
        if ( psfaces[i]->sf->fontname[famlen]==0 )
 
1192
            exact = true;
 
1193
    }
 
1194
    fontclass = 0x1;
 
1195
    if ( psfaces[psf_outline]==NULL ) fontclass |= 4;
 
1196
    if ( psfaces[psf_bold]!=NULL ) fontclass |= 0x18;
 
1197
    if ( psfaces[psf_italic]!=NULL ) fontclass |= 0x40;
 
1198
    if ( psfaces[psf_condense]!=NULL ) fontclass |= 0x80;
 
1199
    if ( psfaces[psf_extend]!=NULL ) fontclass |= 0x100;
 
1200
    putshort(res,fontclass);            /* fontClass */
 
1201
    geoffset = ftell(res);
 
1202
    putlong(res,0);                     /* Offset to glyph encoding table */ /* Fill in later */
 
1203
    putlong(res,0);                     /* Reserved, MBZ */
 
1204
    strcnt = 1/* Family Name */ + pscnt-exact /* count of format strings */ +
 
1205
            has_hyphen +
 
1206
            pscnt-exact /* count of additional strings */;
 
1207
    /* indeces to format strings */
 
1208
    for ( i=0,pscnt=2; i<48; ++i )
 
1209
        if ( psfaces[i]!=NULL && psfaces[i]->sf->fontname[famlen]!=0 )
 
1210
            putc(pscnt++,res);
 
1211
        else if ( exact )
 
1212
            putc(1,res);
 
1213
        else
 
1214
            putc(2,res);
 
1215
    putshort(res,strcnt);               /* strcnt strings */
 
1216
    putpnsstring(res,familyname,famlen);
 
1217
    if ( has_hyphen ) has_hyphen = pscnt++;     /* Space for hyphen if present */
 
1218
    /* Now the format strings */
 
1219
    for ( i=0; i<48; ++i ) if ( psfaces[i]!=NULL ) {
 
1220
        if ( psfaces[i]->sf->fontname[famlen]!=0 ) {
 
1221
            if ( has_hyphen && psfaces[i]->sf->fontname[famlen]==' ' ) {
 
1222
                putc(2,res);
 
1223
                putc(has_hyphen,res);
 
1224
                putc(pscnt++,res);
 
1225
            } else {
 
1226
                putc(1,res);            /* Familyname with the following */
 
1227
                putc(pscnt++,res);
 
1228
            }
 
1229
        }
 
1230
    }
 
1231
    if ( has_hyphen ) {
 
1232
        putc(1,res);
 
1233
        putc('-',res);
 
1234
    }
 
1235
    /* Now the additional names */
 
1236
    for ( i=0; i<48; ++i ) if ( psfaces[i]!=NULL ) {
 
1237
        if ( psfaces[i]->sf->fontname[famlen]!=0 )
 
1238
            putpsstring(res,psfaces[i]->sf->fontname+famlen);
 
1239
    }
 
1240
    /* Greg: record offset for glyph encoding table */
 
1241
    /* We assume that the bitmap and postscript fonts are encoded similarly */
 
1242
    /*  and so a null vector will do. */
 
1243
    /* GWW: Hmm. ATM refuses to use postscript fonts that have */
 
1244
    /*  glyph encoding tables. Printer drivers use them ok. ATM will only */
 
1245
    /*  work on fonts with mac roman encodings */
 
1246
    if ( strmatch(psfaces[0]->map->enc->enc_name,"mac")!=0 &&
 
1247
            strmatch(psfaces[0]->map->enc->enc_name,"macintosh")!=0 &&
 
1248
            strmatch(psfaces[0]->map->enc->enc_name,"macroman")!=0 ) {
 
1249
        if ( format==ff_pfbmacbin )
 
1250
#if !defined(FONTFORGE_CONFIG_NO_WINDOWING_UI)
 
1251
            ff_post_notice(_("The generated font won't work with ATM"),_("ATM requires that fonts be encoded with the Macintosh Latin encoding. This postscript font will print fine, but only the bitmap versions will be displayed on the screen"));
 
1252
#endif
 
1253
        glyphenc = ftell( res );
 
1254
        fseek(res,geoffset,SEEK_SET);
 
1255
        putlong(res,glyphenc-geoffset+2);
 
1256
        fseek(res,glyphenc,SEEK_SET);
 
1257
        putshort(res,0); /* Greg: an empty Glyph encoding table */
 
1258
    }
 
1259
 
 
1260
    end = ftell(res);
 
1261
    fseek(res,widoffpos,SEEK_SET);
 
1262
    putlong(res,widoffloc-rlenpos-4);   /* Fill in width offset */
 
1263
    putlong(res,kernloc!=0?kernloc-rlenpos-4:0);        /* Fill in kern offset */
 
1264
    putlong(res,styleloc!=0?styleloc-rlenpos-4:0);      /* Fill in style offset */
 
1265
 
 
1266
    fseek(res,rlenpos,SEEK_SET);
 
1267
    putlong(res,end-rlenpos-4);         /* resource length */
 
1268
    fseek(res,end,SEEK_SET);
 
1269
return(rlenpos);
 
1270
}
 
1271
 
 
1272
/* I presume this routine is called after all resources have been written */
 
1273
static void DumpResourceMap(FILE *res,struct resourcetype *rtypes,enum fontformat format) {
 
1274
    uint32 rfork_base = format>=ff_ttfdfont?0:128;      /* space for mac binary header */
 
1275
    uint32 resource_base = rfork_base+0x100;
 
1276
    uint32 rend, rtypesstart, mend, namestart;
 
1277
    int i,j;
 
1278
 
 
1279
    fseek(res,0,SEEK_END);
 
1280
    rend = ftell(res);
 
1281
 
 
1282
    if ( format<ff_ttfdfont ) {
 
1283
        /* Duplicate resource header */
 
1284
        putlong(res,0x100);                     /* start of resource data */
 
1285
        putlong(res,rend-rfork_base);           /* start of resource map */
 
1286
        putlong(res,rend-rfork_base-0x100);     /* length of resource data */
 
1287
        putlong(res,0);                         /* don't know the length of the map section yet */
 
1288
    } else {
 
1289
        for ( i=0; i<16; ++i )                  /* 16 bytes of zeroes */
 
1290
            putc(0,res);
 
1291
    }
 
1292
 
 
1293
    putlong(res,0);                     /* Some mac specific thing I don't understand */
 
1294
    putshort(res,0);                    /* another */
 
1295
    putshort(res,0);                    /* another */
 
1296
 
 
1297
    putshort(res,4+ftell(res)-rend);    /* Offset to resource types */
 
1298
    putshort(res,0);                    /* Don't know where the names go yet */
 
1299
 
 
1300
    rtypesstart = ftell(res);
 
1301
    for ( i=0; rtypes[i].tag!=0; ++i );
 
1302
    putshort(res,i-1);                  /* Count of different types */
 
1303
    for ( i=0; rtypes[i].tag!=0; ++i ) {
 
1304
        putlong(res,rtypes[i].tag);     /* Resource type */
 
1305
        putshort(res,0);                /* Number of resources of this type */
 
1306
        putshort(res,0);                /* Offset to the resource list */
 
1307
    }
 
1308
 
 
1309
    /* Now the resource lists... */
 
1310
    for ( i=0; rtypes[i].tag!=0; ++i ) {
 
1311
        rtypes[i].resloc = ftell(res);
 
1312
        for ( j=0; rtypes[i].res[j].pos!=0; ++j ) {
 
1313
            putshort(res,rtypes[i].res[j].id);
 
1314
            rtypes[i].res[j].nameptloc = ftell(res);
 
1315
            putshort(res,0xffff);               /* assume no name at first */
 
1316
            putc(rtypes[i].res[j].flags,res);   /* resource flags */
 
1317
                /* three byte resource offset */
 
1318
            putc( ((rtypes[i].res[j].pos-resource_base)>>16)&0xff, res );
 
1319
            putc( ((rtypes[i].res[j].pos-resource_base)>>8)&0xff, res );
 
1320
            putc( ((rtypes[i].res[j].pos-resource_base)&0xff), res );
 
1321
            putlong(res,0);
 
1322
        }
 
1323
    }
 
1324
    namestart = ftell(res);
 
1325
    /* Now the names, if any */
 
1326
    for ( i=0; rtypes[i].tag!=0; ++i ) {
 
1327
        for ( j=0; rtypes[i].res[j].pos!=0; ++j ) {
 
1328
            if ( rtypes[i].res[j].name!=NULL ) {
 
1329
                rtypes[i].res[j].nameloc = ftell(res);
 
1330
                putc(strlen(rtypes[i].res[j].name),res);        /* Length */
 
1331
                fwrite(rtypes[i].res[j].name,1,strlen(rtypes[i].res[j].name),res);
 
1332
            }
 
1333
        }
 
1334
    }
 
1335
    mend = ftell(res);
 
1336
 
 
1337
    /* Repeat the rtypes list now we know where they go */
 
1338
    fseek(res,rtypesstart+2,SEEK_SET);          /* skip over the count */
 
1339
    for ( i=0; rtypes[i].tag!=0; ++i ) {
 
1340
        putlong(res,rtypes[i].tag);     /* Resource type */
 
1341
        for ( j=0; rtypes[i].res[j].pos!=0; ++j );
 
1342
        putshort(res,j-1);              /* Number of resources of this type */
 
1343
        putshort(res,rtypes[i].resloc-rtypesstart);
 
1344
    }
 
1345
    /* And go back and fixup any name pointers */
 
1346
    for ( i=0; rtypes[i].tag!=0; ++i ) {
 
1347
        for ( j=0; rtypes[i].res[j].pos!=0; ++j ) {
 
1348
            if ( rtypes[i].res[j].name!=NULL ) {
 
1349
                fseek(res,rtypes[i].res[j].nameptloc,SEEK_SET);
 
1350
                putshort(res,rtypes[i].res[j].nameloc-namestart);
 
1351
            }
 
1352
        }
 
1353
    }
 
1354
 
 
1355
    fseek(res,rend,SEEK_SET);
 
1356
        /* Fixup duplicate header (and offset to the name list) */
 
1357
    if ( format<ff_ttfdfont ) {
 
1358
        putlong(res,0x100);                     /* start of resource data */
 
1359
        putlong(res,rend-rfork_base);           /* start of resource map */
 
1360
        putlong(res,rend-rfork_base-0x100);     /* length of resource data */
 
1361
        putlong(res,mend-rend);                 /* length of map section */
 
1362
    } else {
 
1363
        for ( i=0; i<16; ++i )
 
1364
            putc(0,res);
 
1365
    }
 
1366
 
 
1367
    putlong(res,0);                     /* Some mac specific thing I don't understand */
 
1368
    putshort(res,0);                    /* another */
 
1369
    putshort(res,0);                    /* another */
 
1370
 
 
1371
    putshort(res,4+ftell(res)-rend);    /* Offset to resource types */
 
1372
    putshort(res,namestart-rend);       /* name section */
 
1373
 
 
1374
    fseek(res,rfork_base,SEEK_SET);
 
1375
        /* Fixup main resource header */
 
1376
    putlong(res,0x100);                 /* start of resource data */
 
1377
    putlong(res,rend-rfork_base);       /* start of resource map */
 
1378
    putlong(res,rend-rfork_base-0x100); /* length of resource data */
 
1379
    putlong(res,mend-rend);             /* length of map section */
 
1380
}
 
1381
 
 
1382
long mactime(void) {
 
1383
    time_t now;
 
1384
    int i;
 
1385
 
 
1386
    time(&now);
 
1387
    /* convert from 1970 based time to 1904 based time */
 
1388
    now += (1970-1904)*365L*24*60*60;
 
1389
    for ( i=1904; i<1970; i+=4 )
 
1390
        now += 24*60*60;
 
1391
    /* Ignore any leap seconds -- Sorry Steve */
 
1392
return( now );
 
1393
}
 
1394
 
 
1395
static int DumpMacBinaryHeader(FILE *res,struct macbinaryheader *mb) {
 
1396
#if !__Mac
 
1397
    uint8 header[128], *hpt; char buffer[256], *pt, *dpt;
 
1398
    uint32 len;
 
1399
    time_t now;
 
1400
    int crc;
 
1401
 
 
1402
    if ( mb->macfilename==NULL ) {
 
1403
        char *pt = strrchr(mb->binfilename,'/');
 
1404
        if ( pt==NULL ) pt = mb->binfilename;
 
1405
        else ++pt;
 
1406
        strcpy(buffer,pt);
 
1407
        dpt = strrchr(buffer,'.');
 
1408
        if ( dpt==NULL ) {
 
1409
            buffer[0] = '_';
 
1410
            strcpy(buffer+1,pt);
 
1411
        } else
 
1412
            *dpt = '\0';
 
1413
        mb->macfilename = buffer;
 
1414
        buffer[63] = '\0';
 
1415
    }
 
1416
 
 
1417
    memset(header,'\0',sizeof(header));
 
1418
    hpt = header;
 
1419
    *hpt++ = '\0';              /* version number */
 
1420
    /* Mac Filename */
 
1421
    pt = mb->macfilename;
 
1422
    *hpt++ = strlen( pt );
 
1423
    while ( *pt )
 
1424
        *hpt++ = *pt++;
 
1425
    while ( hpt<header+65 )
 
1426
        *hpt++ = '\0';
 
1427
    /* Mac File Type */
 
1428
    *hpt++ = mb->type>>24; *hpt++ = mb->type>>16; *hpt++ = mb->type>>8; *hpt++ = mb->type;
 
1429
    /* Mac Creator */
 
1430
    *hpt++ = mb->creator>>24; *hpt++ = mb->creator>>16; *hpt++ = mb->creator>>8; *hpt++ = mb->creator;
 
1431
    *hpt++ = '\0';              /* No finder flags set */
 
1432
    *hpt++ = '\0';              /* (byte 74) MBZ */
 
1433
    *hpt++ = '\0'; *hpt++ = '\0';       /* Vert Position in folder */
 
1434
    *hpt++ = '\0'; *hpt++ = '\0';       /* Hor Position in folder */
 
1435
    *hpt++ = '\0'; *hpt++ = '\0';       /* window or folder id??? */
 
1436
    *hpt++ = '\0';              /* protected bit ??? */
 
1437
    *hpt++ = '\0';              /* (byte 82) MBZ */
 
1438
        /* Data fork length */
 
1439
    *hpt++ = '\0'; *hpt++ = '\0'; *hpt++ = '\0'; *hpt++ = '\0';
 
1440
        /* Resource fork length */
 
1441
    fseek(res,0,SEEK_END);
 
1442
    len = ftell(res)-sizeof(header);
 
1443
    *hpt++ = len>>24; *hpt++ = len>>16; *hpt++ = len>>8; *hpt++ = len;
 
1444
        /* Pad resource fork to be a multiple of 128 bytes */
 
1445
    while ( (len&127)!=0 )
 
1446
        { putc('\0',res); ++len; }
 
1447
 
 
1448
        /* Creation time, (seconds from 1/1/1904) */
 
1449
    now = mactime();
 
1450
    time(&now);
 
1451
    *hpt++ = now>>24; *hpt++ = now>>16; *hpt++ = now>>8; *hpt++ = now;
 
1452
        /* Modification time, (seconds from 1/1/1904) */
 
1453
    *hpt++ = now>>24; *hpt++ = now>>16; *hpt++ = now>>8; *hpt++ = now;
 
1454
 
 
1455
    *hpt++ = '\0'; *hpt++ = '\0';       /* Get Info comment length */
 
1456
    *hpt++ = 0;                         /* More finder flags */
 
1457
 
 
1458
/* MacBinary 3 */
 
1459
    memcpy(header+102,"mBIN",4);
 
1460
    header[106] = 0;                    /* Script. I assume 0 is latin */
 
1461
    header[107] = 0;                    /* extended finder flags */
 
1462
/* End of MacBinary 3 */
 
1463
    header[122] = 130;                  /* MacBinary version 3, written in (129 is MB2) */
 
1464
    header[123] = 129;                  /* MacBinary Version 2, needed to read */
 
1465
 
 
1466
    crc = binhex_crc(header,124);
 
1467
    header[124] = crc>>8;
 
1468
    header[125] = crc;
 
1469
 
 
1470
    fseek(res,0,SEEK_SET);
 
1471
    fwrite(header,1,sizeof(header),res);
 
1472
return( true );
 
1473
#else
 
1474
    int ret;
 
1475
    FSRef ref, parentref;
 
1476
    short macfile;
 
1477
    char *buf, *dirname, *pt, *fname;
 
1478
    HFSUniStr255 resforkname;
 
1479
    FSCatalogInfo info;
 
1480
    long len;
 
1481
    unichar_t *filename;
 
1482
    ByteCount whocares;
 
1483
    /* When on the mac let's just create a real resource fork. We do this by */
 
1484
    /*  creating a mac file with a resource fork, opening that fork, and */
 
1485
    /*  dumping all the data in the temporary file after the macbinary header */
 
1486
 
 
1487
    /* The mac file routines are really lovely. I can't convert a pathspec to */
 
1488
    /*  an FSRef unless the file exists.  That is incredibly stupid and annoying of them */
 
1489
    /* But the directory should exist... */
 
1490
    fname = mb->macfilename?mb->macfilename:mb->binfilename;
 
1491
    dirname = copy(fname);
 
1492
    pt = strrchr(dirname,'/');
 
1493
    if ( pt!=NULL )
 
1494
        pt[1] = '\0';
 
1495
    else {
 
1496
        free(dirname);
 
1497
        dirname = copy(".");
 
1498
    }
 
1499
    ret=FSPathMakeRef( (uint8 *) dirname,&parentref,NULL);
 
1500
    free(dirname);
 
1501
    if ( ret!=noErr )
 
1502
return( false );
 
1503
 
 
1504
    pt = strrchr(fname,'/');
 
1505
    filename = def2u_copy(pt==NULL?fname:pt+1);
 
1506
    ((FInfo *) (info.finderInfo))->fdType = mb->type;
 
1507
    ((FInfo *) (info.finderInfo))->fdCreator = mb->creator;
 
1508
    ret = FSCreateFileUnicode(&parentref,u_strlen(filename), (UniChar *) filename,
 
1509
                kFSCatInfoFinderInfo, &info, &ref, NULL);
 
1510
    free(filename);
 
1511
    if ( ret==dupFNErr ) {
 
1512
        /* File already exists, create failed, didn't get an FSRef */
 
1513
        ret=FSPathMakeRef( (uint8 *) fname,&ref,NULL);
 
1514
    }
 
1515
    if ( ret!=noErr )
 
1516
return( false );
 
1517
 
 
1518
    FSGetResourceForkName(&resforkname);
 
1519
    FSCreateFork(&ref,resforkname.length,resforkname.unicode);  /* I don't think this is needed, but it doesn't hurt... */
 
1520
    ret = FSOpenFork(&ref,resforkname.length,resforkname.unicode,fsWrPerm,&macfile);
 
1521
    if ( ret!=noErr )
 
1522
return( false );
 
1523
    FSSetForkSize(macfile,fsFromStart,0);/* Truncate it just in case it existed... */
 
1524
    fseek(res,128,SEEK_SET);    /* Everything after the mac binary header in */
 
1525
        /* the temp file is resource fork */
 
1526
    buf = galloc(8*1024);
 
1527
    while ( (len=fread(buf,1,8*1024,res))>0 )
 
1528
        FSWriteFork(macfile,fsAtMark,0,len,buf,&whocares);
 
1529
    FSCloseFork(macfile);
 
1530
    free(buf);
 
1531
return( true );
 
1532
#endif
 
1533
}
 
1534
 
 
1535
static void WriteDummyMacHeaders(FILE *res) {
 
1536
    /* Leave space for the mac binary header (128bytes) and the mac resource */
 
1537
    /*  file header (256 bytes) */
 
1538
    int i;
 
1539
    for ( i=0; i<128; ++i )
 
1540
        putc(0,res);
 
1541
    for ( i=0; i<256; ++i )
 
1542
        putc(0,res);
 
1543
}
 
1544
 
 
1545
static void WriteDummyDFontHeaders(FILE *res) {
 
1546
    /* Leave space for the mac resource file header (256 bytes) */
 
1547
    /*  dfonts have the format of a data fork resource file (which I've never */
 
1548
    /*  seen documented, but appears to be just like a resource fork except */
 
1549
    /*  the first 16 bytes are not duplicated at the map */
 
1550
    int i;
 
1551
    for ( i=0; i<256; ++i )
 
1552
        putc(0,res);
 
1553
}
 
1554
 
 
1555
        /* The mac has rules about what the filename should be for a postscript*/
 
1556
        /*  font. If you deviate from those rules the font will not be found */
 
1557
        /*  The font name must begin with a capital letter */
 
1558
        /*  The filename is designed by modifying the font name */
 
1559
        /*  After the initial capital there can be at most 4 lower case letters (or digits) */
 
1560
        /*   in the filename, any additional lc letters (or digits) in the fontname are ignored */
 
1561
        /*  Every subsequent capital will be followed by at most 2 lc letters */
 
1562
        /*  special characters ("-$", etc.) are removed entirely */
 
1563
        /* So Times-Bold => TimesBol, HelveticaDemiBold => HelveDemBol */
 
1564
        /* MacBinary limits the name to 63 characters, I dunno what happens if */
 
1565
        /*  we excede that */
 
1566
static void MakeMacPSName(char buffer[63],SplineFont *sf) {
 
1567
    char *pt, *spt, *lcpt;
 
1568
 
 
1569
    for ( pt = buffer, spt = sf->fontname; *spt && pt<buffer+63-1; ++spt ) {
 
1570
        if ( Isupper(*spt) || spt==sf->fontname ) {
 
1571
            *pt++ = *spt;
 
1572
            lcpt = (spt==sf->fontname?spt+5:spt+3);
 
1573
        } else if ( (Islower(*spt) || Isdigit(*spt)) && spt<lcpt )
 
1574
            *pt++ = *spt;
 
1575
    }
 
1576
    *pt = '\0';
 
1577
}
 
1578
 
 
1579
int WriteMacPSFont(char *filename,SplineFont *sf,enum fontformat format,
 
1580
        int flags,EncMap *map) {
 
1581
#ifndef LUA_FF_LIB
 
1582
    FILE *res, *temppfb;
 
1583
    int ret = 1;
 
1584
    struct resourcetype resources[2];
 
1585
    struct macbinaryheader header;
 
1586
    int lcfn = false, lcfam = false;
 
1587
    char buffer[63];
 
1588
#if __Mac
 
1589
    char *pt;
 
1590
#endif
 
1591
 
 
1592
    temppfb = tmpfile();
 
1593
    if ( temppfb==NULL )
 
1594
return( 0 );
 
1595
 
 
1596
        /* The mac has rules about what the filename should be for a postscript*/
 
1597
        /*  font. If you deviate from those rules the font will not be found */
 
1598
        /*  The font name must begin with a capital letter */
 
1599
        /*  The filename is designed by modifying the font name */
 
1600
        /*  After the initial capital there can be at most 4 lower case letters (or digits) */
 
1601
        /*   in the filename, any additional lc letters (or digits) in the fontname are ignored */
 
1602
        /*  Every subsequent capital will be followed by at most 2 lc letters */
 
1603
        /*  special characters ("-$", etc.) are removed entirely */
 
1604
        /* So Times-Bold => TimesBol, HelveticaDemiBold => HelveDemBol */
 
1605
        /* MacBinary limits the name to 63 characters, I dunno what happens if */
 
1606
        /*  we excede that */
 
1607
    if ( Islower(*sf->fontname)) { *sf->fontname = toupper(*sf->fontname); lcfn = true; }
 
1608
    if ( Islower(*sf->familyname)) { *sf->familyname = toupper(*sf->familyname); lcfam = true; }
 
1609
    MakeMacPSName(buffer,sf);
 
1610
 
 
1611
    ret = _WritePSFont(temppfb,sf,ff_pfb,flags,map,NULL);
 
1612
    if ( lcfn ) *sf->fontname = Tolower(*sf->fontname);
 
1613
    if ( lcfam ) *sf->familyname = Tolower(*sf->familyname);
 
1614
    if ( ret==0 || ferror(temppfb) ) {
 
1615
        fclose(temppfb);
 
1616
return( 0 );
 
1617
    }
 
1618
 
 
1619
    if ( __Mac && format==ff_pfbmacbin )
 
1620
        res = tmpfile();
 
1621
    else
 
1622
        res = fopen(filename,"wb+");
 
1623
    if ( res==NULL ) {
 
1624
        fclose(temppfb);
 
1625
return( 0 );
 
1626
    }
 
1627
 
 
1628
    WriteDummyMacHeaders(res);
 
1629
    memset(resources,'\0',sizeof(resources));
 
1630
    rewind(temppfb);
 
1631
 
 
1632
    resources[0].tag = CHR('P','O','S','T');
 
1633
    resources[0].res = PSToResources(res,temppfb);
 
1634
    fclose(temppfb);
 
1635
    DumpResourceMap(res,resources,format);
 
1636
    free( resources[0].res );
 
1637
 
 
1638
#if __Mac
 
1639
    header.macfilename = galloc(strlen(filename)+strlen(buffer)+1);
 
1640
    strcpy(header.macfilename,filename);
 
1641
    pt = strrchr(header.macfilename,'/');
 
1642
    if ( pt==NULL ) pt=header.macfilename-1;
 
1643
    strcpy(pt+1,buffer);
 
1644
#else
 
1645
    header.macfilename = buffer;
 
1646
#endif
 
1647
        /* Adobe uses a creator of ASPF (Adobe Systems Postscript Font I assume) */
 
1648
        /* Fontographer uses ACp1 (Altsys Corp. Postscript type 1???) */
 
1649
        /* Both include an FREF, BNDL, ICON* and comment */
 
1650
        /* I shan't bother with that... It'll look ugly with no icon, but oh well */
 
1651
    header.type = CHR('L','W','F','N');
 
1652
    header.creator = CHR('G','W','p','1');
 
1653
    ret = DumpMacBinaryHeader(res,&header);
 
1654
    if ( ferror(res) ) ret = 0;
 
1655
    if ( fclose(res)==-1 ) ret = 0;
 
1656
#if __Mac
 
1657
    free(header.macfilename);
 
1658
#endif
 
1659
return( ret );
 
1660
#else
 
1661
return( 0 );
 
1662
#endif
 
1663
}
 
1664
 
 
1665
int WriteMacTTFFont(char *filename,SplineFont *sf,enum fontformat format,
 
1666
        int32 *bsizes, enum bitmapformat bf,int flags,EncMap *map) {
 
1667
    FILE *res, *tempttf;
 
1668
    int ret = 1, r;
 
1669
    struct resourcetype resources[4];
 
1670
    struct resource rlist[3][2], *dummynfnts=NULL;
 
1671
    struct macbinaryheader header;
 
1672
 
 
1673
    tempttf = tmpfile();
 
1674
    if ( tempttf==NULL )
 
1675
return( 0 );
 
1676
 
 
1677
    if ( _WriteTTFFont(tempttf,sf,format==ff_none?ff_none:
 
1678
                                  format==ff_ttfmacbin?ff_ttf:
 
1679
                                  format-1,bsizes,bf,flags,map)==0 || ferror(tempttf) ) {
 
1680
        fclose(tempttf);
 
1681
return( 0 );
 
1682
    }
 
1683
    if ( bf!=bf_ttf && bf!=bf_sfnt_dfont )
 
1684
        bsizes = NULL;          /* as far as the FOND for the truetype is concerned anyway */
 
1685
 
 
1686
    if ( __Mac && format==ff_ttfmacbin )
 
1687
        res = tmpfile();
 
1688
    else
 
1689
        res = fopen(filename,"wb+");
 
1690
    if ( res==NULL ) {
 
1691
        fclose(tempttf);
 
1692
return( 0 );
 
1693
    }
 
1694
 
 
1695
    if ( format!=ff_ttfmacbin )
 
1696
        WriteDummyDFontHeaders(res);
 
1697
    else
 
1698
        WriteDummyMacHeaders(res);
 
1699
    memset(rlist,'\0',sizeof(rlist));
 
1700
    memset(resources,'\0',sizeof(resources));
 
1701
    rewind(tempttf);
 
1702
 
 
1703
    r = 0;
 
1704
    resources[r].tag = CHR('s','f','n','t');
 
1705
    resources[r++].res = rlist[0];
 
1706
    rlist[0][0].pos = TTFToResource(res,tempttf);
 
1707
    rlist[0][0].id = HashToId(sf->fontname,sf,map);
 
1708
    rlist[0][0].flags = 0x00;   /* sfnts generally have resource flags 0x20 */
 
1709
    if ( bsizes!=NULL ) {
 
1710
        resources[r].tag = CHR('N','F','N','T');
 
1711
        resources[r++].res = dummynfnts = BuildDummyNFNTlist(res,sf,bsizes,rlist[0][0].id,map);
 
1712
    }
 
1713
    resources[r].tag = CHR('F','O','N','D');
 
1714
    resources[r].res = rlist[1];
 
1715
    rlist[1][0].pos = SFToFOND(res,sf,rlist[0][0].id,true,bsizes,map);
 
1716
    rlist[1][0].flags = 0x00;   /* I've seen FONDs with resource flags 0, 0x20, 0x60 */
 
1717
    rlist[1][0].id = rlist[0][0].id;
 
1718
    rlist[1][0].name = sf->fondname ? sf->fondname : sf->familyname;
 
1719
    fclose(tempttf);
 
1720
    DumpResourceMap(res,resources,format);
 
1721
    free(dummynfnts);
 
1722
 
 
1723
    ret = true;
 
1724
    if ( format==ff_ttfmacbin ) {
 
1725
        header.macfilename = NULL;
 
1726
        header.binfilename = filename;
 
1727
            /* Fontographer uses the old suitcase format for both bitmaps and ttf */
 
1728
        header.type = CHR('F','F','I','L');
 
1729
        header.creator = CHR('D','M','O','V');
 
1730
        ret = DumpMacBinaryHeader(res,&header);
 
1731
    }
 
1732
    if ( ferror(res) ) ret = false;
 
1733
    if ( fclose(res)==-1 ) ret = 0;
 
1734
return( ret );
 
1735
}
 
1736
 
 
1737
int WriteMacBitmaps(char *filename,SplineFont *sf, int32 *sizes, int is_dfont,
 
1738
        EncMap *map) {
 
1739
    FILE *res;
 
1740
    int ret = 1;
 
1741
    struct resourcetype resources[3];
 
1742
    struct resource rlist[2][2];
 
1743
    struct macbinaryheader header;
 
1744
    char *binfilename, *pt, *dpt;
 
1745
 
 
1746
    /* The filename we've been given is for the outline font, which might or */
 
1747
    /*  might not be stuffed inside a bin file */
 
1748
    binfilename = galloc(strlen(filename)+strlen(".bmap.dfont")+1);
 
1749
    strcpy(binfilename,filename);
 
1750
    pt = strrchr(binfilename,'/');
 
1751
    if ( pt==NULL ) pt = binfilename; else ++pt;
 
1752
    dpt = strrchr(pt,'.');
 
1753
    if ( dpt==NULL )
 
1754
        dpt = pt+strlen(pt);
 
1755
    else if ( strmatch(dpt,".bin")==0 || strmatch(dpt,".dfont")==0 ) {
 
1756
        *dpt = '\0';
 
1757
        dpt = strrchr(pt,'.');
 
1758
        if ( dpt==NULL )
 
1759
            dpt = pt+strlen(pt);
 
1760
    }
 
1761
    strcpy(dpt,is_dfont?".bmap.dfont":__Mac?".bmap":".bmap.bin");
 
1762
 
 
1763
    if ( __Mac && !is_dfont )
 
1764
        res = tmpfile();
 
1765
    else
 
1766
        res = fopen(binfilename,"wb+");
 
1767
    if ( res==NULL ) {
 
1768
        free(binfilename);
 
1769
return( 0 );
 
1770
    }
 
1771
 
 
1772
    if ( is_dfont )
 
1773
        WriteDummyDFontHeaders(res);
 
1774
    else
 
1775
        WriteDummyMacHeaders(res);
 
1776
    memset(rlist,'\0',sizeof(rlist));
 
1777
    memset(resources,'\0',sizeof(resources));
 
1778
 
 
1779
    resources[0].tag = CHR('N','F','N','T');
 
1780
    resources[0].res = SFToNFNTs(res,sf,sizes,map);
 
1781
    resources[1].tag = CHR('F','O','N','D');
 
1782
    resources[1].res = rlist[1];
 
1783
    rlist[1][0].id = HashToId(sf->fontname,sf,map);
 
1784
    rlist[1][0].pos = SFToFOND(res,sf,rlist[1][0].id,false,sizes,map);
 
1785
    rlist[1][0].name = sf->fondname ? sf->fondname : sf->familyname;
 
1786
    DumpResourceMap(res,resources,is_dfont?ff_ttfdfont:ff_ttfmacbin);
 
1787
 
 
1788
    ret = true;
 
1789
    if ( !is_dfont ) {
 
1790
        header.macfilename = NULL;
 
1791
        header.binfilename = binfilename;
 
1792
            /* Fontographer uses the old suitcase format for both bitmaps and ttf */
 
1793
        header.type = CHR('F','F','I','L');
 
1794
        header.creator = CHR('D','M','O','V');
 
1795
        ret = DumpMacBinaryHeader(res,&header);
 
1796
    }
 
1797
    if ( ferror(res)) ret = false;
 
1798
    if ( fclose(res)==-1 ) ret = 0;
 
1799
    free(resources[0].res);
 
1800
    free(binfilename);
 
1801
return( ret );
 
1802
}
 
1803
 
 
1804
/* We have to worry about these font formats:
 
1805
  ff_pfbmacbin, ff_ttfmacbin, ff_ttfdfont, ff_otfdfont, ff_otfciddfont, ff_none
 
1806
  bf_ttf, bf_sfnt_dfont, bf_nfntmacbin,
 
1807
  bf_nfntdfont  I no long support this. OS/X doesn't support NFNTs so there's no point
 
1808
*/
 
1809
 
 
1810
int WriteMacFamily(char *filename,struct sflist *sfs,enum fontformat format,
 
1811
        enum bitmapformat bf,int flags, EncMap *map) {
 
1812
    FILE *res;
 
1813
    int ret = 1, r, i;
 
1814
    struct resourcetype resources[4];
 
1815
    struct resource *rlist;
 
1816
    struct macbinaryheader header;
 
1817
    struct sflist *sfi, *sfsub;
 
1818
    char buffer[80];
 
1819
    int freefilename = 0;
 
1820
    char *pt;
 
1821
    int id, fondcnt;
 
1822
    struct sflistlist *sfsl, *sfli;
 
1823
 
 
1824
    if ( format==ff_pfbmacbin ) {
 
1825
        for ( sfi=sfs; sfi!=NULL; sfi = sfi->next ) {
 
1826
            char *tempname;
 
1827
            MakeMacPSName(buffer,sfi->sf);
 
1828
#if !__Mac
 
1829
            strcat(buffer,".bin");
 
1830
#endif
 
1831
            tempname = galloc(strlen(filename)+strlen(buffer)+1);
 
1832
            strcpy(tempname,filename);
 
1833
            pt = strrchr(tempname,'/');
 
1834
            if ( pt==NULL ) pt=tempname-1;
 
1835
            strcpy(pt+1,buffer);
 
1836
            if ( strcmp(tempname,filename)==0 ) {
 
1837
                char *tf = galloc(strlen(filename)+20);
 
1838
                strcpy(tf,filename);
 
1839
                filename = tf;
 
1840
                freefilename = true;
 
1841
                pt = strrchr(filename,'.');
 
1842
                if ( pt==NULL || pt<strrchr(filename,'/'))
 
1843
                    pt = filename+strlen(filename)+1;
 
1844
#if __Mac
 
1845
                strcpy(pt-1,".fam");
 
1846
#else
 
1847
                strcpy(pt-1,".fam.bin");
 
1848
#endif
 
1849
            }
 
1850
            if ( WriteMacPSFont(tempname,sfi->sf,format,flags,sfi->map)==0 )
 
1851
return( 0 );
 
1852
            free(tempname);
 
1853
        }
 
1854
    } else if ( format!=ff_none || bf==bf_sfnt_dfont ) {
 
1855
        for ( sfi=sfs; sfi!=NULL; sfi = sfi->next ) {
 
1856
            sfi->tempttf = tmpfile();
 
1857
            if ( sfi->tempttf==NULL ||
 
1858
                    _WriteTTFFont(sfi->tempttf,sfi->sf,format==ff_none?ff_none:
 
1859
                                          format==ff_ttfmacbin?ff_ttf:
 
1860
                                          format-1,sfi->sizes,bf,flags,sfi->map)==0 ||
 
1861
                    ferror(sfi->tempttf) ) {
 
1862
                for ( sfsub=sfs; sfsub!=sfi; sfsub=sfsub->next )
 
1863
                    fclose( sfsub->tempttf );
 
1864
return( 0 );
 
1865
            }
 
1866
            rewind(sfi->tempttf);
 
1867
        }
 
1868
    }
 
1869
 
 
1870
    if ( __Mac && (format==ff_ttfmacbin || format==ff_pfbmacbin ||
 
1871
            (format==ff_none && bf==bf_nfntmacbin)))
 
1872
        res = tmpfile();
 
1873
    else
 
1874
        res = fopen(filename,"wb+");
 
1875
    if ( res==NULL ) {
 
1876
        for ( sfsub=sfs; sfsub!=NULL; sfsub=sfsub->next )
 
1877
            fclose( sfsub->tempttf );
 
1878
return( 0 );
 
1879
    }
 
1880
 
 
1881
    if ( format==ff_ttfdfont || format==ff_otfdfont || format==ff_otfciddfont ||
 
1882
            bf==bf_sfnt_dfont /*|| (format==ff_none && bf==bf_nfntdfont)*/)
 
1883
        WriteDummyDFontHeaders(res);
 
1884
    else
 
1885
        WriteDummyMacHeaders(res);
 
1886
    memset(resources,'\0',sizeof(resources));
 
1887
 
 
1888
    id = HashToId(sfs->sf->fontname,sfs->sf,sfs->map);
 
1889
 
 
1890
    r = 0;
 
1891
    if ( format==ff_ttfmacbin || format==ff_ttfdfont || format==ff_otfdfont ||
 
1892
            format==ff_otfciddfont || (format==ff_none && bf==bf_sfnt_dfont )) {
 
1893
        resources[r].tag = CHR('s','f','n','t');
 
1894
        for ( sfi=sfs, i=0; sfi!=NULL; sfi=sfi->next, ++i );
 
1895
        resources[r].res = gcalloc(i+1,sizeof(struct resource));
 
1896
        for ( sfi=sfs, i=0; sfi!=NULL; sfi=sfi->next, ++i ) {
 
1897
            resources[r].res[i].pos = TTFToResource(res,sfi->tempttf);
 
1898
            resources[r].res[i].id = sfi->id = id+i;
 
1899
            resources[r].res[i].flags = 0x00;   /* sfnts generally have resource flags 0x20 */
 
1900
            fclose(sfi->tempttf);
 
1901
        }
 
1902
        ++r;
 
1903
        if ( bf==bf_ttf || bf==bf_sfnt_dfont ) {
 
1904
            resources[r].tag = CHR('N','F','N','T');
 
1905
            resources[r++].res = BuildDummyNFNTfamilyList(res,sfs,id);
 
1906
        }
 
1907
    }
 
1908
    if ( bf==bf_nfntmacbin /*|| bf==bf_nfntdfont */) {
 
1909
        resources[r].tag = CHR('N','F','N','T');
 
1910
        resources[r++].res = SFsToNFNTs(res,sfs,id);
 
1911
    }
 
1912
 
 
1913
    sfsl = FondSplitter(sfs,&fondcnt);
 
1914
    rlist = gcalloc(fondcnt+1,sizeof(struct resource));
 
1915
    resources[r].tag = CHR('F','O','N','D');
 
1916
    resources[r++].res = rlist;
 
1917
    for ( i=0, sfli=sfsl; i<fondcnt && sfli!=NULL; ++i, sfli = sfli->next ) {
 
1918
        rlist[i].pos = SFsToFOND(res,sfli->sfs,id,format,bf);
 
1919
        rlist[i].flags = 0x00;  /* I've seen FONDs with resource flags 0, 0x20, 0x60 */
 
1920
        rlist[i].id = id+i;
 
1921
        rlist[i].name = sfli->fondname;
 
1922
    }
 
1923
    DumpResourceMap(res,resources,format!=ff_none?format:
 
1924
            bf==bf_nfntmacbin?ff_ttfmacbin:ff_ttfdfont);
 
1925
    SFListListFree(sfsl);
 
1926
    for ( i=0; i<r; ++i )
 
1927
        free(resources[i].res);
 
1928
 
 
1929
    ret = true;
 
1930
    if ( format==ff_ttfmacbin || format==ff_pfbmacbin ||
 
1931
            (format==ff_none && bf==bf_nfntmacbin) ) {
 
1932
        header.macfilename = NULL;
 
1933
        header.binfilename = filename;
 
1934
            /* Fontographer uses the old suitcase format for both bitmaps and ttf */
 
1935
        header.type = CHR('F','F','I','L');
 
1936
        header.creator = CHR('D','M','O','V');
 
1937
        ret = DumpMacBinaryHeader(res,&header);
 
1938
    }
 
1939
    if ( ferror(res) ) ret = false;
 
1940
    if ( fclose(res)==-1 ) ret = 0;
 
1941
    if ( freefilename )
 
1942
        free(filename);
 
1943
    for ( sfi=sfs; sfi!=NULL; sfi=sfi->next ) {
 
1944
        free( sfi->ids );
 
1945
        free( sfi->bdfs );
 
1946
    }
 
1947
return( ret );
 
1948
}
 
1949
 
 
1950
void SfListFree(struct sflist *sfs) {
 
1951
    struct sflist *sfi;
 
1952
 
 
1953
    while ( sfs!=NULL ) {
 
1954
        sfi = sfs->next;
 
1955
        free(sfs->sizes);
 
1956
        EncMapFree(sfs->map);
 
1957
        chunkfree(sfs,sizeof(struct sflist));
 
1958
        sfs = sfi;
 
1959
    }
 
1960
}
 
1961
#endif
 
1962
 
 
1963
/* ******************************** Reading ********************************* */
 
1964
 
 
1965
static SplineFont *SearchPostscriptResources(FILE *f,long rlistpos,int subcnt,long rdata_pos,
 
1966
        long name_list, int flags) {
 
1967
    long here = ftell(f);
 
1968
    long *offsets, lenpos;
 
1969
    int rname = -1, tmp;
 
1970
    int ch1, ch2;
 
1971
    int len, type, i, j, rlen;
 
1972
    unsigned short id, *rsrcids;
 
1973
    /* I don't pretend to understand the rational behind the format of a */
 
1974
    /*  postscript font. It appears to be split up into chunks where the */
 
1975
    /*  maximum chunk size is 0x800, each section (ascii, binary, ascii, eof) */
 
1976
    /*  has its own set of chunks (ie chunks don't cross sections) */
 
1977
    char *buffer=NULL;
 
1978
    int max = 0;
 
1979
    FILE *pfb;
 
1980
    FontDict *fd;
 
1981
    SplineFont *sf;
 
1982
 
 
1983
    fseek(f,rlistpos,SEEK_SET);
 
1984
    rsrcids = gcalloc(subcnt,sizeof(short));
 
1985
    offsets = gcalloc(subcnt,sizeof(long));
 
1986
    for ( i=0; i<subcnt; ++i ) {
 
1987
        rsrcids[i] = getushort(f);
 
1988
        tmp = (short) getushort(f);
 
1989
        if ( rname==-1 ) rname = tmp;
 
1990
        /* flags = */ getc(f);
 
1991
        ch1 = getc(f); ch2 = getc(f);
 
1992
        offsets[i] = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
 
1993
        /* mbz = */ getlong(f);
 
1994
    }
 
1995
 
 
1996
    pfb = tmpfile();
 
1997
    if ( pfb==NULL ) {
 
1998
        LogError( _("Can't open temporary file for postscript output\n") );
 
1999
        fseek(f,here,SEEK_SET );
 
2000
        free(offsets);
 
2001
return(NULL);
 
2002
    }
 
2003
 
 
2004
    putc(0x80,pfb);
 
2005
    putc(1,pfb);
 
2006
    lenpos = ftell(pfb);
 
2007
    putc(0,pfb);
 
2008
    putc(0,pfb);
 
2009
    putc(0,pfb);
 
2010
    putc(0,pfb);
 
2011
    len = 0; type = 1;
 
2012
    id = 501;
 
2013
    for ( i=0; i<subcnt; ++i ) {
 
2014
        for ( j=0; j<subcnt; ++j )
 
2015
            if ( rsrcids[j]==id )
 
2016
                break;
 
2017
        if ( j == subcnt ) {
 
2018
            LogError( _("Missing POST resource %u\n"), id );
 
2019
            break;
 
2020
        }
 
2021
        id = id + 1;
 
2022
        fseek(f,offsets[j],SEEK_SET);
 
2023
        rlen = getlong(f);
 
2024
        ch1 = getc(f); ch2 = getc(f);
 
2025
        rlen -= 2;      /* those two bytes don't count as real data */
 
2026
        if ( ch1==type )
 
2027
            len += rlen;
 
2028
        else {
 
2029
            long hold = ftell(pfb);
 
2030
            fseek(pfb,lenpos,SEEK_SET);
 
2031
            putc(len>>24,pfb);
 
2032
            putc((len>>16)&0xff,pfb);
 
2033
            putc((len>>8)&0xff,pfb);
 
2034
            putc(len&0xff,pfb);
 
2035
            fseek(pfb,hold,SEEK_SET);
 
2036
            if ( ch1==5 )       /* end of font mark */
 
2037
    break;
 
2038
            putc(0x80,pfb);
 
2039
            putc(ch1,pfb);
 
2040
            lenpos = ftell(pfb);
 
2041
            putc(0,pfb);
 
2042
            putc(0,pfb);
 
2043
            putc(0,pfb);
 
2044
            putc(0,pfb);
 
2045
            type = ch1;
 
2046
            len = rlen;
 
2047
        }
 
2048
        if ( rlen>max ) {
 
2049
            free(buffer);
 
2050
            max = rlen;
 
2051
            if ( max<0x800 ) max = 0x800;
 
2052
            buffer=galloc(max);
 
2053
            if ( buffer==NULL ) {
 
2054
                LogError( _("Out of memory\n") );
 
2055
                exit( 1 );
 
2056
            }
 
2057
        }
 
2058
        fread(buffer,1,rlen,f);
 
2059
        fwrite(buffer,1,rlen,pfb);
 
2060
    }
 
2061
    free(buffer);
 
2062
    free(offsets);
 
2063
        free(rsrcids);
 
2064
    putc(0x80,pfb);
 
2065
    putc(3,pfb);
 
2066
    fseek(pfb,lenpos,SEEK_SET);
 
2067
    putc(len>>24,pfb);
 
2068
    putc((len>>16)&0xff,pfb);
 
2069
    putc((len>>8)&0xff,pfb);
 
2070
    putc(len&0xff,pfb);
 
2071
    fseek(f,here,SEEK_SET);
 
2072
    rewind(pfb);
 
2073
    if ( flags&ttf_onlynames )
 
2074
return( (SplineFont *) _NamesReadPostscript(pfb) );     /* This closes the font for us */
 
2075
 
 
2076
    fd = _ReadPSFont(pfb);
 
2077
    sf = NULL;
 
2078
    if ( fd!=NULL ) {
 
2079
        sf = SplineFontFromPSFont(fd);
 
2080
        PSFontFree(fd);
 
2081
        /* There is no FOND in a postscript file, so we can't read any kerning*/
 
2082
    }
 
2083
    fclose(pfb);
 
2084
return( sf );
 
2085
}
 
2086
 
 
2087
static SplineFont *SearchTtfResources(FILE *f,long rlistpos,int subcnt,long rdata_pos,
 
2088
        long name_list,char *filename,int flags,enum openflags openflags) {
 
2089
    long here, start = ftell(f);
 
2090
    long roff;
 
2091
    int rname = -1;
 
2092
    int ch1, ch2;
 
2093
    int len, i, rlen, ilen;
 
2094
    /* The sfnt resource is just a copy of the ttf file */
 
2095
    char *buffer=NULL;
 
2096
    int max = 0;
 
2097
    FILE *ttf;
 
2098
    SplineFont *sf;
 
2099
    int which = 0;
 
2100
    char **names;
 
2101
    char *pt,*lparen;
 
2102
    char *chosenname=NULL;
 
2103
 
 
2104
    fseek(f,rlistpos,SEEK_SET);
 
2105
    if ( subcnt>1 || (flags&ttf_onlynames) ) {
 
2106
        names = gcalloc(subcnt+1,sizeof(char *));
 
2107
        for ( i=0; i<subcnt; ++i ) {
 
2108
            /* resource id = */ getushort(f);
 
2109
            /* rname = (short) */ getushort(f);
 
2110
            /* flags = */ getc(f);
 
2111
            ch1 = getc(f); ch2 = getc(f);
 
2112
            roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
 
2113
            /* mbz = */ getlong(f);
 
2114
            here = ftell(f);
 
2115
            names[i] = TTFGetFontName(f,roff+4,roff+4);
 
2116
            if ( names[i]==NULL ) {
 
2117
                char buffer[32];
 
2118
                sprintf( buffer, "Nameless%d", i );
 
2119
                names[i] = copy(buffer);
 
2120
            }
 
2121
            fseek(f,here,SEEK_SET);
 
2122
        }
 
2123
        if ( flags&ttf_onlynames ) {
 
2124
return( (SplineFont *) names );
 
2125
        }
 
2126
        if ((pt = strrchr(filename,'/'))==NULL ) pt = filename;
 
2127
        if ( (lparen = strchr(pt,'('))!=NULL && strchr(lparen,')')!=NULL ) {
 
2128
            char *find = copy(lparen+1);
 
2129
            pt = strchr(find,')');
 
2130
            if ( pt!=NULL ) *pt='\0';
 
2131
            for ( which=subcnt-1; which>=0; --which )
 
2132
                if ( strcmp(names[which],find)==0 )
 
2133
            break;
 
2134
            if ( which==-1 ) {
 
2135
                char *fn = copy(filename);
 
2136
                fn[lparen-filename] = '\0';
 
2137
#if !defined(FONTFORGE_CONFIG_NO_WINDOWING_UI)
 
2138
                gwwv_post_error(_("Not in Collection"),_("%s is not in %.100s"),find,fn);
 
2139
#endif
 
2140
                free(fn);
 
2141
            }
 
2142
            free(find);
 
2143
#if !defined(FONTFORGE_CONFIG_NO_WINDOWING_UI)
 
2144
        } else if ( no_windowing_ui )
 
2145
            which = 0;
 
2146
        else
 
2147
            which = gwwv_choose(_("Pick a font, any font..."),(const char **) names,subcnt,0,_("There are multiple fonts in this file, pick one"));
 
2148
#else
 
2149
        } else
 
2150
            which = 0;
 
2151
#endif          /* FONTFORGE_CONFIG_NO_WINDOWING_UI */
 
2152
        if ( lparen==NULL && which!=-1 )
 
2153
            chosenname = copy(names[which]);
 
2154
        for ( i=0; i<subcnt; ++i )
 
2155
            free(names[i]);
 
2156
        free(names);
 
2157
        fseek(f,rlistpos,SEEK_SET);
 
2158
    }
 
2159
 
 
2160
    for ( i=0; i<subcnt; ++i ) {
 
2161
        /* resource id = */ getushort(f);
 
2162
        rname = (short) getushort(f);
 
2163
        /* flags = */ getc(f);
 
2164
        ch1 = getc(f); ch2 = getc(f);
 
2165
        roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
 
2166
        /* mbz = */ getlong(f);
 
2167
        if ( i!=which )
 
2168
    continue;
 
2169
        here = ftell(f);
 
2170
 
 
2171
        ttf = tmpfile();
 
2172
        if ( ttf==NULL ) {
 
2173
            LogError( _("Can't open temporary file for truetype output.\n") );
 
2174
    continue;
 
2175
        }
 
2176
 
 
2177
        fseek(f,roff,SEEK_SET);
 
2178
        ilen = rlen = getlong(f);
 
2179
        if ( rlen>16*1024 )
 
2180
            ilen = 16*1024;
 
2181
        if ( ilen>max ) {
 
2182
            free(buffer);
 
2183
            max = ilen;
 
2184
            if ( max<0x800 ) max = 0x800;
 
2185
            buffer=malloc(max);
 
2186
        }
 
2187
        for ( len=0; len<rlen; ) {
 
2188
            int temp = ilen;
 
2189
            if ( rlen-len<ilen ) temp = rlen-len;
 
2190
            temp = fread(buffer,1,temp,f);
 
2191
            if ( temp==EOF )
 
2192
        break;
 
2193
            fwrite(buffer,1,temp,ttf);
 
2194
            len += temp;
 
2195
        }
 
2196
        rewind(ttf);
 
2197
        sf = _SFReadTTF(ttf,flags,openflags,NULL,NULL);
 
2198
        fclose(ttf);
 
2199
        if ( sf!=NULL ) {
 
2200
            free(buffer);
 
2201
            fseek(f,start,SEEK_SET);
 
2202
            if ( sf->chosenname==NULL ) sf->chosenname = chosenname;
 
2203
return( sf );
 
2204
        }
 
2205
        fseek(f,here,SEEK_SET);
 
2206
    }
 
2207
    free(chosenname);
 
2208
    free(buffer);
 
2209
    fseek(f,start,SEEK_SET);
 
2210
return( NULL );
 
2211
}
 
2212
 
 
2213
typedef struct fond {
 
2214
    char *fondname;
 
2215
    int first, last;
 
2216
    int assoc_cnt;
 
2217
    struct assoc {
 
2218
        short size, style, id;
 
2219
    } *assoc;
 
2220
        /* size==0 => scalable */
 
2221
        /* style>>8 is the bit depth (0=>1, 1=>2, 2=>4, 3=>8) */
 
2222
        /* search order for ID is sfnt, NFNT, FONT */
 
2223
    int stylewidthcnt;
 
2224
    struct stylewidths {
 
2225
        short style;
 
2226
        short *widthtab;                /* 4.12 fixed number with the width specified as a fraction of an em */
 
2227
    } *stylewidths;
 
2228
    int stylekerncnt;
 
2229
    struct stylekerns {
 
2230
        short style;
 
2231
        int kernpairs;
 
2232
        struct kerns {
 
2233
            unsigned char ch1, ch2;
 
2234
            short offset;               /* 4.12 */
 
2235
        } *kerns;
 
2236
    } *stylekerns;
 
2237
    char *psnames[48];
 
2238
    struct fond *next;
 
2239
} FOND;
 
2240
 
 
2241
struct MacFontRec {
 
2242
   short fontType;
 
2243
   short firstChar;
 
2244
   short lastChar;
 
2245
   short widthMax;
 
2246
   short kernMax;               /* bb learing */
 
2247
   short Descent;               /* maximum negative distance below baseline*/
 
2248
   short fRectWidth;            /* bounding box width */
 
2249
   short fRectHeight;           /* bounding box height */
 
2250
   unsigned short *offsetWidths;/* offset to start of offset/width table */
 
2251
        /* 0xffff => undefined, else high byte is offset in locTable, */
 
2252
        /*  low byte is width */
 
2253
   short ascent;
 
2254
   short descent;
 
2255
   short leading;
 
2256
   short rowWords;              /* shorts per row */
 
2257
   unsigned short *fontImage;   /* rowWords*fRectHeight */
 
2258
        /* Images for all characters plus one extra for undefined */
 
2259
   unsigned short *locs;        /* lastchar-firstchar+3 words */
 
2260
        /* Horizontal offset to start of n'th character. Note: applies */
 
2261
        /*  to each row. Missing characters have same loc as following */
 
2262
};
 
2263
 
 
2264
static void FondListFree(FOND *list) {
 
2265
    FOND *next;
 
2266
    int i;
 
2267
 
 
2268
    while ( list!=NULL ) {
 
2269
        next = list->next;
 
2270
        free(list->assoc);
 
2271
        for ( i=0; i<list->stylewidthcnt; ++i )
 
2272
            free(list->stylewidths[i].widthtab);
 
2273
        free(list->stylewidths);
 
2274
        for ( i=0; i<list->stylekerncnt; ++i )
 
2275
            free(list->stylekerns[i].kerns);
 
2276
        free(list->stylekerns);
 
2277
        for ( i=0; i<48; ++i )
 
2278
            free(list->psnames[i]);
 
2279
        free(list);
 
2280
        list = next;
 
2281
    }
 
2282
}
 
2283
 
 
2284
/* There's probably only one fond in the file, but there could be more so be */
 
2285
/*  prepared... */
 
2286
/* I want the fond: */
 
2287
/*  to get the fractional widths for the SWIDTH entry on bdf */
 
2288
/*  to get the font name */
 
2289
/*  to get the font association tables */
 
2290
/*  to get the style flags */
 
2291
/* http://developer.apple.com/techpubs/mac/Text/Text-269.html */
 
2292
static FOND *BuildFondList(FILE *f,long rlistpos,int subcnt,long rdata_pos,
 
2293
        long name_list,int flags) {
 
2294
    long here, start = ftell(f);
 
2295
    long offset;
 
2296
    int rname = -1;
 
2297
    char name[300];
 
2298
    int ch1, ch2;
 
2299
    int i, j, k, cnt, isfixed;
 
2300
    FOND *head=NULL, *cur;
 
2301
    long widoff, kernoff, styleoff;
 
2302
 
 
2303
    fseek(f,rlistpos,SEEK_SET);
 
2304
    for ( i=0; i<subcnt; ++i ) {
 
2305
        /* resource id = */ getushort(f);
 
2306
        rname = (short) getushort(f);
 
2307
        /* flags = */ getc(f);
 
2308
        ch1 = getc(f); ch2 = getc(f);
 
2309
        offset = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
 
2310
        /* mbz = */ getlong(f);
 
2311
        here = ftell(f);
 
2312
 
 
2313
        cur = gcalloc(1,sizeof(FOND));
 
2314
        cur->next = head;
 
2315
        head = cur;
 
2316
 
 
2317
        if ( rname!=-1 ) {
 
2318
            fseek(f,name_list+rname,SEEK_SET);
 
2319
            ch1 = getc(f);
 
2320
            fread(name,1,ch1,f);
 
2321
            name[ch1] = '\0';
 
2322
            cur->fondname = copy(name);
 
2323
        }
 
2324
 
 
2325
        offset += 4;
 
2326
        fseek(f,offset,SEEK_SET);
 
2327
        isfixed = getushort(f)&0x8000?1:0;
 
2328
        /* family id = */ getushort(f);
 
2329
        cur->first = getushort(f);
 
2330
        cur->last = getushort(f);
 
2331
/* on a 1 point font... */
 
2332
        /* ascent = */ getushort(f);
 
2333
        /* descent = */ getushort(f);
 
2334
        /* leading = */ getushort(f);
 
2335
        /* widmax = */ getushort(f);
 
2336
        if ( (widoff = getlong(f))!=0 ) widoff += offset;
 
2337
        if ( (kernoff = getlong(f))!=0 ) kernoff += offset;
 
2338
        if ( (styleoff = getlong(f))!=0 ) styleoff += offset;
 
2339
        for ( j=0; j<9; ++j )
 
2340
            getushort(f);
 
2341
        /* internal & undefined, for international scripts = */ getlong(f);
 
2342
        /* version = */ getushort(f);
 
2343
        cur->assoc_cnt = getushort(f)+1;
 
2344
        cur->assoc = gcalloc(cur->assoc_cnt,sizeof(struct assoc));
 
2345
        for ( j=0; j<cur->assoc_cnt; ++j ) {
 
2346
            cur->assoc[j].size = getushort(f);
 
2347
            cur->assoc[j].style = getushort(f);
 
2348
            cur->assoc[j].id = getushort(f);
 
2349
        }
 
2350
        if ( widoff!=0 ) {
 
2351
            fseek(f,widoff,SEEK_SET);
 
2352
            cnt = getushort(f)+1;
 
2353
            cur->stylewidthcnt = cnt;
 
2354
            cur->stylewidths = gcalloc(cnt,sizeof(struct stylewidths));
 
2355
            for ( j=0; j<cnt; ++j ) {
 
2356
                cur->stylewidths[j].style = getushort(f);
 
2357
                cur->stylewidths[j].widthtab = galloc((cur->last-cur->first+3)*sizeof(short));
 
2358
                for ( k=cur->first; k<=cur->last+2; ++k )
 
2359
                    cur->stylewidths[j].widthtab[k] = getushort(f);
 
2360
            }
 
2361
        }
 
2362
        if ( kernoff!=0 && (flags&ttf_onlykerns) ) {
 
2363
            fseek(f,kernoff,SEEK_SET);
 
2364
            cnt = getushort(f)+1;
 
2365
            cur->stylekerncnt = cnt;
 
2366
            cur->stylekerns = gcalloc(cnt,sizeof(struct stylekerns));
 
2367
            for ( j=0; j<cnt; ++j ) {
 
2368
                cur->stylekerns[j].style = getushort(f);
 
2369
                cur->stylekerns[j].kernpairs = getushort(f);
 
2370
                cur->stylekerns[j].kerns = galloc(cur->stylekerns[j].kernpairs*sizeof(struct kerns));
 
2371
                for ( k=0; k<cur->stylekerns[j].kernpairs; ++k ) {
 
2372
                    cur->stylekerns[j].kerns[k].ch1 = getc(f);
 
2373
                    cur->stylekerns[j].kerns[k].ch2 = getc(f);
 
2374
                    cur->stylekerns[j].kerns[k].offset = getushort(f);
 
2375
                }
 
2376
            }
 
2377
        }
 
2378
        if ( styleoff!=0 ) {
 
2379
            uint8 stringoffsets[48];
 
2380
            int strcnt, stringlen, format;
 
2381
            char **strings, *pt;
 
2382
            fseek(f,styleoff,SEEK_SET);
 
2383
            /* class = */ getushort(f);
 
2384
            /* glyph encoding offset = */ getlong(f);
 
2385
            /* reserved = */ getlong(f);
 
2386
            for ( j=0; j<48; ++j )
 
2387
                stringoffsets[j] = getc(f);
 
2388
            strcnt = getushort(f);
 
2389
            strings = galloc(strcnt*sizeof(char *));
 
2390
            for ( j=0; j<strcnt; ++j ) {
 
2391
                stringlen = getc(f);
 
2392
                strings[j] = galloc(stringlen+2);
 
2393
                strings[j][0] = stringlen;
 
2394
                strings[j][stringlen+1] = '\0';
 
2395
                for ( k=0; k<stringlen; ++k )
 
2396
                    strings[j][k+1] = getc(f);
 
2397
            }
 
2398
            for ( j=0; j<48; ++j ) {
 
2399
                for ( k=j-1; k>=0; --k )
 
2400
                    if ( stringoffsets[j]==stringoffsets[k] )
 
2401
                break;
 
2402
                if ( k!=-1 )
 
2403
            continue;           /* this style doesn't exist */
 
2404
                format = stringoffsets[j]-1;
 
2405
                stringlen = strings[0][0];
 
2406
                if ( format!=0 )
 
2407
                    for ( k=0; k<strings[format][0]; ++k )
 
2408
                        stringlen += strings[ strings[format][k+1]-1 ][0];
 
2409
                pt = cur->psnames[j] = galloc(stringlen+1);
 
2410
                strcpy(pt,strings[ 0 ]+1);
 
2411
                pt += strings[ 0 ][0];
 
2412
                if ( format!=0 )
 
2413
                    for ( k=0; k<strings[format][0]; ++k ) {
 
2414
                        strcpy(pt,strings[ strings[format][k+1]-1 ]+1);
 
2415
                        pt += strings[ strings[format][k+1]-1 ][0];
 
2416
                    }
 
2417
                *pt = '\0';
 
2418
            }
 
2419
            for ( j=0; j<strcnt; ++j )
 
2420
                free(strings[j]);
 
2421
            free(strings);
 
2422
        }
 
2423
        fseek(f,here,SEEK_SET);
 
2424
    }
 
2425
    fseek(f,start,SEEK_SET);
 
2426
return( head );
 
2427
}
 
2428
 
 
2429
static BDFChar *NFNTCvtBitmap(struct MacFontRec *font,int index,SplineFont *sf,int gid) {
 
2430
    BDFChar *bdfc;
 
2431
    int i,j, bits, bite, bit;
 
2432
 
 
2433
    bdfc = chunkalloc(sizeof(BDFChar));
 
2434
    bdfc->xmin = (font->offsetWidths[index]>>8)+font->kernMax;
 
2435
    bdfc->xmax = bdfc->xmin + font->locs[index+1]-font->locs[index]-1;
 
2436
    if ( bdfc->xmax<bdfc->xmin )
 
2437
        bdfc->xmax = bdfc->xmin;                /* Empty glyph mark */
 
2438
    bdfc->ymin = -font->descent;
 
2439
    bdfc->ymax = font->ascent-1;
 
2440
    bdfc->width = font->offsetWidths[index]&0xff;
 
2441
    bdfc->vwidth = font->ascent + font->descent;
 
2442
    bdfc->bytes_per_line = ((bdfc->xmax-bdfc->xmin)>>3) + 1;
 
2443
    bdfc->bitmap = gcalloc(bdfc->bytes_per_line*font->fRectHeight,sizeof(uint8));
 
2444
    bdfc->orig_pos = gid;
 
2445
    bdfc->sc = sf->glyphs[gid];
 
2446
 
 
2447
    bits = font->locs[index]; bite = font->locs[index+1];
 
2448
    for ( i=0; i<font->fRectHeight; ++i ) {
 
2449
        uint16 *test = font->fontImage + i*font->rowWords;
 
2450
        uint8 *bpt = bdfc->bitmap + i*bdfc->bytes_per_line;
 
2451
        for ( bit=bits, j=0; bit<bite; ++bit, ++j ) {
 
2452
            if ( test[bit>>4]&(0x8000>>(bit&0xf)) )
 
2453
                bpt[j>>3] |= (0x80>>(j&7));
 
2454
        }
 
2455
    }
 
2456
    BCCompressBitmap(bdfc);
 
2457
return( bdfc );
 
2458
}
 
2459
 
 
2460
static void LoadNFNT(FILE *f,long offset, SplineFont *sf, int size) {
 
2461
    long here = ftell(f);
 
2462
    long baseow;
 
2463
    long ow;
 
2464
    int i,gid;
 
2465
    struct MacFontRec font;
 
2466
    BDFFont *bdf;
 
2467
    SplineChar *sc;
 
2468
 
 
2469
    offset += 4;                /* skip over the length */
 
2470
    fseek(f,offset,SEEK_SET);
 
2471
    memset(&font,'\0',sizeof(struct MacFontRec));
 
2472
    font.fontType = getushort(f);
 
2473
    font.firstChar = getushort(f);
 
2474
    font.lastChar = getushort(f);
 
2475
    font.widthMax = getushort(f);
 
2476
    font.kernMax = (short) getushort(f);
 
2477
    font.Descent = (short) getushort(f);
 
2478
    font.fRectWidth = getushort(f);
 
2479
    font.fRectHeight = getushort(f);
 
2480
    baseow = ftell(f);
 
2481
    ow = getushort(f);
 
2482
    font.ascent = getushort(f);
 
2483
    font.descent = getushort(f);
 
2484
    if ( font.Descent>=0 ) {
 
2485
        ow |= (font.Descent<<16);
 
2486
        font.Descent = -font.descent;           /* Possibly overkill, but should be safe */
 
2487
    }
 
2488
    font.leading = getushort(f);
 
2489
    font.rowWords = getushort(f);
 
2490
    if ( font.rowWords!=0 ) {
 
2491
        font.fontImage = gcalloc(font.rowWords*font.fRectHeight,sizeof(short));
 
2492
        font.locs = gcalloc(font.lastChar-font.firstChar+3,sizeof(short));
 
2493
        font.offsetWidths = gcalloc(font.lastChar-font.firstChar+3,sizeof(short));
 
2494
        for ( i=0; i<font.rowWords*font.fRectHeight; ++i )
 
2495
            font.fontImage[i] = getushort(f);
 
2496
        for ( i=0; i<font.lastChar-font.firstChar+3; ++i )
 
2497
            font.locs[i] = getushort(f);
 
2498
        fseek(f,baseow+2*ow,SEEK_SET);
 
2499
        for ( i=0; i<font.lastChar-font.firstChar+3; ++i )
 
2500
            font.offsetWidths[i] = getushort(f);
 
2501
    }
 
2502
    fseek(f,here,SEEK_SET);
 
2503
    if ( font.rowWords==0 )
 
2504
return;
 
2505
 
 
2506
    /* Now convert the FONT record to one of my BDF structs */
 
2507
    bdf = gcalloc(1,sizeof(BDFFont));
 
2508
    bdf->sf = sf;
 
2509
    bdf->next = sf->bitmaps;
 
2510
    sf->bitmaps = bdf;
 
2511
    bdf->glyphcnt = bdf->glyphmax = sf->glyphcnt;
 
2512
    bdf->pixelsize = font.ascent+font.descent;
 
2513
    bdf->glyphs = gcalloc(sf->glyphcnt,sizeof(BDFChar *));
 
2514
    bdf->ascent = font.ascent;
 
2515
    bdf->descent = font.descent;
 
2516
    bdf->res = 72;
 
2517
    for ( i=font.firstChar; i<=font.lastChar+1; ++i ) {
 
2518
        if ( i!=font.lastChar+1 )
 
2519
            sc = SFMakeChar(sf,sf->map,i);
 
2520
        else {
 
2521
            sc = SFGetChar(sf,-1,".notdef");
 
2522
            if ( sc==NULL )
 
2523
    break;
 
2524
        }
 
2525
        gid = sc->orig_pos;
 
2526
        bdf->glyphs[gid] = NFNTCvtBitmap(&font,i-font.firstChar,sf,gid);
 
2527
        if ( !sf->glyphs[gid]->widthset ) {
 
2528
            sf->glyphs[gid]->width = bdf->glyphs[gid]->width*(sf->ascent+sf->descent)/bdf->pixelsize;
 
2529
            sf->glyphs[gid]->widthset = true;
 
2530
        }
 
2531
    }
 
2532
 
 
2533
    free(font.fontImage);
 
2534
    free(font.locs);
 
2535
    free(font.offsetWidths);
 
2536
}
 
2537
 
 
2538
static char *BuildName(char *family,int style) {
 
2539
    char buffer[350];
 
2540
 
 
2541
    strncpy(buffer,family,200);
 
2542
    if ( style!=0 )
 
2543
        strcat(buffer,"-");
 
2544
    if ( style&sf_bold )
 
2545
        strcat(buffer,"Bold");
 
2546
    if ( style&sf_italic )
 
2547
        strcat(buffer,"Italic");
 
2548
    if ( style&sf_underline )
 
2549
        strcat(buffer,"Underline");
 
2550
    if ( style&sf_outline )
 
2551
        strcat(buffer,"Outline");
 
2552
    if ( style&sf_shadow )
 
2553
        strcat(buffer,"Shadow");
 
2554
    if ( style&sf_condense )
 
2555
        strcat(buffer,"Condensed");
 
2556
    if ( style&sf_extend )
 
2557
        strcat(buffer,"Extended");
 
2558
return( copy(buffer));
 
2559
}
 
2560
 
 
2561
static int GuessStyle(char *fontname,int *styles,int style_cnt) {
 
2562
    int which, style;
 
2563
    char *stylenames = _GetModifiers(fontname,NULL,NULL);
 
2564
 
 
2565
    style = _MacStyleCode(stylenames,NULL,NULL);
 
2566
    for ( which = style_cnt; which>=0; --which )
 
2567
        if ( styles[which] == style )
 
2568
return( which );
 
2569
 
 
2570
return( -1 );
 
2571
}
 
2572
 
 
2573
static FOND *PickFOND(FOND *fondlist,char *filename,char **name, int *style) {
 
2574
    int i,j;
 
2575
    FOND *test;
 
2576
    uint8 stylesused[96];
 
2577
    char **names;
 
2578
    int cnt, which;
 
2579
    char *pt, *lparen;
 
2580
    FOND **fonds = NULL, *fond = NULL;
 
2581
    int *styles = NULL;
 
2582
    char *find = NULL;
 
2583
 
 
2584
    if ((pt = strrchr(filename,'/'))!=NULL ) pt = filename;
 
2585
    if ( (lparen = strchr(filename,'('))!=NULL && strchr(lparen,')')!=NULL ) {
 
2586
        find = copy(lparen+1);
 
2587
        pt = strchr(find,')');
 
2588
        if ( pt!=NULL ) *pt='\0';
 
2589
        for ( test=fondlist; test!=NULL; test=test->next ) {
 
2590
            for ( i=0; i<48; ++i )
 
2591
                if ( test->psnames[i]!=NULL && strcmp(find,test->psnames[i])==0 ) {
 
2592
                    *style = (i&3) | ((i&~3)<<1);       /* PS styles skip underline bit */
 
2593
                    *name = copy(test->psnames[i]);
 
2594
return( test );
 
2595
                }
 
2596
        }
 
2597
    }
 
2598
 
 
2599
    /* The file may contain multiple families, and each family may contain */
 
2600
    /*  multiple styles (and each style may contain multiple sizes, but that's */
 
2601
    /*  not an issue for us here) */
 
2602
    names = NULL;
 
2603
    for ( i=0; i<2; ++i ) {
 
2604
        cnt = 0;
 
2605
        for ( test=fondlist; test!=NULL; test=test->next ) if ( test->fondname!=NULL ) {
 
2606
            memset(stylesused,0,sizeof(stylesused));
 
2607
            for ( j=0; j<test->assoc_cnt; ++j ) {
 
2608
                if ( test->assoc[j].size!=0 && !stylesused[test->assoc[j].style]) {
 
2609
                    stylesused[test->assoc[j].style]=true;
 
2610
                    if ( names!=NULL ) {
 
2611
                        names[cnt] = BuildName(test->fondname,test->assoc[j].style);
 
2612
                        styles[cnt] = test->assoc[j].style;
 
2613
                        fonds[cnt] = test;
 
2614
                    }
 
2615
                    ++cnt;
 
2616
                }
 
2617
            }
 
2618
        }
 
2619
        if ( names==NULL ) {
 
2620
            names = gcalloc(cnt+1,sizeof(char *));
 
2621
            fonds = galloc(cnt*sizeof(FOND *));
 
2622
            styles = galloc(cnt*sizeof(int));
 
2623
        }
 
2624
    }
 
2625
 
 
2626
    if ( find!=NULL ) {
 
2627
        for ( which=cnt-1; which>=0; --which )
 
2628
            if ( strcmp(names[which],find)==0 )
 
2629
        break;
 
2630
        if ( which==-1 && strstrmatch(find,test->fondname)!=NULL )
 
2631
            which = GuessStyle(find,styles,cnt);
 
2632
        if ( which==-1 ) {
 
2633
            char *fn = copy(filename);
 
2634
            fn[lparen-filename] = '\0';
 
2635
#if !defined(FONTFORGE_CONFIG_NO_WINDOWING_UI)
 
2636
            gwwv_post_error(_("Not in Collection"),_("%s is not in %.100s"),find,fn);
 
2637
#endif
 
2638
            free(fn);
 
2639
        }
 
2640
        free(find);
 
2641
    } else if ( cnt==1 )
 
2642
        which = 0;
 
2643
#if !defined(FONTFORGE_CONFIG_NO_WINDOWING_UI)
 
2644
    else if ( no_windowing_ui )
 
2645
        which = 0;
 
2646
    else
 
2647
        which = gwwv_choose(_("Pick a font, any font..."),(const char **) names,cnt,0,
 
2648
                _("There are multiple fonts in this file, pick one"));
 
2649
#elif defined(FONTFORGE_CONFIG_NO_WINDOWING_UI)
 
2650
    else
 
2651
        which = 0;
 
2652
#endif          /* FONTFORGE_CONFIG_NO_WINDOWING_UI */
 
2653
 
 
2654
    if ( which!=-1 ) {
 
2655
        fond = fonds[which];
 
2656
        *name = copy(names[which]);
 
2657
        *style = styles[which];
 
2658
    }
 
2659
    for ( i=0; i<cnt; ++i )
 
2660
        free(names[i]);
 
2661
    free(names); free(fonds); free(styles);
 
2662
    if ( which==-1 )
 
2663
return( NULL );
 
2664
 
 
2665
return( fond );
 
2666
}
 
2667
 
 
2668
static SplineFont *SearchBitmapResources(FILE *f,long rlistpos,int subcnt,long rdata_pos,
 
2669
        long name_list,char *filename,FOND *fondlist,int flags) {
 
2670
    long start = ftell(f);
 
2671
    long roff;
 
2672
    int rname = -1;
 
2673
    int ch1, ch2;
 
2674
    int i,j;
 
2675
    int res_id;
 
2676
    char *name;
 
2677
    FOND *fond;
 
2678
    int style;
 
2679
    SplineFont *sf;
 
2680
    int find_id;
 
2681
    SplineChar *sc;
 
2682
 
 
2683
    fond = PickFOND(fondlist,filename,&name,&style);
 
2684
    if ( fond==NULL )
 
2685
return( NULL );
 
2686
 
 
2687
    find_id=-1;
 
2688
    if ( flags&ttf_onlyonestrike ) {
 
2689
        int biggest = 0;
 
2690
        for ( i=0; i<fond->assoc_cnt; ++i ) {
 
2691
            if ( fond->assoc[i].style==style && fond->assoc[i].size>biggest ) {
 
2692
                biggest = fond->assoc[i].size;
 
2693
                find_id = fond->assoc[i].id;
 
2694
            }
 
2695
        }
 
2696
    }
 
2697
 
 
2698
    sf = SplineFontBlank(257);
 
2699
    free(sf->fontname); sf->fontname = name;
 
2700
    free(sf->familyname); sf->familyname = copy(fond->fondname);
 
2701
    sf->fondname = copy(fond->fondname);
 
2702
    free(sf->fullname); sf->fullname = copy(name);
 
2703
    free(sf->origname); sf->origname = NULL;
 
2704
    if ( style & sf_bold ) {
 
2705
        free(sf->weight); sf->weight = copy("Bold");
 
2706
    }
 
2707
    free(sf->copyright); sf->copyright = NULL;
 
2708
    free(sf->comments); sf->comments = NULL;
 
2709
 
 
2710
    sf->map = EncMapNew(257,257,FindOrMakeEncoding("mac"));
 
2711
 
 
2712
    for ( i=0; i<fond->stylewidthcnt; ++i ) {
 
2713
        if ( fond->stylewidths[i].style == style ) {
 
2714
            short *widths = fond->stylewidths[i].widthtab;
 
2715
            for ( j=fond->first; j<=fond->last; ++j ) {
 
2716
                sc = SFMakeChar(sf,sf->map,j);
 
2717
                sc->width = ((widths[j-fond->first]*1000L+(1<<11))>>12);
 
2718
                sc->widthset = true;
 
2719
            }
 
2720
            sc = SplineCharCreate();
 
2721
            sc->parent = sf;
 
2722
            sc->orig_pos = sf->glyphcnt;
 
2723
            sf->glyphs[sf->glyphcnt++] = sc;
 
2724
            sc->name = copy(".notdef");
 
2725
            sc->width = (widths[fond->last+1-fond->first]*1000L+(1<<11))>>12;
 
2726
            sc->widthset = true;
 
2727
        }
 
2728
    }
 
2729
 
 
2730
    fseek(f,rlistpos,SEEK_SET);
 
2731
    for ( i=0; i<subcnt; ++i ) {
 
2732
        res_id = getushort(f);
 
2733
        rname = (short) getushort(f);
 
2734
        /* flags = */ getc(f);
 
2735
        ch1 = getc(f); ch2 = getc(f);
 
2736
        roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
 
2737
        /* mbz = */ getlong(f);
 
2738
        for ( j=fond->assoc_cnt-1; j>=0; --j )
 
2739
            if ( (find_id!=-1 && res_id==find_id) ||
 
2740
                    ( fond->assoc[j].style==style && fond->assoc[j].id==res_id &&
 
2741
                        fond->assoc[j].size!=0 ) )
 
2742
                LoadNFNT(f,roff,sf,fond->assoc[j].size);
 
2743
    }
 
2744
    fseek(f,start,SEEK_SET);
 
2745
 
 
2746
    sf->onlybitmaps = true;
 
2747
    SFOrderBitmapList(sf);
 
2748
return( sf );
 
2749
}
 
2750
 
 
2751
/* Look for kerning info and merge it into the currently existing font "into" */
 
2752
static SplineFont *FindFamilyStyleKerns(SplineFont *into,EncMap *map,FOND *fondlist,char *filename) {
 
2753
    char *name;
 
2754
    int style;
 
2755
    FOND *fond;
 
2756
    int i,j;
 
2757
    int ch1, ch2, offset;
 
2758
    KernPair *kp;
 
2759
    SplineChar *sc1, *sc2;
 
2760
 
 
2761
    fond = PickFOND(fondlist,filename,&name,&style);
 
2762
    if ( fond==NULL || into==NULL )
 
2763
return( NULL );
 
2764
    for ( i=0; i<fond->stylekerncnt; ++i )
 
2765
        if ( fond->stylekerns[i].style==style )
 
2766
    break;
 
2767
    if ( i==fond->stylekerncnt ) {
 
2768
        LogError(_("No kerning table for %s\n"), name );
 
2769
        free(name);
 
2770
return( NULL );
 
2771
    }
 
2772
    for ( j=0; j<fond->stylekerns[i].kernpairs; ++j ) {
 
2773
        ch1 = fond->stylekerns[i].kerns[j].ch1;
 
2774
        ch2 = fond->stylekerns[i].kerns[j].ch2;
 
2775
        offset = (fond->stylekerns[i].kerns[j].offset*(into->ascent+into->descent)+(1<<11))>>12;
 
2776
        sc1 = SFMakeChar(into,map,ch1);
 
2777
        sc2 = SFMakeChar(into,map,ch2);
 
2778
        for ( kp=sc1->kerns; kp!=NULL; kp=kp->next )
 
2779
            if ( kp->sc==sc2 )
 
2780
        break;
 
2781
        if ( kp==NULL ) {
 
2782
            uint32 script;
 
2783
            kp = chunkalloc(sizeof(KernPair));
 
2784
            kp->sc = sc2;
 
2785
            kp->next = sc1->kerns;
 
2786
            sc1->kerns = kp;
 
2787
            script = SCScriptFromUnicode(sc1);
 
2788
            if ( script==DEFAULT_SCRIPT )
 
2789
                script = SCScriptFromUnicode(sc2);
 
2790
            kp->subtable = SFSubTableFindOrMake(sc1->parent,CHR('k','e','r','n'),
 
2791
                    script, gpos_pair);
 
2792
        }
 
2793
        kp->off = offset;
 
2794
    }
 
2795
return( into );
 
2796
}
 
2797
 
 
2798
/* Look for a bare truetype font in a binhex/macbinary wrapper */
 
2799
static SplineFont *MightBeTrueType(FILE *binary,int32 pos,int32 dlen,int flags,
 
2800
        enum openflags openflags) {
 
2801
    FILE *temp = tmpfile();
 
2802
    char *buffer = galloc(8192);
 
2803
    int len;
 
2804
    SplineFont *sf;
 
2805
 
 
2806
    if ( flags&ttf_onlynames ) {
 
2807
        char **ret;
 
2808
        char *temp = TTFGetFontName(binary,pos,pos);
 
2809
        if ( temp==NULL )
 
2810
return( NULL );
 
2811
        ret = galloc(2*sizeof(char *));
 
2812
        ret[0] = temp;
 
2813
        ret[1] = NULL;
 
2814
return( (SplineFont *) ret );
 
2815
    }
 
2816
 
 
2817
    fseek(binary,pos,SEEK_SET);
 
2818
    while ( dlen>0 ) {
 
2819
        len = dlen > 8192 ? 8192 : dlen;
 
2820
        len = fread(buffer,1,dlen > 8192 ? 8192 : dlen,binary);
 
2821
        if ( len==0 )
 
2822
    break;
 
2823
        fwrite(buffer,1,len,temp);
 
2824
        dlen -= len;
 
2825
    }
 
2826
    rewind(temp);
 
2827
    sf = _SFReadTTF(temp,flags,openflags,NULL,NULL);
 
2828
    fclose(temp);
 
2829
    free(buffer);
 
2830
return( sf );
 
2831
}
 
2832
 
 
2833
static SplineFont *IsResourceFork(FILE *f, long offset,char *filename,int flags,
 
2834
        enum openflags openflags, SplineFont *into,EncMap *map) {
 
2835
    /* If it is a good resource fork then the first 16 bytes are repeated */
 
2836
    /*  at the location specified in bytes 4-7 */
 
2837
    /* We include an offset because if we are looking at a mac binary file */
 
2838
    /*  the resource fork will actually start somewhere in the middle of the */
 
2839
    /*  file, not at the beginning */
 
2840
    unsigned char buffer[16], buffer2[16];
 
2841
    long rdata_pos, map_pos, type_list, name_list, rpos;
 
2842
    int32 rdata_len, map_len;
 
2843
    unsigned long tag;
 
2844
    int i, cnt, subcnt, nfnt_subcnt=0, font_subcnt=0, fond_subcnt=0;
 
2845
    SplineFont *sf;
 
2846
    uint32 nfnt_pos=0, font_pos=0, fond_pos=0;
 
2847
    FOND *fondlist=NULL;
 
2848
 
 
2849
    fseek(f,offset,SEEK_SET);
 
2850
    if ( fread(buffer,1,16,f)!=16 )
 
2851
return( NULL );
 
2852
    rdata_pos = offset + ((buffer[0]<<24)|(buffer[1]<<16)|(buffer[2]<<8)|buffer[3]);
 
2853
    map_pos = offset + ((buffer[4]<<24)|(buffer[5]<<16)|(buffer[6]<<8)|buffer[7]);
 
2854
    rdata_len = ((buffer[8]<<24)|(buffer[9]<<16)|(buffer[10]<<8)|buffer[11]);
 
2855
    map_len = ((buffer[12]<<24)|(buffer[13]<<16)|(buffer[14]<<8)|buffer[15]);
 
2856
    if ( rdata_pos+rdata_len!=map_pos || rdata_len==0 )
 
2857
return( NULL );
 
2858
    fseek(f,map_pos,SEEK_SET);
 
2859
    buffer2[15] = buffer[15]+1; /* make it be different */
 
2860
    if ( fread(buffer2,1,16,f)!=16 )
 
2861
return( NULL );
 
2862
 
 
2863
/* Apple's data fork resources appear to have a bunch of zeroes here instead */
 
2864
/*  of a copy of the first 16 bytes */
 
2865
    for ( i=0; i<16; ++i )
 
2866
        if ( buffer2[i]!=0 )
 
2867
    break;
 
2868
    if ( i!=16 ) {
 
2869
        for ( i=0; i<16; ++i )
 
2870
            if ( buffer[i]!=buffer2[i] )
 
2871
return( NULL );
 
2872
    }
 
2873
    getlong(f);         /* skip the handle to the next resource map */
 
2874
    getushort(f);       /* skip the file resource number */
 
2875
    getushort(f);       /* skip the attributes */
 
2876
    type_list = map_pos + getushort(f);
 
2877
    name_list = map_pos + getushort(f);
 
2878
 
 
2879
    fseek(f,type_list,SEEK_SET);
 
2880
    cnt = getushort(f)+1;
 
2881
    for ( i=0; i<cnt; ++i ) {
 
2882
        tag = getlong(f);
 
2883
 /* printf( "%c%c%c%c\n", tag>>24, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff );*/
 
2884
        subcnt = getushort(f)+1;
 
2885
        rpos = type_list+getushort(f);
 
2886
        sf = NULL;
 
2887
        if ( tag==CHR('P','O','S','T') && !(flags&(ttf_onlystrikes|ttf_onlykerns)))             /* No FOND */
 
2888
            sf = SearchPostscriptResources(f,rpos,subcnt,rdata_pos,name_list,flags);
 
2889
        else if ( tag==CHR('s','f','n','t') && !(flags&ttf_onlykerns))
 
2890
            sf = SearchTtfResources(f,rpos,subcnt,rdata_pos,name_list,filename,flags,openflags);
 
2891
        else if ( tag==CHR('N','F','N','T') ) {
 
2892
            nfnt_pos = rpos;
 
2893
            nfnt_subcnt = subcnt;
 
2894
        } else if ( tag==CHR('F','O','N','T') ) {
 
2895
            font_pos = rpos;
 
2896
            font_subcnt = subcnt;
 
2897
        } else if ( tag==CHR('F','O','N','D') ) {
 
2898
            fond_pos = rpos;
 
2899
            fond_subcnt = subcnt;
 
2900
        }
 
2901
        if ( sf!=NULL )
 
2902
return( sf );
 
2903
    }
 
2904
    if ( flags&ttf_onlynames )                  /* Not interested in bitmap resources here */
 
2905
return( NULL );
 
2906
 
 
2907
    if ( flags&ttf_onlykerns ) {                /* For kerns */
 
2908
        if ( fond_subcnt!=0 )
 
2909
            fondlist = BuildFondList(f,fond_pos,fond_subcnt,rdata_pos,name_list,flags);
 
2910
        into = FindFamilyStyleKerns(into,map,fondlist,filename);
 
2911
        FondListFree(fondlist);
 
2912
return( into );
 
2913
    }
 
2914
    /* Ok. If no outline font, try for a bitmap */
 
2915
    if ( nfnt_subcnt==0 ) {
 
2916
        nfnt_pos = font_pos;
 
2917
        nfnt_subcnt = font_subcnt;
 
2918
    }
 
2919
    if ( nfnt_subcnt!=0 ) {
 
2920
        if ( fond_subcnt!=0 )
 
2921
            fondlist = BuildFondList(f,fond_pos,fond_subcnt,rdata_pos,name_list,flags);
 
2922
        sf = SearchBitmapResources(f,nfnt_pos,nfnt_subcnt,rdata_pos,name_list,
 
2923
                filename,fondlist,flags);
 
2924
        FondListFree(fondlist);
 
2925
        if ( sf!=NULL )
 
2926
return( sf );
 
2927
    }
 
2928
return( (SplineFont *) -1 );    /* It's a valid resource file, but just has no fonts */
 
2929
}
 
2930
 
 
2931
#if __Mac
 
2932
static SplineFont *HasResourceFork(char *filename,int flags,enum openflags openflags,
 
2933
        SplineFont *into,EncMap *map) {
 
2934
    /* If we're on a mac, we can try to see if we've got a real resource fork */
 
2935
    /* (if we do, copy it into a temporary data file and then manipulate that)*/
 
2936
    SplineFont *ret;
 
2937
    FILE *resfork;
 
2938
    char *tempfn=filename, *pt, *lparen, *respath;
 
2939
 
 
2940
    if (( pt=strrchr(filename,'/'))==NULL ) pt = filename;
 
2941
    if ( (lparen = strchr(pt,'('))!=NULL && strchr(lparen,')')!=NULL ) {
 
2942
        tempfn = copy(filename);
 
2943
        tempfn[lparen-filename] = '\0';
 
2944
    }
 
2945
    respath = galloc(strlen(tempfn)+strlen("/rsrc")+1);
 
2946
    strcpy(respath,tempfn);
 
2947
    strcat(respath,"/rsrc");
 
2948
    resfork = fopen(respath,"r");
 
2949
    free(respath);
 
2950
    if ( tempfn!=filename )
 
2951
        free(tempfn);
 
2952
    if ( resfork==NULL )
 
2953
return( NULL );
 
2954
    ret = IsResourceFork(resfork,0,filename,flags,openflags,into,map);
 
2955
    fclose(resfork);
 
2956
return( ret );
 
2957
}
 
2958
#endif
 
2959
 
 
2960
static SplineFont *IsResourceInBinary(FILE *f,char *filename,int flags,
 
2961
        enum openflags openflags, SplineFont *into,EncMap *map) {
 
2962
    unsigned char header[128];
 
2963
    unsigned long offset, dlen, rlen;
 
2964
 
 
2965
    if ( fread(header,1,128,f)!=128 )
 
2966
return( NULL );
 
2967
    if ( header[0]!=0 || header[74]!=0 || header[82]!=0 || header[1]<=0 ||
 
2968
            header[1]>33 || header[63]!=0 || header[2+header[1]]!=0 )
 
2969
return( NULL );
 
2970
    dlen = ((header[0x53]<<24)|(header[0x54]<<16)|(header[0x55]<<8)|header[0x56]);
 
2971
    rlen = ((header[0x57]<<24)|(header[0x58]<<16)|(header[0x59]<<8)|header[0x5a]);
 
2972
        /* 128 bytes for header, then the dlen is padded to a 128 byte boundary */
 
2973
    offset = 128 + ((dlen+127)&~127);
 
2974
/* Look for a bare truetype font in a binhex/macbinary wrapper */
 
2975
    if ( dlen!=0 && rlen<=dlen) {
 
2976
        int pos = ftell(f);
 
2977
        fread(header,1,4,f);
 
2978
        header[5] = '\0';
 
2979
        if ( strcmp((char *) header,"OTTO")==0 || strcmp((char *) header,"true")==0 ||
 
2980
                strcmp((char *) header,"ttcf")==0 ||
 
2981
                (header[0]==0 && header[1]==1 && header[2]==0 && header[3]==0))
 
2982
return( MightBeTrueType(f,pos,dlen,flags,openflags));
 
2983
    }
 
2984
return( IsResourceFork(f,offset,filename,flags,openflags,into,map));
 
2985
}
 
2986
 
 
2987
static int lastch=0, repeat = 0;
 
2988
static void outchr(FILE *binary, int ch) {
 
2989
    int i;
 
2990
 
 
2991
    if ( repeat ) {
 
2992
        if ( ch==0 ) {
 
2993
            /* no repeat, output a literal 0x90 (the repeat flag) */
 
2994
            lastch=0x90;
 
2995
            putc(lastch,binary);
 
2996
        } else {
 
2997
            for ( i=1; i<ch; ++i )
 
2998
                putc(lastch,binary);
 
2999
        }
 
3000
        repeat = 0;
 
3001
    } else if ( ch==0x90 ) {
 
3002
        repeat = 1;
 
3003
    } else {
 
3004
        putc(ch,binary);
 
3005
        lastch = ch;
 
3006
    }
 
3007
}
 
3008
 
 
3009
static SplineFont *IsResourceInHex(FILE *f,char *filename,int flags,enum openflags openflags,
 
3010
        SplineFont *into,EncMap *map) {
 
3011
    /* convert file from 6bit to 8bit */
 
3012
    /* interesting data is enclosed between two colons */
 
3013
    FILE *binary = tmpfile();
 
3014
    char *sixbit = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
 
3015
    int ch, val, cnt, i, dlen, rlen;
 
3016
    unsigned char header[20]; char *pt;
 
3017
    SplineFont *ret;
 
3018
 
 
3019
    if ( binary==NULL ) {
 
3020
        LogError( _("can't create temporary file\n") );
 
3021
return( NULL );
 
3022
    }
 
3023
 
 
3024
    lastch = repeat = 0;
 
3025
    while ( (ch=getc(f))!=':' );        /* There may be comments before file start */
 
3026
    cnt = val = 0;
 
3027
    while ( (ch=getc(f))!=':' ) {
 
3028
        if ( Isspace(ch))
 
3029
    continue;
 
3030
        for ( pt=sixbit; *pt!=ch && *pt!='\0'; ++pt );
 
3031
        if ( *pt=='\0' ) {
 
3032
            fclose(binary);
 
3033
return( NULL );
 
3034
        }
 
3035
        val = (val<<6) | (pt-sixbit);
 
3036
        if ( ++cnt==4 ) {
 
3037
            outchr(binary,(val>>16)&0xff);
 
3038
            outchr(binary,(val>>8)&0xff);
 
3039
            outchr(binary,val&0xff);
 
3040
            val = cnt = 0;
 
3041
        }
 
3042
    }
 
3043
    if ( cnt!=0 ) {
 
3044
        if ( cnt==1 )
 
3045
            outchr(binary,val<<2);
 
3046
        else if ( cnt==2 ) {
 
3047
            val<<=4;
 
3048
            outchr(binary,(val>>8)&0xff);
 
3049
            outchr(binary,val&0xff);
 
3050
        } else if ( cnt==3 ) {
 
3051
            val<<=6;
 
3052
            outchr(binary,(val>>16)&0xff);
 
3053
            outchr(binary,(val>>8)&0xff);
 
3054
            outchr(binary,val&0xff);
 
3055
        }
 
3056
    }
 
3057
 
 
3058
    rewind(binary);
 
3059
    ch = getc(binary);  /* Name length */
 
3060
    /* skip name */
 
3061
    for ( i=0; i<ch; ++i )
 
3062
        getc(binary);
 
3063
    if ( getc(binary)!='\0' ) {
 
3064
        fclose(binary);
 
3065
return( NULL );
 
3066
    }
 
3067
    fread(header,1,20,binary);
 
3068
    dlen = (header[10]<<24)|(header[11]<<16)|(header[12]<<8)|header[13];
 
3069
    rlen = (header[14]<<24)|(header[15]<<16)|(header[16]<<8)|header[17];
 
3070
/* Look for a bare truetype font in a binhex/macbinary wrapper */
 
3071
    if ( dlen!=0 && rlen<dlen ) {
 
3072
        int pos = ftell(binary);
 
3073
        fread(header,1,4,binary);
 
3074
        header[5] = '\0';
 
3075
        if ( strcmp((char *) header,"OTTO")==0 || strcmp((char *) header,"true")==0 ||
 
3076
                strcmp((char *) header,"ttcf")==0 ||
 
3077
                (header[0]==0 && header[1]==1 && header[2]==0 && header[3]==0)) {
 
3078
            ret = MightBeTrueType(binary,pos,dlen,flags,openflags);
 
3079
            fclose(binary);
 
3080
return( ret );
 
3081
        }
 
3082
    }
 
3083
    if ( rlen==0 ) {
 
3084
        fclose(binary);
 
3085
return( NULL );
 
3086
    }
 
3087
 
 
3088
    ret = IsResourceFork(binary,ftell(binary)+dlen+2,filename,flags,openflags,into,map);
 
3089
 
 
3090
    fclose(binary);
 
3091
return( ret );
 
3092
}
 
3093
 
 
3094
static SplineFont *IsResourceInFile(char *filename,int flags,enum openflags openflags,
 
3095
        SplineFont *into, EncMap *map) {
 
3096
    FILE *f;
 
3097
    char *spt, *pt;
 
3098
    SplineFont *sf;
 
3099
    char *temp=filename, *lparen;
 
3100
 
 
3101
    if (( pt=strrchr(filename,'/'))==NULL ) pt = filename;
 
3102
    if ( (lparen = strchr(pt,'('))!=NULL && strchr(lparen,')')!=NULL ) {
 
3103
        temp = copy(filename);
 
3104
        temp[lparen-filename] = '\0';
 
3105
    }
 
3106
    f = fopen(temp,"rb");
 
3107
    if ( temp!=filename ) free(temp);
 
3108
    if ( f==NULL )
 
3109
return( NULL );
 
3110
    spt = strrchr(filename,'/');
 
3111
    if ( spt==NULL ) spt = filename;
 
3112
    pt = strrchr(spt,'.');
 
3113
    if ( pt!=NULL && (pt[1]=='b' || pt[1]=='B') && (pt[2]=='i' || pt[2]=='I') &&
 
3114
            (pt[3]=='n' || pt[3]=='N') && (pt[4]=='\0' || pt[4]=='(') ) {
 
3115
        if ( (sf = IsResourceInBinary(f,filename,flags,openflags,into,map))) {
 
3116
            fclose(f);
 
3117
return( sf );
 
3118
        }
 
3119
    } else if ( pt!=NULL && (pt[1]=='h' || pt[1]=='H') && (pt[2]=='q' || pt[2]=='Q') &&
 
3120
            (pt[3]=='x' || pt[3]=='X') && (pt[4]=='\0' || pt[4]=='(')) {
 
3121
        if ( (sf = IsResourceInHex(f,filename,flags,openflags,into,map))) {
 
3122
            fclose(f);
 
3123
return( sf );
 
3124
        }
 
3125
    }
 
3126
 
 
3127
    sf = IsResourceFork(f,0,filename,flags,openflags,into,map);
 
3128
    fclose(f);
 
3129
#if __Mac
 
3130
    if ( sf==NULL )
 
3131
        sf = HasResourceFork(filename,flags,openflags,into,map);
 
3132
#endif
 
3133
return( sf );
 
3134
}
 
3135
 
 
3136
static SplineFont *FindResourceFile(char *filename,int flags,enum openflags openflags,
 
3137
        SplineFont *into,EncMap *map) {
 
3138
    char *spt, *pt, *dpt;
 
3139
    char buffer[1400];
 
3140
    SplineFont *sf;
 
3141
 
 
3142
    if ( (sf = IsResourceInFile(filename,flags,openflags,into,map)))
 
3143
return( sf );
 
3144
 
 
3145
    /* Well, look in the resource fork directory (if it exists), the resource */
 
3146
    /*  fork is placed there in a seperate file on (some) non-Mac disks */
 
3147
    strcpy(buffer,filename);
 
3148
    spt = strrchr(buffer,'/');
 
3149
    if ( spt==NULL ) { spt = buffer; pt = filename; }
 
3150
    else { ++spt; pt = filename + (spt-buffer); }
 
3151
    strcpy(spt,"resource.frk/");
 
3152
    strcat(spt,pt);
 
3153
    if ( (sf=IsResourceInFile(buffer,flags,openflags,into,map)))
 
3154
return( sf );
 
3155
 
 
3156
    /* however the resource fork does not appear to do long names properly */
 
3157
    /*  names are always lower case 8.3, do some simple things to check */
 
3158
    spt = strrchr(buffer,'/')+1;
 
3159
    for ( pt=spt; *pt; ++pt )
 
3160
        if ( Isupper( *pt ))
 
3161
            *pt = Tolower( *pt );
 
3162
    dpt = strchr(spt,'.');
 
3163
    if ( dpt==NULL ) dpt = spt+strlen(spt);
 
3164
    if ( dpt-spt>8 || strlen(dpt)>4 ) {
 
3165
        char exten[8];
 
3166
        strncpy(exten,dpt,7);
 
3167
        exten[4] = '\0';        /* it includes the dot */
 
3168
        if ( dpt-spt>6 )
 
3169
            dpt = spt+6;
 
3170
        *dpt++ = '~';
 
3171
        *dpt++ = '1';
 
3172
        strcpy(dpt,exten);
 
3173
    }
 
3174
return( IsResourceInFile(buffer,flags,openflags,into,map));
 
3175
}
 
3176
 
 
3177
SplineFont *SFReadMacBinary(char *filename,int flags,enum openflags openflags) {
 
3178
    SplineFont *sf = FindResourceFile(filename,flags,openflags,NULL,NULL);
 
3179
 
 
3180
    if ( sf==NULL )
 
3181
        LogError( _("Couldn't find a font file named %s\n"), filename );
 
3182
    else if ( sf==(SplineFont *) (-1) ) {
 
3183
        LogError( _("%s is a mac resource file but contains no postscript or truetype fonts\n"), filename );
 
3184
        sf = NULL;
 
3185
    }
 
3186
return( sf );
 
3187
}
 
3188
 
 
3189
#ifdef LUA_FF_LIB
 
3190
SplineFont *SFReadMacBinaryInfo(char *filename,int flags,enum openflags openflags) {
 
3191
    SplineFont *sf = FindResourceFile(filename,flags,openflags,NULL,NULL);
 
3192
 
 
3193
    if ( sf==NULL )
 
3194
        LogError( _("Couldn't find a font file named %s\n"), filename );
 
3195
    else if ( sf==(SplineFont *) (-1) ) {
 
3196
        LogError( _("%s is a mac resource file but contains no postscript or truetype fonts\n"), filename );
 
3197
        sf = NULL;
 
3198
    }
 
3199
return( sf );
 
3200
}
 
3201
#endif
 
3202
 
 
3203
int LoadKerningDataFromMacFOND(SplineFont *sf, char *filename,EncMap *map) {
 
3204
    if ( FindResourceFile(filename,ttf_onlykerns,0,sf,map)==NULL )
 
3205
return ( false );
 
3206
 
 
3207
return( true );
 
3208
}
 
3209
 
 
3210
char **NamesReadMacBinary(char *filename) {
 
3211
return( (char **) FindResourceFile(filename,ttf_onlynames,0,NULL,NULL));
 
3212
}