diff options
author | George Williams <gww@silcom.com> | 2001-11-07 06:56:00 +0000 |
---|---|---|
committer | George Williams <gww@silcom.com> | 2001-11-07 06:56:00 +0000 |
commit | 0bd8f845ad35973e10656118f7a309164695b9c8 (patch) | |
tree | ea7995702091bbd5ae4be0afcee9013983881c06 |
Initial revision
-rw-r--r-- | fondu.c | 884 | ||||
-rw-r--r-- | macfonts.h | 73 | ||||
-rw-r--r-- | readnfnt.c | 466 |
3 files changed, 1423 insertions, 0 deletions
@@ -0,0 +1,884 @@ +/* Copyright (C) 2001 by George Williams */ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + + * The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <unistd.h> +#include <time.h> + +#include "macfonts.h" + +int tolatin1 = false; +static int force = false, inquire = false, doafm = false; + +int getushort(FILE *f) { + int ch1 = getc(f); + int ch2 = getc(f); + if ( ch2==EOF ) +return( EOF ); +return( (ch1<<8)|ch2 ); +} + +long getlong(FILE *f) { + int ch1 = getc(f); + int ch2 = getc(f); + int ch3 = getc(f); + int ch4 = getc(f); + if ( ch4==EOF ) +return( EOF ); +return( (ch1<<24)|(ch2<<16)|(ch3<<8)|ch4 ); +} + +int cleanfilename(char *filename) { + char *pt, *npt; + int ch, exists, ch2; + + for ( ch = *(pt=npt=filename); ch!='\0'; ch = *++pt ) { + if ( ch>'!' && ch!='*' && ch!='?' && ch!='/' && ch!='\\' && ch!='[' && ch<0x7f ) + *npt++ = ch; + } + *npt = '\0'; + if ( force && !inquire ) +return( true ); + + exists = access(filename,F_OK)==0; + + forever { + if ( exists ) + fprintf( stderr, "%s exists, do you want to overwrite it? (n) ", filename ); + else if ( inquire ) + fprintf( stderr, "Write %s? (y) ", filename ); + else +return( true ); + ch = getchar(); + if ( ch=='y' || ch=='Y' || ch=='n' || ch=='N' || ch==EOF || ch=='\n' ) { + if ( ch=='\n' || ch==EOF ) + ch = exists ? 'n' : 'y'; + else + while ( (ch2=getchar())!='\n' && ch2!=EOF ); +return( ch=='y' || ch=='Y' ); + } else if ( ch=='=' ) { + for ( pt=filename; (ch=getchar())!=EOF && ch!='\n'; ) + *pt++ = ch; +return( true ); + } else { + fprintf( stderr, "Please answer with 'y'(es), 'n'(o) or '=new-filename'.\n" ); + } + } +} + +static void mytmpname(char *temp) { + static int upos; + /* build up a temporary filename that doesn't match anything else */ + + forever { + sprintf( temp, "fondu%04X-%d", getpid(), ++upos ); + if ( access(temp,F_OK)==-1 ) +return; + } +} + +static FILE *CreateAfmFile(FILE *f,FOND *fond,long styleoff,int style, + char *fontname,char *familyname) { + char namebuf[300], **strings; + int i,cnt, len,j, index; + FILE *afm; + + if ( styleoff==0 || style>=48 ) { + if ( fond->fondname!=NULL ) + strcpy(familyname,fond->fondname); + else + strcpy(familyname,"Nameless"); + strcpy(fontname,familyname); + for ( i=0; styles[i]!=NULL ; ++i ) + if ( style&(1<<i)) + strcat(fontname,styles[i]); + } else { + fseek(f,styleoff+2+4+4,SEEK_SET); + index = 0; + for ( i=0; i<48; ++i ) + if ( i==style ) + index = getc(f); + else + getc(f); + cnt = getushort(f); + /* well the docs say that there's a STR255 here, but actually there's */ + /* a more compressed pascal string */ + strings = calloc(cnt,sizeof(char *)); + /* Apple uses a 1based array index, I use a 0based. */ + for ( i=0; i<cnt; ++i ) { + len = getc(f); + strings[i] = malloc(len+1); + for ( j=0; j<len; ++j ) + strings[i][j] = getc(f); + strings[i][j] = '\0'; + } + strcpy(familyname,strings[0]); + strcpy(fontname,familyname); + if ( index!=0 ) { + char *ctl = strings[index-1]; + while ( *ctl ) { + strcat(fontname,strings[*ctl-1]); + ++ctl; + } + } + for ( i=1; i<cnt; ++i ) + free(strings[i]); + free(strings); + } + strcpy(namebuf,fontname); + strcat(namebuf,".afm"); + if ( !cleanfilename(namebuf)) +return( NULL ); + afm = fopen( namebuf,"w" ); + if ( afm==NULL ) + fprintf( stderr, "Can't open %s\n", namebuf ); +return( afm ); +} + +static void MakeAfmFiles(FOND *fond,FILE *f, int styleoff, int isfixed) { + long start = ftell(f); + int i,j,k; + FILE *afm; + time_t now; + char fontname[256], familyname[256]; + char buffer[32]; + + for ( i=0; i<fond->stylekerncnt; ++i ) { + for ( j=fond->stylewidthcnt-1; j>=0; --j ) + if ( fond->stylekerns[i].style==fond->stylewidths[j].style ) + break; + afm = CreateAfmFile(f,fond,styleoff,fond->stylekerns[i].style,fontname,familyname); + if ( afm==NULL ) + continue; + fprintf( afm, "StartFontMetrics 2.0\n" ); + fprintf( afm, "Comment Caveat: This does not contain all the information generally found in an AFM file\n" ); + fprintf( afm, "Comment Generated by Fondu from a mac FOND resource\n" ); + time(&now); + fprintf( afm, "Comment Creation Data: %s", ctime(&now) ); + fprintf( afm, "FontName %s\n", fontname ); + fprintf( afm, "FamilyName %s\n", familyname ); + fprintf( afm, "Weight %s\n", ( fond->stylekerns[i].style&sf_bold )?"Bold":"Medium" ); + if ( !( fond->stylekerns[i].style&sf_italic )) + fprintf( afm, "ItalicAngle 0\n" ); + fprintf( afm, "IsFixedPitch %s\n", isfixed?"true":"false"); + fprintf( afm, "EncodingScheme MacRoman\n" ); /* I assume */ + /* I could check to see if there's an offset table, and check it to */ + /* see if there's a bounding box table and then read that in and */ + /* convert it and output a proper FontBBox. But it might not be there*/ + /* and it's a pain, and pfaedit never looks at it anyway */ + if ( j!=-1 ) { + fprintf( afm, "StartCharMetrics %d\n", fond->last-fond->first+1 ); + for ( k=fond->first; k<=fond->last; ++k ) { + const char *name; + if ( k<=256 && macnames[k]!=NULL ) + name = macnames[k]; + else { + sprintf( buffer, "char%04x", k ); + name = buffer; + } + fprintf( afm, "C %d ; WX %d ; N %s ;\n", /* No bounding box info */ + k>=256?-1:k, + (fond->stylewidths[j].widthtab[k-fond->first]*1000 + (1<<11))>>12, + name ); + } + fprintf( afm, "EndCharMetrics\n" ); + } else + fprintf( afm, "StartCharMetrics 0\nEndCharMetrics\n" ); + fprintf( afm, "StartKernData\nStartKernPairs %d\n", + fond->stylekerns[i].kernpairs ); + for ( k=0; k<fond->stylekerns[i].kernpairs; ++k ) { + const char *name1, *name2; + struct kerns *kp = &fond->stylekerns[i].kerns[k]; + if ( kp->ch1<=256 ) + name1 = macnames[kp->ch1]; + else { + sprintf( buffer, "char%04x", kp->ch1 ); + name1 = buffer; + } + if ( kp->ch2<=256 ) + name2 = macnames[kp->ch2]; + else { + sprintf( fontname, "char%04x", kp->ch2 ); + name2 = fontname; + } + fprintf( afm, "KPX %s %s %d\n", name1, name2, (kp->offset*1000+(1<<11))>>12 ); + } + fprintf( afm, "EndKernPairs\nEndKernData\nEndFontMetrics\n" ); + fclose( afm ); + } + fseek(f,start,SEEK_SET); +} + +/* There's probably only one fond in the file, but there could be more so be */ +/* prepared... */ +/* I want the fond: */ +/* to get the fractional widths for the SWIDTH entry on bdf */ +/* to get the font name */ +/* to get the font association tables */ +/* to get the style flags */ +/* http://developer.apple.com/techpubs/mac/Text/Text-269.html */ +static FOND *BuildFondList(FILE *f,long rlistpos,int subcnt,long rdata_pos, + long name_list) { + long here, start = ftell(f); + long offset; + int rname = -1; + char name[300]; + int ch1, ch2; + int i, j, k, cnt, isfixed; + FOND *head=NULL, *cur; + long widoff, kernoff, styleoff; + + fseek(f,rlistpos,SEEK_SET); + for ( i=0; i<subcnt; ++i ) { + /* resource id = */ getushort(f); + rname = (short) getushort(f); + /* flags = */ getc(f); + ch1 = getc(f); ch2 = getc(f); + offset = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f)); + /* mbz = */ getlong(f); + here = ftell(f); + + cur = calloc(1,sizeof(FOND)); + cur->next = head; + head = cur; + + if ( rname!=-1 ) { + fseek(f,name_list+rname,SEEK_SET); + ch1 = getc(f); + fread(name,1,ch1,f); + name[ch1] = '\0'; + cur->fondname = strdup(name); + } + + offset += 4; + fseek(f,offset,SEEK_SET); + isfixed = getushort(f)&0x8000?1:0; + /* family id = */ getushort(f); + cur->first = getushort(f); + cur->last = getushort(f); +/* on a 1 point font... */ + /* ascent = */ getushort(f); + /* descent = */ (short) getushort(f); + /* leading = */ getushort(f); + /* widmax = */ getushort(f); + if ( (widoff = getlong(f))!=0 ) widoff += offset; + if ( (kernoff = getlong(f))!=0 ) kernoff += offset; + if ( (styleoff = getlong(f))!=0 ) styleoff += offset; + for ( j=0; j<9; ++j ) + getushort(f); + /* internal & undefined, for international scripts = */ getlong(f); + /* version = */ getushort(f); + cur->assoc_cnt = getushort(f)+1; + cur->assoc = calloc(cur->assoc_cnt,sizeof(struct assoc)); + for ( j=0; j<cur->assoc_cnt; ++j ) { + cur->assoc[j].size = getushort(f); + cur->assoc[j].style = getushort(f); + cur->assoc[j].id = getushort(f); + } + if ( widoff!=0 ) { + fseek(f,widoff,SEEK_SET); + cnt = getushort(f)+1; + cur->stylewidthcnt = cnt; + cur->stylewidths = calloc(cnt,sizeof(struct stylewidths)); + for ( j=0; j<cnt; ++j ) { + cur->stylewidths[j].style = getushort(f); + cur->stylewidths[j].widthtab = malloc((cur->last-cur->first+1)*sizeof(short)); + for ( k=cur->first; k<=cur->last; ++k ) + cur->stylewidths[j].widthtab[k] = getushort(f); + } + } + if ( kernoff!=0 && doafm ) { + /* The only point of generating an afm file is to make the kerning*/ + /* info available to pfaedit. So we only do this if there is kern*/ + fseek(f,kernoff,SEEK_SET); + cnt = getushort(f)+1; + cur->stylekerncnt = cnt; + cur->stylekerns = calloc(cnt,sizeof(struct stylekerns)); + for ( j=0; j<cnt; ++j ) { + cur->stylekerns[j].style = getushort(f); + cur->stylekerns[j].kernpairs = getushort(f); + cur->stylekerns[j].kerns = malloc(cur->stylekerns[j].kernpairs*sizeof(struct kerns)); + for ( k=0; k<=cur->stylekerns[j].kernpairs; ++k ) { + cur->stylekerns[j].kerns[k].ch1 = getc(f); + cur->stylekerns[j].kerns[k].ch2 = getc(f); + cur->stylekerns[j].kerns[k].offset = getushort(f); + } + } + MakeAfmFiles(cur,f,styleoff,isfixed); + } + fseek(f,here,SEEK_SET); + } + fseek(f,start,SEEK_SET); +return( head ); +} + +static void SearchPostscriptResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, + long name_list, FOND *fonds) { + long here = ftell(f); + long *offsets, lenpos; + int rname = -1, tmp; + char name[300], newname[300]; + int ch1, ch2; + static int ucnt; + int len, type, i, rlen; + /* I don't pretend to understand the rational behind the format of a */ + /* postscript font. It appears to be split up into chunks where the */ + /* maximum chunk size is 0x800 */ + char *buffer=NULL; + int max = 0; + FILE *pfb; + + fseek(f,rlistpos,SEEK_SET); + offsets = calloc(subcnt,sizeof(long)); + for ( i=0; i<subcnt; ++i ) { + /* resource id = */ getushort(f); + tmp = (short) getushort(f); + if ( rname==-1 ) rname = tmp; + /* flags = */ getc(f); + ch1 = getc(f); ch2 = getc(f); + offsets[i] = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f)); + /* mbz = */ getlong(f); + } + mytmpname(name); + /* use the temp name until we've read the postscript font to see what it's name really is */ + if ( rname!=-1 ) { + fseek(f,name_list+rname,SEEK_SET); + ch1 = getc(f); + fread(newname,1,ch1,f); + strcpy(newname+ch1,".pfb"); + } else + sprintf(newname,"Untitled-%d.pfb", ++ucnt ); + + pfb = fopen( name,"w" ); + if ( pfb==NULL ) { + fprintf( stderr, "Can't open temporary file for postscript output\n", name ); + fseek(f,here,SEEK_SET ); + free(offsets); +return; + } + + putc(0x80,pfb); + putc(1,pfb); + lenpos = ftell(pfb); + putc(0,pfb); + putc(0,pfb); + putc(0,pfb); + putc(0,pfb); + len = 0; type = 1; + for ( i=0; i<subcnt; ++i ) { + fseek(f,offsets[i],SEEK_SET); + rlen = getlong(f); + ch1 = getc(f); ch2 = getc(f); + rlen -= 2; /* those two bytes don't count as real data */ + if ( ch1==type ) + len += rlen; + else { + long hold = ftell(pfb); + fseek(pfb,lenpos,SEEK_SET); + putc(len>>24,pfb); + putc((len>>16)&0xff,pfb); + putc((len>>8)&0xff,pfb); + putc(len&0xff,pfb); + fseek(pfb,hold,SEEK_SET); + putc(0x80,pfb); + putc(ch1,pfb); + lenpos = ftell(pfb); + putc(0,pfb); + putc(0,pfb); + putc(0,pfb); + putc(0,pfb); + type = ch1; + len = rlen; + } + if ( rlen>max ) { + free(buffer); + max = rlen; + if ( max<0x800 ) max = 0x800; + buffer=malloc(max); + } + fread(buffer,1,rlen,f); + if ( type==1 ) { + int j; + char *pt; + for ( j=0; j<rlen; ++j ) if ( buffer[j]=='\r' ) buffer[j] = '\n'; + if ( i==0 && rname==-1 && (pt=strstr(buffer,"/FontName"))!=NULL ) { + pt += strlen("/FontName"); + while ( isspace(*pt) ) ++pt; + if ( *pt=='/' ) { + char *end = strchr(pt,' '); + ch1 = *end; *end='\0'; + sprintf(newname,"%s.pfb", pt+1 ); + *end = ch1; + } + } + } + fwrite(buffer,1,rlen,pfb); + } + free(buffer); + free(offsets); + putc(0x80,pfb); + putc(3,pfb); + fseek(pfb,lenpos,SEEK_SET); + putc(len>>24,pfb); + putc((len>>16)&0xff,pfb); + putc((len>>8)&0xff,pfb); + putc(len&0xff,pfb); + fclose(pfb); + if ( cleanfilename(newname)) { + if ( rename(name,newname)==-1 ) { + fprintf( stderr, "Could not create %s\n", newname); + unlink(name); + } + } else + unlink(name); + fseek(f,here,SEEK_SET); +} + +static int ttfnamefixup(FILE *ttf,char *buffer) { + int version, isotf=false; + int i,num, nameoffset, stringoffset; + int fullval, famval, fullstr, famstr, fulllen, famlen, val, tag; + int plat, spec, lang, name, len, off, ch; + char *pt; + + rewind(ttf); + if ( (version=getlong(ttf))==CHR('O','T','T','O')) + isotf = true; + else if ( version!=0x10000 ) +return(false); /* Not going to mess with ttc collections, or whatever else this might be */ + + num = getushort(ttf); + /* srange = */ getushort(ttf); + /* esel = */ getushort(ttf); + /* rshift = */ getushort(ttf); + for ( i=0; i<num; ++i ) { + tag = getlong(ttf); + /* checksum = */ getlong(ttf); + nameoffset = getlong(ttf); + /* length =*/ getlong(ttf); + if ( tag==CHR('n','a','m','e')) + break; + } + if ( i==num ) +return(false); + + fseek(ttf,nameoffset,SEEK_SET); + /* format = */ getushort(ttf); + num = getushort(ttf); + stringoffset = nameoffset+getushort(ttf); + fullval = famval = 0; + for ( i=0; i<num; ++i ) { + plat = getushort(ttf); + spec = getushort(ttf); + lang = getushort(ttf); + name = getushort(ttf); + len = getushort(ttf); + off = getushort(ttf); + val = 0; + if ( plat==0 && /* any unicode semantics will do && */ lang==0 ) + val = 1; + else if ( plat==3 && spec==1 && lang==0x409 ) + val = 2; + if ( name==4 && val>fullval ) { + fullval = val; + fullstr = off; + fulllen = len; + if ( val==2 ) + break; + } else if ( name==1 && val>famval ) { + famval = val; + famstr = off; + famlen = len; + } + } + if ( fullval==0 ) { + if ( famval==0 ) +return( false ); + fullstr = famstr; + fulllen = famlen; + } + + fseek(ttf,stringoffset+fullstr,SEEK_SET); + pt = buffer; + for ( i=0; i<len/2; ++i ) { + /* Ignore high unicode byte */ getc(ttf)/*<<8*/; + ch = getc(ttf); + /* avoid characters that are hard to manipulate on the command line */ + if ( ch>'!' && ch!='*' && ch!='?' && ch!='/' && ch!='\\' && ch<0x7f ) + *pt++ = ch; + } + strcpy(pt,isotf?".otf":".ttf"); +return( true ); +} + +static void ttfnameset(FILE *ttf,char *curname,char *patheticattempt) { + char buffer[1024]; + + if ( !ttfnamefixup(ttf,buffer)) + strcpy(buffer,patheticattempt); + if ( !cleanfilename(buffer)) + unlink(curname); + else if ( rename(curname, buffer)==-1 ) { + fprintf( stderr, "Could not create %s\n", buffer ); + unlink(curname); + } +} + +static void SearchTtfResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, + long name_list, FOND *fonds) { + long here, start = ftell(f); + long roff; + int rname = -1; + char name[300], newname[300]; + int ch1, ch2; + static int ucnt; + int len, i, rlen, ilen; + /* I think (hope) the sfnt resource is just a copy of the ttf file */ + char *buffer=NULL; + int max = 0; + FILE *ttf; + + fseek(f,rlistpos,SEEK_SET); + for ( i=0; i<subcnt; ++i ) { + rname = (short) getushort(f); + /* flags = */ getc(f); + ch1 = getc(f); ch2 = getc(f); + roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f)); + /* mbz = */ getlong(f); + here = ftell(f); + if ( rname!=-1 ) { + fseek(f,name_list+rname,SEEK_SET); + ch1 = getc(f); + fread(newname,1,ch1,f); + strcpy(newname+ch1,".ttf"); + } else + sprintf(newname,"Untitled-%d.ttf", ++ucnt ); + + mytmpname(name); + ttf = fopen( name,"w+" ); + if ( ttf==NULL ) { + fprintf( stderr, "Can't open temporary file for truetype output.\n" ); + fseek(f,here,SEEK_SET ); + continue; + } + + fseek(f,roff,SEEK_SET); + ilen = rlen = getlong(f); + if ( rlen>16*1024 ) + ilen = 16*1024; + if ( ilen>max ) { + free(buffer); + max = ilen; + if ( max<0x800 ) max = 0x800; + buffer=malloc(max); + } + for ( len=0; len<rlen; ) { + int temp = ilen; + if ( rlen-len<ilen ) temp = rlen-len; + temp = fread(buffer,1,temp,f); + if ( temp==EOF ) + break; + fwrite(buffer,1,temp,ttf); + len += temp; + } + ttfnameset(ttf,name,newname); + fclose(ttf); + } + fseek(f,start,SEEK_SET); +} + +static int IsResourceFork(FILE *f, long offset) { + /* If it is a good resource fork then the first 16 bytes are repeated */ + /* at the location specified in bytes 4-7 */ + /* We include an offset because if we are looking at a mac binary file */ + /* the resource fork will actually start somewhere in the middle of the */ + /* file, not at the beginning */ + unsigned char buffer[16], buffer2[16]; + long rdata_pos, map_pos, type_list, name_list, rpos; + unsigned long tag; + int i, cnt, subcnt; + FOND *fondlist=NULL; + + fseek(f,offset,SEEK_SET); + if ( fread(buffer,1,16,f)!=16 ) +return( false ); + rdata_pos = offset + ((buffer[0]<<24)|(buffer[1]<<16)|(buffer[2]<<8)|buffer[3]); + map_pos = offset + ((buffer[4]<<24)|(buffer[5]<<16)|(buffer[6]<<8)|buffer[7]); + fseek(f,map_pos,SEEK_SET); + buffer2[15] = buffer[15]+1; /* make it be different */ + if ( fread(buffer2,1,16,f)!=16 ) +return( false ); + for ( i=0; i<16; ++i ) + if ( buffer[i]!=buffer2[i] ) +return( false ); + getlong(f); /* skip the handle to the next resource map */ + getushort(f); /* skip the file resource number */ + getushort(f); /* skip the attributes */ + type_list = map_pos + getushort(f); + name_list = map_pos + getushort(f); + + fseek(f,type_list,SEEK_SET); + cnt = getushort(f)+1; + for ( i=0; i<cnt; ++i ) { + tag = getlong(f); + subcnt = getushort(f)+1; + rpos = type_list+getushort(f); + if ( tag==CHR('F','O','N','D')) + fondlist = BuildFondList(f,rpos,subcnt,rdata_pos,name_list); + } + + fseek(f,type_list,SEEK_SET); + cnt = getushort(f)+1; + for ( i=0; i<cnt; ++i ) { + tag = getlong(f); + /* printf( "%c%c%c%c\n", tag>>24, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff );*/ + subcnt = getushort(f)+1; + rpos = type_list+getushort(f); + if ( tag==CHR('P','O','S','T')) /* No FOND */ + SearchPostscriptResources(f,rpos,subcnt,rdata_pos,name_list,fondlist); + else if ( tag==CHR('F','O','N','T')) + SearchNFNTResources(f,rpos,subcnt,rdata_pos,name_list,fondlist); + else if ( tag==CHR('N','F','N','T')) + SearchNFNTResources(f,rpos,subcnt,rdata_pos,name_list,fondlist); + else if ( tag==CHR('s','f','n','t')) + SearchTtfResources(f,rpos,subcnt,rdata_pos,name_list,fondlist); + else if ( tag==CHR('F','O','N','D')) + /* already parsed */; + else + /* Ignored */; + } +return( true ); +} + +static int IsResourceInBinary(FILE *f) { + unsigned char header[128]; + unsigned long offset; + + if ( fread(header,1,128,f)!=128 ) +return( false ); + if ( header[0]!=0 || header[74]!=0 || header[82]!=0 || header[1]<=0 || + header[1]>33 || header[63]!=0 || header[2+header[1]]!=0 ) +return( false ); + offset = (header[0x53]<<24)|(header[0x54]<<16)|(header[0x55]<<8)|header[0x56] ; +return( IsResourceFork(f,offset)); +} + +static int lastch=0, repeat = 0; +static void outchr(FILE *binary, int ch) { + int i; + + if ( repeat ) { + if ( ch==0 ) { + /* no repeat, output a literal 0x90 (the repeat flag) */ + lastch=0x90; + putc(lastch,binary); + } else { + for ( i=1; i<ch; ++i ) + putc(lastch,binary); + } + repeat = 0; + } else if ( ch==0x90 ) { + repeat = 1; + } else { + putc(ch,binary); + lastch = ch; + } +} + +static int IsResourceInHex(FILE *f) { + /* convert file from 6bit to 8bit */ + /* interesting data is enclosed between two colons */ + FILE *binary = tmpfile(); + char *sixbit = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; + int ch, val, cnt, i, dlen, rlen, ret; + char header[20], *pt; + + if ( binary==NULL ) { + fprintf( stderr, "can't create temporary file\n" ); +return( false ); + } + + lastch = repeat = 0; + while ( (ch=getc(f))!=':' ); /* There may be comments before file start */ + cnt = val = 0; + while ( (ch=getc(f))!=':' ) { + if ( isspace(ch)) + continue; + for ( pt=sixbit; *pt!=ch && *pt!='\0'; ++pt ); + if ( *pt=='\0' ) { + fclose(binary); +return( false ); + } + val = (val<<6) | (pt-sixbit); + if ( ++cnt==4 ) { + outchr(binary,(val>>16)&0xff); + outchr(binary,(val>>8)&0xff); + outchr(binary,val&0xff); + val = cnt = 0; + } + } + if ( cnt!=0 ) { + if ( cnt==1 ) + outchr(binary,val<<2); + else if ( cnt==2 ) { + val<<=4; + outchr(binary,(val>>8)&0xff); + outchr(binary,val&0xff); + } else if ( cnt==3 ) { + val<<=6; + outchr(binary,(val>>16)&0xff); + outchr(binary,(val>>8)&0xff); + outchr(binary,val&0xff); + } + } + + rewind(binary); + ch = getc(binary); /* Name length */ + /* skip name */ + for ( i=0; i<ch; ++i ) + getc(binary); + if ( getc(binary)!='\0' ) { + fclose(binary); +return( false ); + } + fread(header,1,20,binary); + dlen = (header[10]<<24)|(header[11]<<16)|(header[12]<<8)|header[13]; + rlen = (header[14]<<24)|(header[15]<<16)|(header[16]<<8)|header[17]; + if ( rlen==0 ) { + fclose(binary); +return( false ); + } + + ret = IsResourceFork(binary,ftell(binary)+dlen+2); + fclose(binary); +return( ret ); +} + +static int IsResourceInFile(char *filename) { + FILE *f; + char *spt, *pt; + int ret; + + f = fopen(filename,"r"); + if ( f==NULL ) +return( false ); + spt = strrchr(filename,'/'); + if ( spt==NULL ) spt = filename; + pt = strrchr(spt,'.'); + if ( pt!=NULL && (pt[1]=='b' || pt[1]=='B') && (pt[2]=='i' || pt[2]=='I') && + (pt[3]=='n' || pt[3]=='N') && pt[4]=='\0' ) { + if ( IsResourceInBinary(f)) { + fclose(f); +return( true ); + } + } else if ( pt!=NULL && (pt[1]=='h' || pt[1]=='H') && (pt[2]=='q' || pt[2]=='Q') && + (pt[3]=='x' || pt[3]=='X') && pt[4]=='\0' ) { + if ( IsResourceInHex(f)) { + fclose(f); +return( true ); + } + } + + ret = IsResourceFork(f,0); + fclose(f); +return( ret ); +} + +static int FindResourceFile(char *filename) { + char *spt, *pt, *dpt; + char buffer[1400]; + + if ( IsResourceInFile(filename)) +return( true ); + + /* Well, look in the resource fork directory (if it exists), the resource */ + /* fork is placed there in a seperate file on non-Mac disks */ + strcpy(buffer,filename); + spt = strrchr(buffer,'/'); + if ( spt==NULL ) { spt = buffer; pt = filename; } + else { ++spt; pt = filename + (spt-buffer); } + strcpy(spt,"resource.frk/"); + strcat(spt,pt); + if ( IsResourceInFile(buffer)) +return( true ); + + /* however the resource fork does not appear to long names properly */ + /* names are always lower case 8.3, do some simple things to check */ + spt = strrchr(buffer,'/')+1; + for ( pt=spt; *pt; ++pt ) + if ( isupper( *pt )) + *pt = tolower( *pt ); + dpt = strchr(spt,'.'); + if ( dpt==NULL ) dpt = spt+strlen(spt); + if ( dpt-spt>8 || strlen(dpt)>4 ) { + char exten[8]; + strncpy(exten,dpt,7); + exten[4] = '\0'; /* it includes the dot */ + if ( dpt-spt>6 ) + dpt = spt+6; + *dpt++ = '~'; + *dpt++ = '1'; + strcpy(dpt,exten); + } +return( IsResourceInFile(buffer)); +} + +int main(int argc, char **argv) { + int i, ret = 0; + + for ( i=1; i<argc; ++i ) + if ( *argv[i]=='-' ) { + char *pt = argv[i]; + if ( pt[1]=='-' ) ++pt; + if (strcmp(pt,"-latin1")==0 ) + tolatin1 = true; + else if (strcmp(pt,"-force")==0 || strcmp(pt,"-f")==0 ) + force = true; + else if (strcmp(pt,"-inquire")==0 || strcmp(pt,"-i")==0 ) + force = true; + else if (strcmp(pt,"-afm")==0 ) + doafm = true; + else { + fprintf( stderr, "Usage: %s [-force] [-inquire] [-latin1] [-afm] macfiles\n", + argv[0] ); + fprintf( stderr, " if -force is given you will not be asked about replacing existing files\n" ); + fprintf( stderr, " if -inquire is given you will be asked about writing each file (whether\n" ); + fprintf( stderr, "\tit exists or not). -inquire overrides -force.\n" ); + fprintf( stderr, " if -latin1 is given nfnts will be reencoded to latin1 (else left in mac roman)\n" ); + fprintf( stderr, " if -afm is given then an incomplete afm file will be generated from any fonds.\n" ); + fprintf( stderr, " macfile may be a macbinary (.bin), binhex (.hqx) or bare resource fork.\n" ); + exit(0); + } + } else if ( !FindResourceFile(argv[i])) { + fprintf( stderr, "Can't find an appropriate resource fork in %s\n", argv[i]); + ret=1; + } +return( ret ); +} diff --git a/macfonts.h b/macfonts.h new file mode 100644 index 0000000..41461d8 --- /dev/null +++ b/macfonts.h @@ -0,0 +1,73 @@ +/* Copyright (C) 2001 by George Williams */ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + + * The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define CHR(ch1,ch2,ch3,ch4) (((ch1)<<24)|((ch2)<<16)|((ch3)<<8)|(ch4)) +#define true 1 +#define false 0 + +#define forever for (;;) + +enum style_flags { sf_bold = 1, sf_italic = 2, sf_underline = 4, sf_outline = 8, + sf_shadow = 0x10, sf_condense = 0x20, sf_extend = 0x40 }; + +typedef struct fond { + char *fondname; + int first, last; + int assoc_cnt; + struct assoc { + short size, style, id; + } *assoc; + /* size==0 => scalable */ + /* style>>8 is the bit depth (0=>1, 1=>2, 2=>4, 3=>8) */ + /* search order for ID is sfnt, NFNT, FONT */ + int stylewidthcnt; + struct stylewidths { + short style; + short *widthtab; /* 4.12 fixed number with the width specified as a fraction of an em */ + } *stylewidths; + int stylekerncnt; + struct stylekerns { + short style; + int kernpairs; + struct kerns { + unsigned char ch1, ch2; + short offset; /* 4.12 */ + } *kerns; + } *stylekerns; + struct fond *next; +} FOND; + +extern int tolatin1; +extern const char *macnames[]; +extern const char *styles[]; + +extern int getushort(FILE *f); +extern long getlong(FILE *f); +extern int cleanfilename(char *filename); + +extern void SearchNFNTResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, + long name_list, FOND *fonds); diff --git a/readnfnt.c b/readnfnt.c new file mode 100644 index 0000000..c55794d --- /dev/null +++ b/readnfnt.c @@ -0,0 +1,466 @@ +/* Copyright (C) 2001 by George Williams */ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + + * The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "macfonts.h" + +const char *macnames[] = { + NULL, "Eth", "eth", "Lslash", "lslash", "Scaron", "scaron", "Yacute", + "yacute", NULL, NULL, "Thorn", "thorn", NULL, "Zcaron", "zcaron", + NULL, NULL, NULL, NULL, NULL, "onehalf", "onequarter", "onesuperior", + "threequarters", "threesuperior", "twosuperior", "brokenbar", "minus", "multiply", NULL, NULL, + "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle", + "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", + "zero", "one", "two", "three", "four", "five", "six", "seven", + "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", + "at", "A", "B", "C", "D", "E", "F", "G", + "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", + "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", + "grave", "a", "b", "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", "m", "n", "o", + "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", NULL, + "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", + "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave", + "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute", + "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", + "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph", "germandbls", + "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE", "Oslash", + "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff", "summation", + "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", "ae", "oslash", + "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", "Delta", "guillemotleft", + "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde", "Otilde", "OE", "oe", + "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", "lozenge", + "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl", + "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", + "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", + "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", + "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", +NULL}; + +static unsigned char mac2iso[] = { + 0, 208, 240, 0, 0, 0, 0, 221, 253, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 33, 34, 35, 36, 37, 38, 0, 40, 41, 42, 43, 44, 173, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 0, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, + 196, 197, 199, 201, 209, 214, 220, 225, 224, 226, 228, 227, 229, 231, 233, 232, + 234, 235, 237, 236, 238, 239, 241, 243, 242, 244, 246, 245, 250, 249, 251, 252, + 0, 176, 162, 163, 0, 0, 0, 223, 174, 169, 0, 180, 168, 0, 198, 216, + 0, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 186, 0, 230, 248, + 191, 161, 0, 0, 0, 0, 0, 171, 187, 0, 0, 192, 195, 213, 0, 0, + 0, 0, 0, 0, 96, 39, 247, 0, 255, 0, 0, 0, 0, 0, 0, 0, + 0, 183, 0, 0, 0, 194, 202, 193, 203, 200, 205, 206, 207, 204, 211, 212, + 0, 210, 218, 219, 217, 0, 0, 0, 0, 0, 0, 0, 184, 0, 0, 0 +}; + +static unsigned char iso2mac[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 33, 34, 35, 36, 37, 38, 213, 40, 41, 42, 43, 44, 0, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 212, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 193, 162, 163, 0, 0, 0, 0, 172, 169, 187, 199, 0, 45, 168, 0, + 161, 177, 0, 0, 171, 0, 0, 225, 252, 0, 188, 200, 0, 0, 0, 192, + 203, 231, 229, 204, 128, 129, 174, 130, 233, 131, 230, 232, 237, 234, 235, 236, + 1, 132, 241, 238, 239, 205, 133, 0, 175, 244, 242, 243, 134, 7, 0, 167, + 136, 135, 137, 139, 138, 140, 190, 141, 143, 142, 144, 145, 147, 146, 148, 149, + 2, 150, 152, 151, 153, 155, 154, 214, 191, 157, 156, 158, 159, 8, 0, 216 +}; +const char *styles[]= { "Bold", "Italic", "Underline", "Outline", + "Shadow", "Condensed", "Extended", NULL }; + +struct MacFontRec { + short fontType; + short firstChar; + short lastChar; + short widthMax; + short kernMax; /* bb learing */ + short Descent; /* maximum negative distance below baseline*/ + short fRectWidth; /* bounding box width */ + short fRectHeight; /* bounding box height */ + unsigned short *offsetWidths;/* offset to start of offset/width table */ + /* 0xffff => undefined, else high byte is offset in locTable, */ + /* low byte is width */ + short ascent; + short descent; + short leading; + short rowWords; /* shorts per row */ + unsigned short *fontImage; /* rowWords*fRectHeight */ + /* Images for all characters plus one extra for undefined */ + unsigned short *locs; /* lastchar-firstchar+3 words */ + /* Horizontal offset to start of n'th character. Note: applies */ + /* to each row. Missing characters have same loc as following */ +}; + +typedef struct rect { + short left,width, height,bottom; +} Rect; + +static void LoadNFNT(FILE *f,struct MacFontRec *font, long offset) { + long here = ftell(f); + long baseow; + long ow; + int i; + + offset += 4; /* skip over the length */ + fseek(f,offset,SEEK_SET); + memset(font,'\0',sizeof(struct MacFontRec)); + font->fontType = getushort(f); + font->firstChar = getushort(f); + font->lastChar = getushort(f); + font->widthMax = getushort(f); + font->kernMax = (short) getushort(f); + font->Descent = (short) getushort(f); + font->fRectWidth = getushort(f); + font->fRectHeight = getushort(f); + baseow = ftell(f); + ow = getushort(f); + font->ascent = getushort(f); + font->descent = getushort(f); + if ( font->Descent>=0 ) { + ow |= (font->Descent<<16); + font->Descent = -font->descent; /* Possibly overkill, but should be safe */ + } + font->leading = getushort(f); + font->rowWords = getushort(f); + font->fontImage = calloc(font->rowWords*font->fRectHeight,sizeof(short)); + font->locs = calloc(font->lastChar-font->firstChar+3,sizeof(short)); + font->offsetWidths = calloc(font->lastChar-font->firstChar+3,sizeof(short)); + for ( i=0; i<font->rowWords*font->fRectHeight; ++i ) + font->fontImage[i] = getushort(f); + for ( i=0; i<font->lastChar-font->firstChar+3; ++i ) + font->locs[i] = getushort(f); + fseek(f,baseow+2*ow,SEEK_SET); + for ( i=0; i<font->lastChar-font->firstChar+3; ++i ) + font->offsetWidths[i] = getushort(f); + fseek(f,here,SEEK_SET); +} + +static int FontHasChar(struct MacFontRec *font, int ch ) { + if ( ch<font->firstChar || ch>font->lastChar || ch==0 || ch=='\t' || ch=='\r' ) +return( false ); + +return ( font->offsetWidths[ch-font->firstChar]!=0xffff ); +} + +static int GetFontCount(struct MacFontRec *font) { + int cnt=0, i; + + for ( i=font->firstChar; i<=font->lastChar; ++i ) { + if ( FontHasChar(font,i) ) + ++cnt; + } +return( cnt ); +} + +static int GetFontAvgWidth(struct MacFontRec *font) { + int cnt=0, i, wid=0,ch; + /* Only average those characters in the encoding */ + + for ( i=font->firstChar; i<=font->lastChar; ++i ) { + if ( tolatin1 ) { + if ( i<256 && mac2iso[i]!=0 ) + ch = mac2iso[i]; + else + continue; + } else + ch = i; + if ( FontHasChar(font,ch) ) { + ++cnt; + wid += (font->offsetWidths[ch-font->firstChar]&0xff); + } + } +return( cnt>0?wid*10/cnt:0 ); +} + +static int AnyBitsSet(unsigned short *pt, int bits, int bite ) { + int i; + + for ( i=bits; i<bite; ++i ) + if ( pt[i>>4]&(1<<(15-(i&15))) ) +return( true ); + +return( false ); +} + +static int GetCharBBox(struct MacFontRec *font, int ch, Rect *bbox ) { + unsigned short *widths = font->offsetWidths; + unsigned short *locs = font->locs; + unsigned short *rows = font->fontImage; + int i; + int ow; + + ch -= font->firstChar; + ow = widths[ch]; + bbox->left = (ow>>8)+font->kernMax; bbox->width = locs[ch+1]-locs[ch]; + bbox->height = font->fRectHeight; bbox->bottom = -font->descent; + for ( i=0; i<font->fRectHeight; ++i ) + if ( AnyBitsSet(rows+i*font->rowWords,locs[ch],locs[ch+1]) ) + break; + bbox->height -= i; + for ( i=0; i<bbox->height; ++i ) + if ( AnyBitsSet(rows+(font->fRectHeight-i-1)*font->rowWords,locs[ch],locs[ch+1]) ) + break; + bbox->bottom += i; bbox->height -= i; + if ( bbox->height<0 ) bbox->height = 0; +return( ow&0xff ); /* Width */ +} + +static void WriteRow(FILE *bdf,unsigned short *test, int bits, int bite ) { + int i; + int cnt=0x8, nibble=0; + char buffer[80], *pt=buffer; + + for ( i=bits; i<bite; ++i ) { + if ( test[i>>4]&(1<<(15-(i&15))) ) + nibble |= cnt; + if ( (cnt>>=1)==0 ) { + if ( nibble>=10 ) + *pt++ = 'A'+nibble-10; + else + *pt++ = '0'+nibble; + cnt=0x8; + nibble=0; + } + } + if ( cnt!=0x8 ) { + if ( nibble>=10 ) + *pt++ = 'A'+nibble-10; + else + *pt++ = '0'+nibble; + } + if ( (pt-buffer)&1 ) + *pt++ = '0'; /* pad out to a byte */ + *pt++ = '\n'; + *pt = '\0'; + fputs(buffer,bdf); +} + +static void WriteBitmap(FILE *bdf, struct MacFontRec *font, int ch, Rect *rct ) { + unsigned short *locs = font->locs; + unsigned short *rows = font->fontImage; + int i; + int bits, bite; + int rowf, rowe; + + ch -= font->firstChar; + bits = locs[ch]; bite = locs[ch+1]; + rowf = font->fRectHeight - (rct->height+font->descent+rct->bottom); + rowe = font->fRectHeight-(rct->bottom+font->descent); + for ( i=rowf; i<rowe; ++i ) + WriteRow(bdf,rows+i*font->rowWords,bits,bite); +} + +static void WriteChar(FILE *bdf,struct MacFontRec *font,int enc, int index, + int size, FOND *mine, struct assoc *ass) { + Rect rct; + int width; + short *widths = NULL; + + if ( mine!=NULL && ass!=NULL ) { + int i; + /* I'm ignoring the glyph width table in the nfnt, and just looking at*/ + /* the family table in the fond */ + for ( i=0; i<mine->stylewidthcnt; ++i ) + if ( mine->stylewidths[i].style == ass->style ) { + widths = mine->stylewidths[i].widthtab; + break; + } + } + + if ( index==0 ) + fprintf(bdf,"STARTCHAR .notdef\n"); + else if ( index<256 && macnames[index]!=NULL ) + fprintf(bdf,"STARTCHAR %s\n", macnames[index]); + else + fprintf(bdf,"STARTCHAR char%04x\n", index ); + width = GetCharBBox(font,index,&rct); + fprintf(bdf,"ENCODING %d\n", enc ); + fprintf(bdf,"SWIDTH %ld 0\n", + widths==NULL?width*1000L/size:((widths[index]*1000L+(1<<11))>>12) ); + fprintf(bdf,"DWIDTH %d 0\n", width ); + fprintf(bdf,"BBX %d %d %d %d\n", rct.width, rct.height, rct.left, rct.bottom ); + fprintf(bdf,"BITMAP\n" ); + WriteBitmap(bdf,font,index,&rct); + fprintf(bdf,"ENDCHAR\n" ); +} + +static void DumpNFNT2BDF(FILE *bdf,struct MacFontRec *font, char *resname, + FOND *mine, struct assoc *ass) { + int cnt, avg; + int style = ass!=NULL ? ass->style : 0; + int size = ass!=NULL ? ass->size : font->fRectHeight; + int i; + + cnt = GetFontCount(font); + avg = GetFontAvgWidth(font); + fprintf(bdf,"STARTFONT 2.1\n"); + fprintf(bdf, "FONT -Fondu-%s-%s-%s-%s--%d-%d0-75-75-%s-%d-%s-1\n", + (mine!=NULL && mine->fondname!=NULL)?mine->fondname:resname, + (style&sf_bold)?"Bold":"Medium", + (style&sf_italic)?"I":"R", + (style&sf_condense)?"Condensed":(style&sf_extend)?"Extended":"Normal", + size, (size*72+37)/75, + (font->fontType&0xf000)==0xb000?"M":"P", + avg, + tolatin1?"MacRoman":"ISO8859" ); + + fprintf(bdf, "SIZE %d 75 75\n", (size*72+37)/75 ); + fprintf(bdf, "FONTBOUNDINGBOX %d %d %d %d\n", font->fRectWidth, font->fRectHeight, font->kernMax, -font->descent ); + fprintf(bdf, "COMMENT Created by Fondu from a mac NFNT/FONT resource\n" ); + fprintf(bdf, "STARTPROPERTIES 17\n" ); + fprintf(bdf, "FOUNDRY \"Fondu\"\n" ); + fprintf(bdf, "FAMILY_NAME \"%s\"\n", mine!=NULL && mine->fondname!=NULL?mine->fondname:resname ); + fprintf(bdf, "WEIGHT_NAME \"%s\"\n", (style&sf_bold)?"Bold":"Medium" ); + fprintf(bdf, "SLANT \"%s\"\n", (style&sf_italic)?"I":"R" ); + fprintf(bdf, "SETWIDTH_NAME \"%s\"\n", (style&sf_condense)?"Condensed":(style&sf_extend)?"Extended":"Normal" ); + fprintf(bdf, "ADD_STYLE_NAME \"\"\n" ); + fprintf(bdf, "PIXEL_SIZE %d\n", size ); + fprintf(bdf, "POINT_SIZE %d0\n", (size*72+37)/75 ); + fprintf(bdf, "RESOLUTION_X 75\n" ); + fprintf(bdf, "RESOLUTION_Y 75\n" ); + fprintf(bdf, "SPACING \"%s\"\n", (font->fontType&0xf000)==0xb000?"M":"P"); + fprintf(bdf, "AVERAGE_WIDTH %d\n", avg ); + fprintf(bdf, "CHARSET_REGISTRY \"%s\"\n",tolatin1?"ISO8859":"MacRoman" ); + fprintf(bdf, "CHARSET_ENCODING \"1\"\n" ); + fprintf(bdf, "FONT_ASCENT %d\n", font->ascent ); + fprintf(bdf, "FONT_DESCENT %d\n", font->descent ); + fprintf(bdf, "FACE_NAME \"" ); + if ( *resname!='\0' ) { + fprintf(bdf, "%s\"\n", resname ); + } else if ( mine!=NULL && mine->fondname!=NULL ) { + fprintf(bdf, "%s", mine->fondname ); + if ( ass!=NULL ) { + for ( i=0; styles[i]!=NULL; ++i ) + if ( ass->style&(1<<i)) + fprintf( bdf, "%s", styles[i]); + } + fprintf( bdf, "\"\n" ); + } else + fprintf( bdf, "nameless\"\n" ); + fprintf(bdf, "ENDPROPERTIES\n" ); + fprintf(bdf, "CHARS %d\n", cnt ); + if ( tolatin1 ) { + for ( i=0; i<=255; ++i ) { + int ch = iso2mac[i]; + if ( FontHasChar(font,ch) ) /* character exists */ + WriteChar(bdf,font,ch,i,size,mine,ass); + } + for ( i=font->firstChar; i<=font->lastChar; ++i ) + if ( (i>=256 || mac2iso[i]==0) && FontHasChar(font,i) ) + WriteChar(bdf,font,-1,i,size,mine,ass); + } else { + for ( i=font->firstChar; i<=font->lastChar; ++i ) + if ( FontHasChar(font,i) ) + WriteChar(bdf,font,i,i,size,mine,ass); + } + fprintf(bdf, "ENDFONT\n" ); +} + +void SearchNFNTResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, + long name_list, FOND *fonds) { + long here, start = ftell(f); + long roff; + int rname = -1; + char resname[256], name[300]; + int ch1, ch2; + static int ucnt; + int i,j; + int res_id; + FILE *bdf; + FOND *mine; + struct assoc *ass; + struct MacFontRec font; + + fseek(f,rlistpos,SEEK_SET); + for ( i=0; i<subcnt; ++i ) { + rname = (short) getushort(f); + /* flags = */ getc(f); + ch1 = getc(f); ch2 = getc(f); + roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f)); + /* mbz = */ getlong(f); + here = ftell(f); + LoadNFNT(f,&font, roff); + ass = NULL; + for ( mine = fonds; mine!=NULL; mine = mine->next ) { + for ( i=0; i<mine->assoc_cnt; ++i ) + if ( res_id==mine->assoc[i].id ) { + ass = &mine->assoc[i]; + break; + } + if ( ass!=NULL ) + break; + } + resname[0] = '\0'; + if ( rname!=-1 ) { + fseek(f,name_list+rname,SEEK_SET); + ch1 = getc(f); + fread(resname,1,ch1,f); + sprintf( name, "%s-%d.bdf", resname, ass!=NULL?ass->size:font.fRectHeight ); + } else if ( ass!=NULL ) { + if ( mine->fondname==NULL ) + sprintf( name, "Untitled%d-%d.bdf", ++ucnt, ass->size ); + else { + strcpy( name, mine->fondname ); + for ( j=0; styles[j]!=NULL; ++j ) + if ( ass->style&(1<<j)) + strcat(name,styles[j]); + sprintf( name+strlen(name), "-%d.bdf", ass->size ); + } + } else + sprintf(name,"Untitled%d-%d.bdf", ++ucnt, font.fRectHeight ); + fseek(f,here,SEEK_SET); + if ( !cleanfilename(name)) + /* Do Nothing */; + else if ( (font.fontType&0xc)!=0 ) + fprintf( stderr, "The bitmap font %s a depth greater than 1 and is ignored\n", name ); + else { + bdf = fopen( name,"w+" ); + if ( bdf==NULL ) + fprintf( stderr, "Can't open %s for output\n", name ); + else + DumpNFNT2BDF(bdf,&font,resname,mine,ass); + } + free( font.offsetWidths ); + free( font.fontImage ); + free( font.locs ); + } + fseek(f,start,SEEK_SET); +} |