/* Copyright (C) 2001-2004 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 #include #include #include #include "macfonts.h" #define CHR(ch1,ch2,ch3,ch4) (((ch1)<<24)|((ch2)<<16)|((ch3)<<8)|(ch4)) #define true 1 #define false 0 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 ); } /* 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, end; int rname = -1; char name[300]; int ch1, ch2; int i, j, k, l, ch, rlen, cnt; FOND *head=NULL, *cur; long widoff, kernoff, styleoff, bboff, offsetstart, glyphenc; fseek(f,rlistpos,SEEK_SET); for ( i=0; ifondname = strdup(name); printf( "\nFOND %s\n", name ); } else printf( "\nFOND nameless\n" ); offset += 4; fseek(f,offset-4,SEEK_SET); printf( "Resource len=%d\n", rlen = getlong(f)); printf( "flags = %x\n", getushort(f)); /* 1 => mbz */ /* 2 => has a glyph width table */ /* 1<<12 => ignore global FractEnable */ /* 1<<13 => more on the above */ /* 1<<14 => don't use fractional width table */ /* 1<<15 => fixed width */ printf( "famid = %d\n", getushort(f)); cur->first = getushort(f); cur->last = getushort(f); printf( "first=%d, last=%d\n", cur->first, cur->last ); /* on a 1 point font... */ printf( "ascent = %g\n", getushort(f)/(double) (1<<12)); printf( "descent = %g\n", (short) getushort(f)/(double) (1<<12)); printf( "leading = %g\n", getushort(f)/(double) (1<<12)); printf( "widmax = %g\n", getushort(f)/(double) (1<<12) ); if ( (widoff = getlong(f))!=0 ) widoff += offset; if ( (kernoff = getlong(f))!=0 ) kernoff += offset; if ( (styleoff = getlong(f))!=0 ) styleoff += offset; printf( "width table offset = %d\n", widoff==0?0:widoff-offset); printf( "kern table offset = %d\n", kernoff==0?0:kernoff-offset); printf( "style table offset = %d\n", styleoff==0?0:styleoff-offset); printf( "extra width values:\n" ); printf( " plain: %d\n", getushort(f)); printf( " bold: %d\n", getushort(f)); printf( " italic: %d\n", getushort(f)); printf( " underline: %d\n", getushort(f)); printf( " outline: %d\n", getushort(f)); printf( " shadow: %d\n", getushort(f)); printf( " condensed: %d\n", getushort(f)); printf( " extended: %d\n", getushort(f)); printf( " not used: %d\n", getushort(f)); /* internal & undefined, for international scripts = */ getlong(f); printf( "version=%d\n", getushort(f)); /* not the font version, but the format of the FOND */ cur->assoc_cnt = getushort(f)+1; printf( "Association cnt=%d\n", cur->assoc_cnt ); cur->assoc = calloc(cur->assoc_cnt,sizeof(struct assoc)); for ( j=0; jassoc_cnt; ++j ) { cur->assoc[j].size = getushort(f); cur->assoc[j].style = getushort(f); cur->assoc[j].id = getushort(f); printf( " size=%d style=%x id=%d\n", cur->assoc[j].size, cur->assoc[j].style, cur->assoc[j].id ); } end = offset+rlen; offsetstart = ftell(f); bboff = 0; if ( widoff!=0 || kernoff!=0 || styleoff!=0 ) { /* if any of these three tables exists there will be an offset table */ int test; printf( "Offset table cnt=%d\n", cnt=getushort(f)+1 ); for ( j=0; jstylewidthcnt = cnt; cur->stylewidths = calloc(cnt,sizeof(struct stylewidths)); for ( j=0; jstylewidths[j].style = getushort(f); cur->stylewidths[j].widthtab = malloc((cur->last-cur->first+3)*sizeof(short)); printf( " Style=%x\n", cur->stylewidths[j].style); for ( k=cur->first; k<=cur->last+2; ++k ) cur->stylewidths[j].widthtab[k] = getushort(f); } if ( cnt>0 ) { printf( "Widths for style %x%s\n", cur->stylewidths[0].style, (cnt>1?" (I'm not printing out the others)":"") ); for ( k=cur->first; k<=cur->last; ++k ) printf( "Width %d (%c): %g\n", k, k>=32&&k<127?k:k>=160?k:' ', cur->stylewidths[0].widthtab[k]/(double)(1<<12)); } } if ( kernoff!=0 ) { fseek(f,kernoff,SEEK_SET); printf( "Style kern entries: %d\n", cnt = getushort(f)+1); cur->stylekerncnt = cnt; cur->stylekerns = calloc(cnt,sizeof(struct stylekerns)); for ( j=0; jstylekerns[j].style = getushort(f); cur->stylekerns[j].kernpairs = getushort(f); cur->stylekerns[j].kerns = malloc(cur->stylekerns[j].kernpairs*sizeof(struct kerns)); printf( " Style=%x kernpairs=%d\n", cur->stylekerns[j].style,cur->stylekerns[j].kernpairs); for ( k=0; kstylekerns[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); } } } if ( styleoff!=0 ) { int class; fseek(f,styleoff,SEEK_SET); printf( "PS Font Class Flags: %x\n", class = getushort(f)); /* How to create a bold (italic, condensed) font when we don't have one */ if ( class&1 ) printf( " 0x1 Font name needs coordinating\n" ); if ( class&2 ) printf( " 0x2 Needs MacVector reencoding\n" ); if ( class&4 ) printf( " 0x4 Can be outlined with PaintType==2\n" ); if ( class&8 ) printf( " 0x8 Do not embolded by smear & white out\n" ); if ( class&0x10 ) printf( " 0x10 Do not embolded by smearing\n" ); if ( class&0x20 ) printf( " 0x20 Embolden by increasing size\n" ); if ( class&0x40 ) printf( " 0x40 Do not oblique font to italicize\n" ); if ( class&0x80 ) printf( " 0x80 No auto-condense\n" ); if ( class&0x100 ) printf( " 0x100 No auto-expand\n" ); if ( class&0x200 ) printf( " 0x200 Needs some other encoding scheme\n" ); printf( " Glyph encoding offset: %d\n", glyphenc = getlong(f)); /* offset from start of table */ /* reserved = */ getlong(f); /* 48 (byte) indeces into the name table */ printf( "Plain index is: %d\n", getc(f)); printf( "Bold index is: %d\n", getc(f)); printf( "Italic index is: %d\n", getc(f)); for ( j=3; j<48; ++j ) getc(f); printf( " String count: %d\n", cnt = getushort(f)); /* basename length = */ k = getc(f); printf( " BaseFontName: \"" ); for ( j=0; j 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 */ }; static void LoadNFNT(FILE *f,struct MacFontRec *font, long offset) { long here = ftell(f); long baseow; long ow; int i; fseek(f,offset,SEEK_SET); printf( "NFNT length = %d\n", getlong(f)); 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; irowWords*font->fRectHeight; ++i ) font->fontImage[i] = getushort(f); for ( i=0; ilastChar-font->firstChar+3; ++i ) font->locs[i] = getushort(f); fseek(f,baseow+2*ow,SEEK_SET); for ( i=0; ilastChar-font->firstChar+3; ++i ) font->offsetWidths[i] = getushort(f); fseek(f,here,SEEK_SET); } 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; int i; int res_id; FOND *mine; struct assoc *ass; struct MacFontRec font; fseek(f,rlistpos,SEEK_SET); for ( i=0; inext ) { for ( i=0; iassoc_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); resname[ch1] = '\0'; sprintf( name, "%s-%d.bdf", resname, ass!=NULL?ass->size:font.fRectHeight ); fseek(f,here,SEEK_SET); } printf( "NFNT %d", res_id ); if ( resname[0]!='\0' ) printf( " %s", resname ); if ( ass!=NULL ) printf( "in %s size=%d\n", mine->fondname, ass->size ); else printf( "\n" ); printf( " type=%x first=%x, last=%x widMax=%d kMax=%d, ndescent=%d\n rWidth=%d rHeight=%d rWords=%d\n", (unsigned short) font.fontType, font.firstChar, font.lastChar, font.widthMax, font.kernMax, font.Descent, font.fRectWidth, font.fRectHeight, font.rowWords ); } fseek(f,start,SEEK_SET); } static void SearchPostscriptResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, long name_list, FOND *fonds) { long here = ftell(f); int rname = -1, tmp; int ch1, ch2; int i; /* 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 */ fseek(f,rlistpos,SEEK_SET); for ( i=0; ifullval ) { fullval = val; fullstr = off; fulllen = len; if ( val==2 || val==3 ) 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; if ( val==3 ) { for ( i=0; i'!' && ch!='*' && ch!='?' && ch!='/' && ch!='\\' && ch<0x7f ) *pt++ = ch; } } else { for ( i=0; i'!' && ch!='*' && ch!='?' && ch!='/' && ch!='\\' && ch<0x7f ) *pt++ = ch; } } *pt = '\0'; /* strcpy(pt,isotf?".otf":".ttf"); */ return( true ); } static void SearchTtfResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, long name_list, FOND *fonds) { long start = ftell(f), here; long roff; int rname = -1; int ch1, ch2; int i; char buffer[200]; fseek(f,rlistpos,SEEK_SET); for ( i=0; i>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')) /* No FOND */ ; else if ( tag==CHR('N','F','N','T')) /* Has FOND */ SearchNFNTResources(f,rpos,subcnt,rdata_pos,name_list,fondlist); else if ( tag==CHR('s','f','n','t')) /* Has FOND */ SearchTtfResources(f,rpos,subcnt,rdata_pos,name_list,fondlist); else if ( tag==CHR('F','O','N','D')) ; } return( true ); } static int HasResourceFork(char *filename) { /* If we're on a mac, we can try to see if we've got a real resource fork */ /* linux has an HFS+ driver (or whatever) too, so we might as well always */ /* do this check */ char *respath = malloc(strlen(filename)+strlen("/..namedfork/rsrc")+1); FILE *temp; int ret = false; strcpy(respath,filename); strcat(respath,"/..namedfork/rsrc"); temp = fopen(respath,"r"); free(respath); if ( temp!=NULL ) { ret = IsResourceFork(temp,0); fclose(temp); } return( ret ); } 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 = 128+((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>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; i8 || 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