diff options
author | George Williams <gww@silcom.com> | 2001-12-05 07:55:34 +0000 |
---|---|---|
committer | George Williams <gww@silcom.com> | 2001-12-05 07:55:34 +0000 |
commit | 5a3715c05cd1e3f5c362a465bc5f2c6180fbe2be (patch) | |
tree | cc992b496635f7ad43df854c5633cc56e0c57fd6 | |
parent | 5cef931ff57c8bc8259cc97d11a86782f885488e (diff) |
First version of ufond
Fixes to fondu
First version of showfond
-rw-r--r-- | LICENSE | 28 | ||||
-rw-r--r-- | Makefile | 25 | ||||
-rw-r--r-- | README | 16 | ||||
-rw-r--r-- | crctab.c | 142 | ||||
-rw-r--r-- | fondu.c | 20 | ||||
-rw-r--r-- | readnfnt.c | 15 | ||||
-rw-r--r-- | showfond.c | 692 | ||||
-rw-r--r-- | ufond.c | 830 | ||||
-rw-r--r-- | ufond.h | 140 | ||||
-rw-r--r-- | ufondbdf.c | 449 | ||||
-rw-r--r-- | ufondpfb.c | 177 | ||||
-rw-r--r-- | ufondttf.c | 271 |
12 files changed, 2800 insertions, 5 deletions
@@ -0,0 +1,28 @@ +PfaEdit is copyright (C) 2000,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. + +The configure script is subject to the GNU public license. See the file +COPYING. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..06dcddf --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +CC = gcc +WFLAGS = -Wmissing-prototypes -Wunused -Wimplicit -Wreturn-type -Wparentheses -pedantic +CFLAGS = -g $(WFLAGS) +FONDUOBJS = fondu.o readnfnt.o +UFONDOBJS = ufond.o ufondbdf.o ufondpfb.o ufondttf.o crctab.o +SHOWOBJS = showfond.o + +bindir = /usr/local/bin + +all: fondu ufond showfond + +fondu: $(FONDUOBJS) + $(CC) $(CFLAGS) -o fondu $(FONDUOBJS) + +ufond: $(UFONDOBJS) + $(CC) $(CFLAGS) -o ufond $(UFONDOBJS) + +showfond: $(SHOWOBJS) + $(CC) $(CFLAGS) -o showfond $(SHOWOBJS) + +clean: + -rm -f *.o fondu ufond showfond + +install: all + cp fondu ufond showfond $(bindir) @@ -0,0 +1,16 @@ +BUILDING FONDU + I hope that these programs are sufficiently simple that they don't need a + configure script. Just type + $ make + $ make install + +RUNNING FONDU + fondu mac-font-files + Will convert a series of mac font files (copied over to unix in binhex or + macbinary formats) into their equivalent unix font files. + ufond unix-font-files + Will convert a series of unix font files into the equivalent mac font file(s) + If several of the unix fonts have the same font family, then they will all + be placed in one mac FOND (family). + showfond mac-font-files + Will show some information about various mac font resources. diff --git a/crctab.c b/crctab.c new file mode 100644 index 0000000..1f68c7d --- /dev/null +++ b/crctab.c @@ -0,0 +1,142 @@ +/* GWW: Taken from lrzsz-0.12.20.tar, an xmodem package */ +/* http://www.ohse.de/uwe/software/lrzsz.html */ +/* + * Crc calculation stuff + */ + +/* crctab calculated by Mark G. Mendel, Network Systems Corporation */ +unsigned short crctab[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +/* + * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. + * NOTE: First srgument must be in range 0 to 255. + * Second argument is referenced twice. + * + * Programmers may incorporate any or all code into their programs, + * giving proper credit within the source. Publication of the + * source routines is permitted so long as proper credit is given + * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, + * Omen Technology. + */ + +#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +long cr3tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, +0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, +0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, +0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, +0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, +0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, +0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, +0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, +0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, +0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, +0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, +0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, +0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, +0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, +0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, +0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, +0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, +0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, +0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, +0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, +0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, +0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +#ifdef NFGM +long +UPDC32(b, c) +long c; +{ + return (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)); +} + +#else + +#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) +#endif + +/* End of crctab.c */ @@ -323,9 +323,9 @@ static FOND *BuildFondList(FILE *f,long rlistpos,int subcnt,long rdata_pos, 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].kernpairs = getushort(f)+1; cur->stylekerns[j].kerns = malloc(cur->stylekerns[j].kernpairs*sizeof(struct kerns)); - for ( k=0; k<=cur->stylekerns[j].kernpairs; ++k ) { + 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); @@ -618,6 +618,7 @@ static void SearchTtfResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, } ttfnameset(ttf,name,newname); fclose(ttf); + fseek(f,here,SEEK_SET); } fseek(f,start,SEEK_SET); } @@ -630,6 +631,7 @@ static int IsResourceFork(FILE *f, long offset) { /* file, not at the beginning */ unsigned char buffer[16], buffer2[16]; long rdata_pos, map_pos, type_list, name_list, rpos; + long rdata_len, map_len; unsigned long tag; int i, cnt, subcnt; FOND *fondlist=NULL; @@ -639,13 +641,25 @@ static int IsResourceFork(FILE *f, long offset) { 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]); + rdata_len = ((buffer[8]<<24)|(buffer[9]<<16)|(buffer[10]<<8)|buffer[11]); + map_len = ((buffer[12]<<24)|(buffer[13]<<16)|(buffer[14]<<8)|buffer[15]); + if ( rdata_pos+rdata_len!=map_pos ) +return( false ); fseek(f,map_pos,SEEK_SET); buffer2[15] = buffer[15]+1; /* make it be different */ if ( fread(buffer2,1,16,f)!=16 ) return( false ); + +/* Apple's data fork resources appear to have a bunch of zeroes here instead */ +/* of a copy of the first 16 bytes */ for ( i=0; i<16; ++i ) - if ( buffer[i]!=buffer2[i] ) + if ( buffer2[i]!=0 ) + break; + if ( i!=16 ) { + 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 */ @@ -160,7 +160,9 @@ static void LoadNFNT(FILE *f,struct MacFontRec *font, long offset) { } font->leading = getushort(f); font->rowWords = getushort(f); - font->fontImage = calloc(font->rowWords*font->fRectHeight,sizeof(short)); + font->fontImage = NULL; + if ( font->rowWords!=0 ) + 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 ) @@ -423,10 +425,19 @@ void SearchNFNTResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, /* mbz = */ getlong(f); here = ftell(f); LoadNFNT(f,&font, roff); + if ( font.rowWords==0 ) { + /* This appears to be a flag for 2byte fonts, and I don't under- */ + /* stand the format yet (Can't find any docs either) */ + free( font.offsetWidths ); + free( font.locs ); + continue; + } ass = NULL; +/* The docs say that an sfnt will be found before an NFNT for a given id */ +/* that appears to be a lie. An sfnt will be found for size==0, an NFNT else */ for ( mine = fonds; mine!=NULL; mine = mine->next ) { for ( i=0; i<mine->assoc_cnt; ++i ) - if ( res_id==mine->assoc[i].id ) { + if ( res_id==mine->assoc[i].id && mine->assoc[i].size!=0 ) { ass = &mine->assoc[i]; break; } diff --git a/showfond.c b/showfond.c new file mode 100644 index 0000000..8b60960 --- /dev/null +++ b/showfond.c @@ -0,0 +1,692 @@ +/* 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" + +#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; + + fseek(f,rlistpos,SEEK_SET); + for ( i=0; i<subcnt; ++i ) { + printf( "FOND ResId=%d\n", getushort(f)); + if ( feof(f)) { + fprintf(stderr, "EOF found in FOND list after reading %d resources of %d.\n", i, subcnt ); + break; + } + rname = (short) getushort(f); + printf( " resource flags=%x\n", 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)); + 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); + 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; j<cur->assoc_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; j<cnt; ++j ) { + printf( " Offset to=%d\n", test=getlong(f)); + if ( bboff==0 ) bboff = offsetstart+test; + /* there could be other tables here, but I don't know what */ + /* they would mean */ + } + if ( bboff!=0 ) { + fseek(f,bboff,SEEK_SET); + printf( "Number of font bounding boxes: %d\n", cnt = getushort(f)+1); + for ( j=0; j<cnt; ++j ) { + printf( "Style = %x\n", getushort(f)); + printf( " bb left = %g\n", (short) getushort(f)/(double) (1<<12)); + printf( " bb bottom = %g\n", (short) getushort(f)/(double) (1<<12)); + printf( " bb right = %g\n", (short) getushort(f)/(double) (1<<12)); + printf( " bb top = %g\n", (short) getushort(f)/(double) (1<<12)); + } + } + } + if ( widoff!=0 ) { + fseek(f,widoff,SEEK_SET); + printf( "Style widths entries: %d\n", 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)); + printf( " Style=%x\n", cur->stylewidths[j].style); + for ( k=cur->first; k<=cur->last; ++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; j<cnt; ++j ) { + cur->stylekerns[j].style = getushort(f); + cur->stylekerns[j].kernpairs = getushort(f)+1; + 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; 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); + } + } + } + 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", 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<k; ++j ) + putchar(getc(f)); + printf("\"\n" ); + for ( l=2; l<=cnt; ++l ) { + k = getc(f); + printf( "String %d, length=%d: ", l, k); + if ( k!=0 ) { + ch = getc(f); + if ( ch<32 ) { + printf( "%d,", ch); + for ( j=1; j<k; ++j ) + printf( "%d,", getc(f)); + } else { + putchar(ch); + for ( j=1; j<k; ++j ) + putchar(getc(f)); + } + } + putchar('\n'); + } + /* Now we've got cnt pascal strings, some of which are real */ + /* strings, others contain formatting info */ + /* For any given style you look up its index, in the 48 entry list*/ + /* add one to it */ + /* then load that string, the bytes in the string tell you what */ + /* other strings to concatenate to the base font name to get the */ + /* PS fontname for this style */ + } + fseek(f,here,SEEK_SET); + } + fseek(f,start,SEEK_SET); +return( head ); +} + +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 */ +}; + +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); +} + +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; i<subcnt; ++i ) { + printf( "NFNT Resource %x ", res_id = getushort(f)); + if ( feof(f)) { + fprintf(stderr, "EOF found in NFNT list after reading %d resources of %d.\n", i, subcnt ); + break; + } + rname = (short) getushort(f); + printf( " resource flags=%x\n", 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 ); + } + 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; i<subcnt; ++i ) { + printf( "post ResId=%d\n", getushort(f)); + if ( feof(f)) { + fprintf(stderr, "EOF found in POST list after reading %d resources of %d.\n", i, subcnt ); + break; + } + tmp = (short) getushort(f); + if ( rname==-1 ) rname = tmp; + printf( " resource flags=%x\n", getc(f)); + ch1 = getc(f); ch2 = getc(f); + /*offsets[i] = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));*/ getc(f); + /* mbz = */ getlong(f); + } + fseek(f,here,SEEK_SET); +} + +static void SearchTtfResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, + long name_list, FOND *fonds) { + long start = ftell(f); + long roff; + int rname = -1; + int ch1, ch2; + int i; + /* I think (hope) the sfnt resource is just a copy of the ttf file */ + + fseek(f,rlistpos,SEEK_SET); + for ( i=0; i<subcnt; ++i ) { + printf( "sfnt res=%d\n", getushort(f) ); + if ( feof(f)) { + fprintf(stderr, "EOF found in sfnt list after reading %d resources of %d.\n", i, subcnt ); + break; + } + rname = (short) getushort(f); + printf( " resource flags=%x\n", getc(f)); + ch1 = getc(f); ch2 = getc(f); + roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f)); + /* mbz = */ getlong(f); + } + 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 ); + +/* Apple's data fork resources appear to have a bunch of zeroes here instead */ +/* of a copy of the first 16 bytes */ + for ( i=0; i<16; ++i ) + if ( buffer2[i]!=0 ) + break; + if ( i!=16 ) + 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')) /* 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 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<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 ( !FindResourceFile(argv[i])) { + fprintf( stderr, "Can't find an appropriate resource fork in %s\n", argv[i]); + ret=1; + } +return( ret ); +} @@ -0,0 +1,830 @@ +/* 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 <string.h> +#include <ctype.h> +#include <time.h> +#include <unistd.h> +#include "ufond.h" + +/* ufond [-bin] [-res] [-dfont] [-macbin] [-script num] filelist */ + +/* The basic idea is the following: */ +/* We collect all the files we are supposed to deal with */ +/* we parse each file far enough to get: */ +/* a fontname */ +/* (for bdf) a size */ +/* (for ttf) the mac encoding so we can order the hmtx properly */ +/* (for bdf,ttf) the metrics */ +/* We strip off things like Italic, Bold, Oblique, Condensed, "-" to get a family name */ +/* We collect all files into families */ +/* We generate one FOND for each family and put the bdf and ttf into it */ +/* We generate one seperate resource file for each ps font in the family */ +/* If we do not have a plain style then make a seperate FOND for each style */ +/* and pretend each is plain */ +/* If we have a PS font style with no matching bdf (ie. no metrics) then */ +/* complain (but make an entry for it in the fond anyway?) */ + +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 ); +} + +void putshort(int val, FILE *f) { + putc(val>>8,f); + putc(val&0xff,f); +} + +void putlong(long val, FILE *f) { + putc((val>>24)&0xff,f); + putc((val>>16)&0xff,f); + putc((val>>8)&0xff,f); + putc(val&0xff,f); +} + +enum output_format { of_dfont, of_macbin, of_res } output_format = of_macbin; +static int script = 0; /* Roman */ + +static uint16 HashToId(char *fontname) { + int low = 128, high = 0x4000; + uint32 hash = 0; + + if ( script!=0 ) { + low = 0x4000+(script-1)*0x200; + high = low + 0x200; + } + while ( *fontname ) { + int temp = (hash>>28)&0xf; + hash = (hash<<4) | temp; + hash ^= *fontname++-' '; + } + hash %= (high-low); + hash += low; +return( hash ); +} + +static void Usage(char *prog) { + fprintf( stderr, "Usage: %s [-dfont] [-macbin] [-res] [-script name] fontfile {fontfiles}\n", prog ); + fprintf( stderr, " -dfont\t\tPuts the output into a Mac OS/X dfont file.\n" ); + fprintf( stderr, " -macbin\tPuts the output into a resource fork inside a mac binary file.\n" ); + fprintf( stderr, " -res\tPuts the output into a data file containing a resource fork\n\t\t(you have to figure out how to get it into a real resource fork)" ); + fprintf( stderr, " -script [name|code]\tThe name should be the name of a mac script\n\t\tlike Roman or Cyrillic (not all names are recognized)\n\t\tthe code can be a number representing a script\n" ); + fprintf( stderr, "A list of bdf/ttf files all with the same family name will be merged into\n" ); + fprintf( stderr, "one FOND and all stored in one output files. Any pfb files will be refered\n" ); + fprintf( stderr, "to in the FOND but will live in a seperate file.\n" ); + exit( 1 ); +} + +static Face *ParseArgs(int argc, char **argv) { + Face *head = NULL, *last=NULL, *cur; + int i, bad, val; + char *pt, *end; + + for ( i=1; i<argc; ++i ) { + if ( *argv[i]=='-' ) { + char *pt = argv[i]+1; + if ( *pt=='-' ) ++pt; /* deal with double dashes too */ + if ( strcmp(pt,"dfont")==0 ) + output_format = of_dfont; + else if ( strcmp(pt,"bin")==0 || strcmp(pt,"macbin")==0 ) + output_format = of_macbin; + else if ( strcmp(pt,"res")==0 || strcmp(pt,"resource")==0 ) + output_format = of_res; + else if ( strcmp(pt,"script")==0 ) { + int bad = 0; + if ( ++i >= argc ) + bad=true; + else if ( strcasecmp(argv[i],"roman")==0 ) + script = 0; + else if ( strcasecmp(argv[i],"japanese")==0 ) + script = 1; + else if ( strcasecmp(argv[i],"traditionalchinese")==0 || + strcasecmp(argv[i],"tradchinese")==0 || + strcasecmp(argv[i],"big5")==0 || + strcasecmp(argv[i],"taiwan")==0 ) + script = 2; + else if ( strcasecmp(argv[i],"simplifiedchinese")==0 || + strcasecmp(argv[i],"simpchinese")==0 ) + script = 25; + else if ( strcasecmp(argv[i],"korean")==0 ) + script = 3; + else if ( strcasecmp(argv[i],"arabic")==0 ) + script = 4; + else if ( strcasecmp(argv[i],"hebrew")==0 ) + script = 5; + else if ( strcasecmp(argv[i],"greek")==0 ) + script = 6; + else if ( strcasecmp(argv[i],"cyrillic")==0 || + strcasecmp(argv[i],"russian")==0 ) + script = 7; + else if ( (val = strtol(argv[i],&end,10), *end!='\0') || val<0 || val>128 ) + bad = true; + else + script = val; + if ( bad ) { + fprintf( stderr, "The script argument must be followed by a script name or number\n(Roman=0, Japanese=1, Big5=2, Korean=3, Arabic=4, Hebrew=5, Greek=6, Cyrillic=7)\n" ); + exit(1); + } + } else + Usage(argv[0]); + } else { + cur = calloc(1,sizeof(Face)); + cur->filename = argv[i]; + pt = strrchr(argv[i],'.'); + cur->type = -1; + bad = 0; + if ( pt==NULL ) + /* do nothing */; + else if ( strcasecmp(pt,".bdf")==0 ) { + cur->type = ft_bdf; + bad = !BDFGetNames(cur); + } else if ( strcasecmp(pt,".ttf")==0 || strcasecmp(pt,".otf")==0 ) { + cur->type = ft_ttf; + bad = !TTFGetNames(cur); + } else if ( strcasecmp(pt,".pfb")==0 ) { + cur->type = ft_ps; + bad = !PSGetNames(cur); + } + /* I'm not going to support .pfa files, doing the conversion is */ + /* a pain, and I've already written something that does it. */ + if ( cur->type==-1 ) { + fprintf( stderr, "Unknown file type for %s\n Must be one of .bdf, .pfb, .ttf or .otf\n", argv[i] ); + Usage( argv[0] ); + } else if ( bad ) + Usage( argv[0] ); + if ( head==NULL ) + head = cur; + else + last->next = cur; + last = cur; + } + } + if ( head==NULL ) { + fprintf( stderr, "No files\n" ); + Usage(argv[0]); + } +return( head ); +} + +static Family *SortByFamily(Face *faces) { + Family *head=NULL, *last=NULL, *cur; + Face *next; + int index; + int i,cnt,one; + + for ( ; faces!=NULL ; faces = next ) { + next = faces->next; + /* mac styles may be numbers < 96. Postscript styles <48 */ + /* But we still might get two bitmaps with the same style>=48 so */ + /* merge them into one FOND if they match */ + if ( faces->style<48 ) + for ( cur=head; cur!=NULL && strcmp(cur->familyname,faces->family)!=0; cur = cur->next ); + else + for ( cur=head; cur!=NULL && strcmp(cur->familyname,faces->fontname)!=0; cur = cur->next ); + if ( cur==NULL ) { + cur = calloc(1,sizeof(Family)); + if ( head==NULL ) + head = cur; + else + last->next = cur; + last = cur; + cur->familyname = faces->style<48 ? faces->family : faces->fontname; + } + if ( faces->type!=ft_ps ) cur->fixed = faces->fixed; + index = faces->style; + if ( index>=96 ) { + index = 0; + fprintf( stderr, "%s has a style which doesn't fit in a normal FOND, so we're\ngiving it its own FOND where it can pretend to be plain\n", faces->filename ); + } + if ( faces->type==ft_bdf ) { + faces->next = cur->faces[index]; + cur->faces[index] = faces; + } else if ( faces->type==ft_ttf ) { + if ( cur->ttffaces[index]!=NULL ) + fprintf( stderr, "Attempt to add two scalable fonts for the same style in a FOND\n%s and %s\n", faces->filename, cur->ttffaces[index]->filename ); + cur->ttffaces[index] = faces; + faces->next = NULL; + } else { + index = faces->psstyle; + if ( index>=48 ) { + index = 0; + fprintf( stderr, "%s has a style which doesn't fit in a normal FOND, so we're\ngiving it its own FOND where it can pretend to be plain\n", faces->filename ); + } + if ( cur->psfaces[index]!=NULL ) + fprintf( stderr, "Attempt to add two postscript fonts for the same style in a FOND\n%s and %s\n", faces->filename, cur->psfaces[index]->filename ); + cur->psfaces[index] = faces; + faces->next = NULL; + } + } + + for ( cur=head; cur!=NULL; cur=cur->next ) { + for ( i=0; i<48; ++i ) { + /* ps style is different from mac style, hence the complexity */ + if ( cur->psfaces[i]!=NULL && cur->faces[cur->psfaces[i]->style]==NULL ) { + fprintf( stderr, "A postscript font was found without a bitmap font of the same style\n %s\n", cur->psfaces[i]->filename ); + exit( 1 ); + } + } + for ( i=cnt=0; i<96; ++i ) + if ( cur->faces[i]!=NULL || cur->ttffaces[i]!=NULL ) { + one = i; + ++cnt; + } + if ( one!=0 && cnt==1 ) { + fprintf( stderr, "%s does not have a corresponding plain style font.\nWe will claim it is plain when we build the FOND\n", + cur->faces[one]!=NULL ? cur->faces[one]->filename: + cur->ttffaces[one]->filename ); + cur->faces[0] = cur->faces[one]; + cur->ttffaces[0] = cur->ttffaces[one]; + cur->psfaces[0] = cur->psfaces[one]; + cur->faces[one] = cur->ttffaces[one] = cur->psfaces[one] = NULL; + cur->familyname = cur->faces[one]!=NULL ? cur->faces[one]->fontname: + cur->ttffaces[one]->fontname; + } else if ( cur->faces[0]==NULL && cur->ttffaces[0]==NULL ) { + fprintf( stderr, "The family, %s, does not have a plain style. That would lead to\nconfusion, so I'm giving up.\n", cur->familyname ); + exit( 1 ); + } + cur->id = HashToId(cur->familyname); + } +return( head ); +} + +static void putpsstring(FILE *res,char *fontname) { + putc(strlen(fontname),res); + if ( *fontname ) { + if ( islower(*fontname)) + putc(toupper(*fontname),res); + else + putc(*fontname,res); + for ( ++fontname; *fontname; ++fontname ) + putc(*fontname,res); + } +} + +static uint32 FamilyToFOND(FILE *res,Family *fam) { + uint32 rlenpos = ftell(res), widoffpos, widoffloc, kernloc, styleloc, end; + int i,j,cnt, scnt, strcnt, pscnt, maxw; + Face *face, *test; + int exact, badmatch; + /* Fonds are generally marked system heap and sometimes purgeable (resource flags) */ + + /* Use a ttf font if we've got it (metrics more accurate), else the */ + /* biggest bitmap */ + face = fam->ttffaces[0]; + if ( face==NULL ) { + face = fam->faces[0]; + for ( test = face; test!=NULL; test=test->next ) + if ( test->size > face->size ) face = test; + } + maxw = 0; + for ( i=0; i<256; ++i ) + if ( face->metrics[i]>maxw ) maxw = face->metrics[i]; + + putlong(0,res); /* Fill in length later */ + putshort(fam->fixed?0x9000:0x1000,res); + putshort(fam->id,res); + putshort(0,res); /* First character */ + putshort(255,res); /* Last character */ + putshort((short) ((face->ascent*(1<<12))/(face->ascent+face->descent)),res); + putshort(-(short) ((face->descent*(1<<12))/(face->ascent+face->descent)),res); + putshort((short) ((face->linegap*(1<<12))/(face->ascent+face->descent)),res); + putshort((short) maxw,res); + widoffpos = ftell(res); + putlong(0,res); /* Fill in width offset later */ + putlong(0,res); /* Fill in kern offset later */ + putlong(0,res); /* Fill in style offset later */ + for ( i=0; i<9; ++i ) + putshort(0,res); /* Extra width values */ + putlong(0,res); /* Script for international */ + putshort(2,res); /* FOND version */ + + /* Font association table */ + for ( i=cnt=scnt=0; i<96; ++i ) { + for ( face = fam->faces[i]; face!=NULL; face = face->next ) + ++cnt; + if ( fam->ttffaces[i] ) + ++cnt; + if ( fam->faces[i]!=NULL || fam->ttffaces[i]!=NULL ) + ++scnt; + } + putshort(cnt-1,res); /* Number of faces */ + for ( i=cnt=0; i<96; ++i ) if ( fam->ttffaces[i]!=NULL ) { + putshort(0,res); /* it's scaleable */ + putshort(i,res); /* style */ + fam->ttffaces[i]->id = fam->id + cnt++; + putshort(fam->ttffaces[i]->id,res); + } + for ( i=0; i<96; ++i ) for ( face=fam->faces[i]; face!=NULL; face=face->next ) { + putshort(face->size,res); + putshort(i,res); /* style */ + face->id = fam->id + cnt++; + putshort(face->id,res); /* make up a unique ID */ + } + + /* offset table */ + putshort(1-1,res); /* One table */ + putlong(6,res); /* Offset from start of otab to next byte */ + + /* bounding box table */ + putshort(scnt-1,res); /* One bounding box per style */ + for ( i=0; i<96; ++i ) if ( fam->faces[i]!=NULL || fam->ttffaces[i]!=NULL ) { + /* Use a ttf font if we've got it (metrics more accurate), else the */ + /* biggest bitmap */ + face = fam->ttffaces[i]; + if ( face==NULL ) { + face = fam->faces[i]; + for ( test = face; test!=NULL; test=test->next ) + if ( test->size > face->size ) face = test; + } + putshort(i,res); /* style */ + putshort(face->xmin,res); + putshort(face->ymin,res); + putshort(face->xmax,res); + putshort(face->ymax,res); + } + + widoffloc = ftell(res); + putshort(scnt-1,res); /* One set of width metrics per style */ + for ( i=0; i<96; ++i ) if ( fam->faces[i]!=NULL || fam->ttffaces[i]!=NULL ) { + face = fam->ttffaces[i]; + if ( face==NULL ) { + face = fam->faces[i]; + for ( test = face; test!=NULL; test=test->next ) + if ( test->size > face->size ) face = test; + } + putshort(i,res); /* style */ + for ( j=0; j<256; ++j ) + putshort(face->metrics[j],res); + } + + kernloc = 0; + + exact = badmatch = false; + for ( i=pscnt=0; i<48; ++i ) if ( fam->psfaces[i]!=NULL ) { + ++pscnt; + if ( strcmp(fam->familyname,fam->psfaces[i]->fontname)==0 ) + exact = true; + if ( strncmp(fam->psfaces[i]->fontname,fam->familyname,strlen(fam->familyname))!=0 ) + badmatch = true; + } + styleloc = 0; + if ( pscnt!=0 ) { + char *family = badmatch ? "" : fam->familyname; + int fontclass; + if ( badmatch ) exact = false; + styleloc = ftell(res); + fontclass = 0x1; + if ( fam->psfaces[psf_outline]==NULL ) fontclass |= 4; + if ( fam->psfaces[psf_bold]!=NULL ) fontclass |= 0x18; + if ( fam->psfaces[psf_italic]!=NULL ) fontclass |= 0x40; + if ( fam->psfaces[psf_condense]!=NULL ) fontclass |= 0x80; + if ( fam->psfaces[psf_extend]!=NULL ) fontclass |= 0x100; + putshort(fontclass,res); /* fontClass */ + putlong(0,res); /* Offset to glyph encoding table (which we don't use) */ + putlong(0,res); /* Reserved, MBZ */ + strcnt = 1/* Family Name */ + pscnt-exact /* count of format strings */ + + pscnt-exact /* count of additional strings */; + /* indeces to format strings */ + for ( i=0,pscnt=2; i<48; ++i ) + if ( fam->psfaces[i]==NULL || strcmp(family,fam->psfaces[i]->fontname)==0) + putc(1,res); + else + putc(pscnt++,res); + putshort(strcnt,res); /* strcnt strings */ + putpsstring(res,family); + /* Now the format strings */ + for ( i=0; i<48; ++i ) if ( fam->psfaces[i]!=NULL ) { + if ( strcmp(family,fam->psfaces[i]->fontname)!=0 ) { + putc(1,res); /* Familyname with the following */ + putc(pscnt++,res); + } + } + /* Now the additional names */ + for ( i=0; i<48; ++i ) if ( fam->psfaces[i]!=NULL ) { + if ( strcmp(family,fam->psfaces[i]->fontname)!=0 ) + putpsstring(res,fam->psfaces[i]->fontname+strlen(family)); + } + } + + end = ftell(res); + fseek(res,widoffpos,SEEK_SET); + putlong(widoffloc-rlenpos-4,res); /* Fill in width offset */ + putlong(kernloc!=0?kernloc-rlenpos-4:0,res); /* Fill in kern offset */ + putlong(styleloc!=0?styleloc-rlenpos-4:0,res); /* Fill in style offset */ + + fseek(res,rlenpos,SEEK_SET); + putlong(end-rlenpos-4,res); /* resource length */ + fseek(res,end,SEEK_SET); +return(rlenpos); +} + +/* I presume this routine is called after all resources have been written */ +static void DumpResourceMap(FILE *res,struct resourcetype *rtypes) { + uint32 rfork_base = output_format!=of_macbin?0:128; /* space for mac binary header */ + uint32 resource_base = rfork_base+0x100; + uint32 rend, rtypesstart, mend, namestart; + int i,j; + + fseek(res,0,SEEK_END); + rend = ftell(res); + + if ( output_format!=of_dfont ) { + /* Duplicate resource header */ + putlong(0x100,res); /* start of resource data */ + putlong(rend-rfork_base,res); /* start of resource map */ + putlong(rend-rfork_base-0x100,res); /* length of resource data */ + putlong(0,res); /* don't know the length of the map section yet */ + } else { + for ( i=0; i<16; ++i ) /* 16 bytes of zeroes */ + putc(0,res); + } + + putlong(0,res); /* Some mac specific thing I don't understand */ + putshort(0,res); /* another */ + putshort(0,res); /* another */ + + putshort(4+ftell(res)-rend,res); /* Offset to resource types */ + putshort(0,res); /* Don't know where the names go yet */ + + rtypesstart = ftell(res); + for ( i=0; rtypes[i].tag!=0; ++i ); + putshort(i-1,res); /* Count of different types */ + for ( i=0; rtypes[i].tag!=0; ++i ) { + putlong(rtypes[i].tag,res); /* Resource type */ + putshort(0,res); /* Number of resources of this type */ + putshort(0,res); /* Offset to the resource list */ + } + + /* Now the resource lists... */ + for ( i=0; rtypes[i].tag!=0; ++i ) { + rtypes[i].resloc = ftell(res); + for ( j=0; rtypes[i].res[j].pos!=0; ++j ) { + putshort(rtypes[i].res[j].id,res); + rtypes[i].res[j].nameptloc = ftell(res); + putshort(0xffff,res); /* assume no name at first */ + putc(rtypes[i].res[j].flags,res); /* resource flags */ + /* three byte resource offset */ + putc( ((rtypes[i].res[j].pos-resource_base)>>16)&0xff, res ); + putc( ((rtypes[i].res[j].pos-resource_base)>>8)&0xff, res ); + putc( ((rtypes[i].res[j].pos-resource_base)&0xff), res ); + putlong(0,res); + } + } + namestart = ftell(res); + /* Now the names, if any */ + for ( i=0; rtypes[i].tag!=0; ++i ) { + for ( j=0; rtypes[i].res[j].pos!=0; ++j ) { + if ( rtypes[i].res[j].name!=NULL ) { + rtypes[i].res[j].nameloc = ftell(res); + putc(strlen(rtypes[i].res[j].name),res); /* Length */ + fwrite(rtypes[i].res[j].name,1,strlen(rtypes[i].res[j].name),res); + } + } + } + mend = ftell(res); + + /* Repeat the rtypes list now we know where they go */ + fseek(res,rtypesstart+2,SEEK_SET); /* skip over the count */ + for ( i=0; rtypes[i].tag!=0; ++i ) { + putlong(rtypes[i].tag,res); /* Resource type */ + for ( j=0; rtypes[i].res[j].pos!=0; ++j ); + putshort(j-1,res); /* Number of resources of this type */ + putshort(rtypes[i].resloc-rtypesstart,res); + } + /* And go back and fixup any name pointers */ + for ( i=0; rtypes[i].tag!=0; ++i ) { + for ( j=0; rtypes[i].res[j].pos!=0; ++j ) { + if ( rtypes[i].res[j].name!=NULL ) { + fseek(res,rtypes[i].res[j].nameptloc,SEEK_SET); + putshort(rtypes[i].res[j].nameloc-namestart,res); + } + } + } + + fseek(res,rend,SEEK_SET); + /* Fixup duplicate header (and offset to the name list) */ + if ( output_format!=of_dfont ) { + putlong(0x100,res); /* start of resource data */ + putlong(rend-rfork_base,res); /* start of resource map */ + putlong(rend-rfork_base-0x100,res); /* length of resource data */ + putlong(mend-rend,res); /* length of map section */ + } else { + for ( i=0; i<16; ++i ) + putc(0,res); + } + + putlong(0,res); /* Some mac specific thing I don't understand */ + putshort(0,res); /* another */ + putshort(0,res); /* another */ + + putshort(4+ftell(res)-rend,res); /* Offset to resource types */ + putshort(namestart-rend,res); /* name section */ + + fseek(res,rfork_base,SEEK_SET); + /* Fixup main resource header */ + putlong(0x100,res); /* start of resource data */ + putlong(rend-rfork_base,res); /* start of resource map */ + putlong(rend-rfork_base-0x100,res); /* length of resource data */ + putlong(mend-rend,res); /* length of map section */ +} + +/* MacBinary files use the same CRC that XModem does (in the MacBinary header) */ +/* Taken from zglobal.h in lrzsz-0.12.20.tar, an xmodem package */ +/* http://www.ohse.de/uwe/software/lrzsz.html */ + /* crctab.c */ + extern unsigned short crctab[256]; +# define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) + extern long cr3tab[]; +# define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) +/* End of borrowed code */ + +static int crcbuffer(uint8 *buffer,int size) { + int crc = 0, i; + + for ( i=0; size>=2; i+=2, size-=2 ) + crc = updcrc( ((buffer[i]<<8)|buffer[i+1]) , crc ); +return( crc ); +} + +static void DumpMacBinaryHeader(FILE *res,struct macbinaryheader *mb) { + uint8 header[128], *hpt; char buffer[256], *pt, *dpt; + uint32 len; + time_t now; + int i,crc; + + if ( mb->macfilename==NULL ) { + char *pt = strrchr(mb->binfilename,'/'); + if ( pt==NULL ) pt = mb->binfilename; + else ++pt; + strcpy(buffer,pt); + dpt = strrchr(buffer,'.'); + if ( dpt==NULL ) { + buffer[0] = '_'; + strcpy(buffer+1,pt); + } else + *dpt = '\0'; + mb->macfilename = buffer; + buffer[63] = '\0'; + } + + memset(header,'\0',sizeof(header)); + hpt = header; + *hpt++ = '\0'; /* version number */ + /* Mac Filename */ + pt = mb->macfilename; + *hpt++ = strlen( pt ); + while ( *pt ) + *hpt++ = *pt++; + while ( hpt<header+65 ) + *hpt++ = '\0'; + /* Mac File Type */ + *hpt++ = mb->type>>24; *hpt++ = mb->type>>16; *hpt++ = mb->type>>8; *hpt++ = mb->type; + /* Mac Creator */ + *hpt++ = mb->creator>>24; *hpt++ = mb->creator>>16; *hpt++ = mb->creator>>8; *hpt++ = mb->creator; + *hpt++ = '\0'; /* No finder flags set */ + *hpt++ = '\0'; /* (byte 74) MBZ */ + *hpt++ = '\0'; *hpt++ = '\0'; /* Vert Position in folder */ + *hpt++ = '\0'; *hpt++ = '\0'; /* Hor Position in folder */ + *hpt++ = '\0'; *hpt++ = '\0'; /* window or folder id??? */ + *hpt++ = '\0'; /* protected bit ??? */ + *hpt++ = '\0'; /* (byte 82) MBZ */ + /* Data fork length */ + *hpt++ = '\0'; *hpt++ = '\0'; *hpt++ = '\0'; *hpt++ = '\0'; + /* Resource fork length */ + fseek(res,0,SEEK_END); + len = ftell(res)-sizeof(header); + *hpt++ = len>>24; *hpt++ = len>>16; *hpt++ = len>>8; *hpt++ = len; + + /* Creation time, (seconds from 1/1/1904) */ + time(&now); + /* convert from 1970 based time to 1904 based time */ + now += (1970-1904)*365L*24*60*60; + for ( i=1904; i<1970; i+=4 ) + now += 24*60*60; + /* Ignore any leap seconds */ + *hpt++ = now>>24; *hpt++ = now>>16; *hpt++ = now>>8; *hpt++ = now; + /* Modification time, (seconds from 1/1/1904) */ + *hpt++ = now>>24; *hpt++ = now>>16; *hpt++ = now>>8; *hpt++ = now; + + *hpt++ = '\0'; *hpt++ = '\0'; /* Get Info comment length */ + *hpt++ = 0; /* More finder flags */ + +/* MacBinary 3 */ + memcpy(header+102,"mBIN",4); + header[106] = 0; /* Script. I assume 0 is latin */ + header[107] = 0; /* extended finder flags */ +/* End of MacBinary 3 */ + header[122] = 130; /* MacBinary version 3, written in (129 is MB2) */ + header[123] = 129; /* MacBinary Version 2, needed to read */ + + crc = crcbuffer(header,124); + header[124] = crc>>8; + header[125] = crc; + + fseek(res,0,SEEK_SET); + fwrite(header,1,sizeof(header),res); +} + +static void WriteDummyHeaders(FILE *res) { + /* Leave space for the mac binary header (128bytes) and the mac resource */ + /* file header (256 bytes) */ + int i; + if ( output_format == of_macbin ) { + for ( i=0; i<128; ++i ) + putc(0,res); + } + for ( i=0; i<256; ++i ) + putc(0,res); +} + +static int DumpPostscriptFont(Face *face) { + FILE *res; + int ret = 1; + struct resourcetype resources[2]; + struct macbinaryheader header; + char buffer[63], *pt, *spt, *lcpt=NULL; + char filename[63], *fpt; + + fpt = filename; + for ( pt = buffer, spt = face->fontname; *spt && pt<buffer+sizeof(buffer)-1; ++spt ) { + if ( isupper(*spt)) { + *pt++ = *spt; + lcpt = (spt==face->fontname?spt+5:spt+3); + } else if ( islower(*spt) && spt<lcpt ) + *pt++ = *spt; + if ( isalnum(*spt) && fpt<filename+sizeof(filename)-6 ) + *fpt++ = *spt; + } + *pt = '\0'; *fpt = '\0'; + + if ( output_format!=of_macbin ) + strcpy(filename,buffer); + else + strcat(filename,".bin"); + res = fopen(filename,"w+"); + if ( res==NULL ) +return( 0 ); + + WriteDummyHeaders(res); + memset(resources,'\0',sizeof(resources)); + + resources[0].tag = CHR('P','O','S','T'); + resources[0].res = PSToResources(res,face); + if ( resources[0].res==NULL ) { + fclose(res); + unlink(filename); +return( 0 ); + } + DumpResourceMap(res,resources); + free( resources[0].res ); + + if ( output_format==of_macbin ) { + header.macfilename = buffer; + /* Adobe uses a creator of ASPF (Adobe Systems Postscript Font I assume) */ + /* Fontographer uses ACp1 (Altsys Corp. Postscript type 1???) */ + /* Both include an FREF, BNDL, ICON* and comment */ + /* I shan't bother with that... It'll look ugly with no icon, but oh well */ + header.type = CHR('L','W','F','N'); + header.creator = CHR('G','W','p','1'); + DumpMacBinaryHeader(res,&header); + } + ret = !ferror(res); + if ( fclose(res)==-1 ) ret = 0; +return( ret ); +} + +static void DumpFamily(Family *fam) { + int i,ncnt, tcnt, ret; + int npos, tpos, fpos; + Face *face; + struct resourcetype resources[4]; + struct resource fonds[2]; + FILE *res; + struct macbinaryheader header; + char filename[256]; + + for ( i=0; i<48; ++i ) + if ( fam->psfaces[i]!=NULL ) + if ( !DumpPostscriptFont(fam->psfaces[i]) ) + fprintf( stderr, "Failed to write resource file for PostScript %s\n", face->fontname ); + + for ( i=ncnt=tcnt=0; i<98; ++i ) { + for ( face=fam->faces[i]; face!=NULL; face=face->next ) + ++ncnt; + if ( fam->ttffaces[i]!=NULL ) + ++tcnt; + } + + if ( ncnt==0 && tcnt==0 ) +return; + + strcpy(filename,fam->familyname); + strcat(filename,".fam"); + strcat(filename,output_format==of_dfont?".dfont": + output_format==of_macbin?".bin": + ".rsrc"); + res = fopen(filename,"w"); + if ( res==NULL ) { + fprintf( stderr, "Failed to open output file %s\n", filename ); +return; + } + WriteDummyHeaders(res); + + memset( resources, 0, sizeof(resources)); + memset( fonds, 0, sizeof(fonds)); + npos = tpos = fpos = 0; + if ( ncnt!=0 ) { + resources[0].tag = CHR('N','F','N','T'); + resources[0].res = calloc(ncnt+1,sizeof(struct resource)); + for ( i=ncnt=tcnt=0; i<96; ++i ) { + for ( face=fam->faces[i]; face!=NULL; face=face->next ) { + resources[0].res[ncnt].pos = BDFToResource(res,face); + resources[0].res[ncnt].flags = 0x00; /* NFNTs generally have flags of 0 */ + resources[0].res[ncnt].id = fam->id+ncnt; + ++ncnt; + } + } + tpos = fpos = 1; + } + if ( tcnt!=0 ) { + resources[tpos].tag = CHR('s','f','n','t'); + resources[tpos].res = calloc(tcnt+1,sizeof(struct resource)); + for ( i=tcnt=0; i<96; ++i ) { + if ( fam->ttffaces[i]!=NULL ) { + resources[tpos].res[tcnt].pos = TTFToResource(res,fam->ttffaces[i]); + resources[tpos].res[tcnt].flags = 0x00; /* sfnts generally have resource flags 0x20 */ + resources[tpos].res[tcnt].id = fam->id+tcnt; + ++tcnt; + } + } + ++fpos; + } + + resources[fpos].tag = CHR('F','O','N','D'); + resources[fpos].res = fonds; + fonds[0].pos = FamilyToFOND(res,fam); + fonds[0].flags = 0x00; /* I've seen FONDs with resource flags 0, 0x20, 0x60 */ + fonds[0].id = fam->id; + fonds[0].name = fam->familyname; + + DumpResourceMap(res,resources); + + if ( output_format==of_macbin ) { + header.macfilename = NULL; + header.binfilename = filename; + /* Fontographer uses the old suitcase format for both bitmaps and ttf */ + header.type = CHR('F','F','I','L'); + header.creator = CHR('D','M','O','V'); + DumpMacBinaryHeader(res,&header); + } + ret = !ferror(res); + if ( fclose(res)==-1 || ret == 0 ) + fprintf( stderr, "Failed to write resource file for family %s\n", fam->familyname ); +} + +int main( int argc, char **argv) { + Family *families; + + families = SortByFamily(ParseArgs(argc, argv)); + for ( ; families!=NULL; families=families->next ) + DumpFamily(families); + +return( 0 ); +} @@ -0,0 +1,140 @@ +/* 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> /* for NULL */ +#include <stdlib.h> /* for free */ +#include <limits.h> + +#define CHR(ch1,ch2,ch3,ch4) (((ch1)<<24)|((ch2)<<16)|((ch3)<<8)|(ch4)) +#define true 1 +#define false 0 + +#define forever for (;;) + +#if INT_MAX==2147483647 +typedef int int32; +typedef unsigned int uint32; +#else +typedef long int32; +typedef unsigned long uint32; +#endif +/* I don't know of any systems where the following are not true */ +typedef short int16; +typedef unsigned short uint16; +typedef signed char int8; +typedef unsigned char uint8; + +enum style_flags { sf_bold = 1, sf_italic = 2, sf_underline = 4, sf_outline = 8, + sf_shadow = 0x10, sf_condense = 0x20, sf_extend = 0x40 }; +enum psstyle_flags { psf_bold = 1, psf_italic = 2, psf_outline = 4, + psf_shadow = 0x8, psf_condense = 0x10, psf_extend = 0x20 }; + +typedef struct face { + char *filename; + enum face_type { ft_bdf, ft_ps, ft_ttf } type; /* ttf will include otf */ + char *fontname; + char *family; + int16 style; + int16 psstyle; + int size; + int fixed; + short metrics[256]; /* Not computed until NFNT resource dumped, TTF knows once names are read, PS never knows */ + int id; /* NFNT, sfnt resource ID */ + int ascent, descent, linegap; + struct face *next; + int xmin, ymin, xmax, ymax; /* Bounding box for a 1em font (fixed 4.12 format) */ +} Face; + +typedef struct family { + char *familyname; + int id; /* FOND resource ID */ + int fixed; + int ascent, descent, linegap, maxwidth; + Face *faces[96]; + Face *ttffaces[96]; + Face *psfaces[48]; + struct family *next; +} Family; + +struct resource { + uint32 pos; + uint8 flags; + uint16 id; + char *name; + uint32 nameloc; + uint32 nameptloc; +}; + +struct resourcetype { + uint32 tag; + struct resource *res; + uint32 resloc; +}; + +struct macbinaryheader { + char *macfilename; + char *binfilename; /* if macfilename is null and this is set we will figure out macfilename by removing .bin */ + uint32 type; + uint32 creator; +}; + +struct macfont { + short fRectWidth; + short fRectHeight; + short ascent; + short descent; + short nDescent; + short leading; + short kernMax; + short firstChar; + short lastChar; + short fontType; + short rowWords; + short owTLoc; + uint16 widmax; + Face *face; + unsigned short *widths; + short *lbearings; + unsigned short *locs; + unsigned short **rows; + unsigned short *idealwidths; /* For the fond */ +}; + +extern int getushort(FILE *f); +extern long getlong(FILE *f); +extern void putshort(int val, FILE *f); +extern void putlong(long val, FILE *f); + +/* Postscript */ +extern int PSGetNames(Face *face); +extern struct resource *PSToResources(FILE *res,Face *face); +/* TrueType */ +extern int TTFGetNames(Face *face); +extern long TTFToResource(FILE *res,Face *face); +/* bdf */ +extern int BDFGetNames(Face *face); +extern long BDFToResource(FILE *res,Face *face); diff --git a/ufondbdf.c b/ufondbdf.c new file mode 100644 index 0000000..8c357b6 --- /dev/null +++ b/ufondbdf.c @@ -0,0 +1,449 @@ +/* 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 <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <ctype.h> +#include "ufond.h" + +/* Process bdf files to turn them into NFNT resources */ + +struct bdffont { + char **header; + char ***chars; + int charmax; + char *fontname; + int size; + Face *face; +}; + +int BDFGetNames(Face *face) { + /* Get the font and family names by reading the fontfile */ + FILE *bdf = fopen( face->filename, "r" ); + char buffer[512]; + char *pt; + + if ( bdf==NULL ) { + fprintf( stderr, "Can't open %s for reading\n", face->filename ); +return(false); + } + if ( fgets(buffer,sizeof(buffer),bdf)==NULL || strncmp(buffer,"STARTFONT ",10)!=0 ) { + fprintf( stderr, "Hmm, %s doesn't look like a bdf font", face->filename ); + fclose(bdf); +return( false ); + } + buffer[0]='\0'; + while ( fgets(buffer,sizeof(buffer),bdf)!=NULL ) { + if ( strncmp(buffer,"CHARS ",6)==0 ) + /* No more meta info */ + break; + if ( strncmp(buffer,"FAMILY_NAME \"",13)==0 ) { + pt = strchr(buffer+13,'"'); + if ( pt!=NULL ) { + *pt = '\0'; + face->family = strdup(buffer+13); + } + } else if ( strncmp(buffer,"PIXEL_SIZE ",11)==0 ) { + face->size = strtol(buffer+11,NULL,10); + /* It is tempting to use the bounding box value rather than the size */ + /* that way we don't have to do any clipping, but it gives the wrong */ + /* result. */ + } else if ( strncmp(buffer,"FONTBOUNDINGBOX ",16)==0 ) { + int w,h,lb,ds; + if ( sscanf(buffer, "FONTBOUNDINGBOX %d %d %d %d", &w, &h, &lb, &ds)==4 ) { + face->xmin = lb; + face->ymin = ds; + face->xmax = lb+w; + face->ymax = ds+h; + } + } else if ( strncmp(buffer,"FONT_ASCENT ",12)==0 ) { + face->ascent = strtol(buffer+12,NULL,10); + } else if ( strncmp(buffer,"FONT_DESCENT ",13)==0 ) { + face->descent = strtol(buffer+13,NULL,10); + } else if ( strncmp(buffer,"SLANT \"",7)==0 ) { + if ( buffer[7]=='I' || buffer[7]=='O' ) + face->style |= sf_italic; + } else if ( strncmp(buffer,"WEIGHT_NAME \"",13)==0 ) { + if ( strstr(buffer+13,"Bold")!=NULL || strstr(buffer+13,"BOLD")!=NULL || + strstr(buffer+13,"Gras")!=NULL || strstr(buffer+13,"Fett")!=NULL || + strstr(buffer+13,"Black")!=NULL || strstr(buffer+13,"Heavy")!=NULL ) + face->style |= sf_bold; + } else if ( strncmp(buffer,"SETWIDTH_NAME \"",15)==0 ) { + if ( strstr(buffer+15,"Condense")!=NULL ) + face->style |= sf_condense; + else if ( strstr(buffer+15,"Extend")!=NULL || strstr(buffer+15,"Expand")!=NULL ) + face->style |= sf_extend; + } else if ( strncmp(buffer,"SPACING \"",9)==0 ) { + if ( buffer[9]=='M' ) + face->fixed = true; + } + } + fclose(bdf); + if ( face->size==0 ) face->size = face->ascent+face->descent; + if ( face->family==NULL || face->size==0 ) { + fprintf( stderr, "Hmm, %s does not contain all the needed meta data\n", face->filename ); +return( false ); + } + if ( face->ascent==0 ) { + if ( face->descent!=0 ) face->ascent = face->size-face->descent; + else face->ascent = (8*face->size+5)/10; + } + if ( face->descent == 0 ) face->descent = face->size-face->ascent; +return( true ); +} + +static void FreeBdfFont(struct bdffont *font) { + char **l; + int i; + + if ( font!=NULL ) { + for ( i=0; i<font->charmax; ++i ) if ( font->chars[i]!=NULL ) { + l = font->chars[i]; + while ( *l ) free( *l++ ); + free(font->chars[i]); + } + free(font->chars); + l = font->header; + while ( *l ) free( *l++ ); + free( font->header ); + if ( font->fontname ) + free( font->fontname ); + free( font ); + } +} + +#define MAX_WIDTH 200 + +static char **SlurpChar(FILE *bdffile,char *buffer, int size, char *terminator, int *val) { + static char **list=NULL; + static int tot=0; + int i=0, j, enc= -1; + char **ret; + + for (;;) { + if ( i>=tot ) { + if ( list==NULL ) list = malloc((tot=60)*sizeof(char *)); + else list = realloc(list,(tot*=2)*sizeof(char *)); + for ( j=i; j<tot; ++j ) + list[j] = malloc(MAX_WIDTH+1); + } + strcpy(list[i++],buffer); + if ( strstr(buffer,"ENCODING")==buffer ) + sscanf(buffer,"ENCODING %d", &enc); + if ( strstr(buffer,terminator)==buffer ) + break; + if ( fgets(buffer,size,bdffile)==NULL ) + break; + } + + j=i; + if ( j<7 ) j=7; /* Later we just assume that we've got space in the array */ + ret = malloc((j+1)*sizeof(char *)); + for ( j=0; j<i; ++j ) + ret[j] = strdup(list[j]); + while ( j<7 ) + ret[j++] = strdup(""); + ret[i]=NULL; + *val = enc; +return( ret ); +} + +static struct bdffont *SlurpFont(Face *face) { + FILE *bdffile = fopen(face->filename,"r"); + struct bdffont *bdffont; + char buffer[MAX_WIDTH+1]; + char **chr; + int i, enc, last_enc= -1; + + if ( bdffile==NULL ) { + fprintf( stderr, "Can't open %s\n", face->filename ); +return( NULL ); + } + bdffont = calloc(1,sizeof(*bdffont)); + bdffont->face = face; + + fgets(buffer,sizeof(buffer),bdffile); + bdffont->header = SlurpChar(bdffile,buffer, sizeof(buffer), "ENDPROPERTIES", &enc); + fgets(buffer,sizeof(buffer),bdffile); + + fgets(buffer,sizeof(buffer),bdffile); + while ( strcmp(buffer,"ENDFONT\n")!=0 ) { + chr = SlurpChar(bdffile,buffer, sizeof(buffer), "ENDCHAR", &enc); + if ( enc!=-1 ) { + if ( enc>bdffont->charmax ) { + int new = enc+256; + if ( bdffont->charmax==0 ) bdffont->chars = malloc(new*sizeof(char **)); + else bdffont->chars = realloc(bdffont->chars,new*sizeof(char **)); + for ( i=bdffont->charmax; i<new; ++i ) + bdffont->chars[i] = NULL; + bdffont->charmax = new; + } + bdffont->chars[enc] = chr; + last_enc = enc; + } + if ( fgets(buffer,sizeof(buffer),bdffile)==NULL ) + break; + } +return( bdffont ); +} + +static void ParseBdfHeader(struct macfont *macfont, struct bdffont *bdf) { + int h=10,w=10,lb=0,ds=0, i; + + for ( i=0; bdf->header[i]!=NULL; ++i ) + if ( sscanf(bdf->header[i], "FONTBOUNDINGBOX %d %d %d %d", &w, &h, &lb, &ds)==4 ) + break; + macfont->fRectWidth = w; + macfont->fRectHeight = macfont->face->size; + macfont->ascent = macfont->face->ascent; + macfont->descent = macfont->face->descent; + macfont->nDescent = -macfont->face->descent; + macfont->leading = 0; + macfont->kernMax = lb; + macfont->firstChar = 0; + macfont->lastChar = 0xff; + macfont->fontType = macfont->face->fixed?0xb000:0x9000; +} + +static int ParseCharWidths(struct macfont *macfont,int ch,char **chlist,int loc) { + int pwidth=0, swidth=0, gwidth=0, lb=0; + + sscanf(chlist[2],"SWIDTH %d", &swidth ); + sscanf(chlist[3],"DWIDTH %d", &pwidth ); + sscanf(chlist[4],"BBX %d %*d %d", &gwidth, &lb ); + + macfont->widths[ch] = pwidth; + macfont->lbearings[ch] = lb; + macfont->face->metrics[ch] = (((long) swidth<<12)+500)/1000; + macfont->locs[ch] = loc; +return( loc + gwidth ); +} + +static void ProcessLBearings(struct macfont *macfont) { + int i, lb=256, wmax=0; + + for ( i=0; i<255; ++i ) { + if ( macfont->widths[i]!=0xffff && macfont->lbearings[i]<lb ) + lb = macfont->lbearings[i]; + if ( macfont->widths[i]!=0xffff && macfont->widths[i]>wmax ) + wmax = macfont->widths[i]; + } + macfont->kernMax = lb; + macfont->widmax = wmax; + + for ( i=0; i<255; ++i ) { + if ( macfont->widths[i]!=0xffff ) + macfont->widths[i] |= (macfont->lbearings[i]-lb)<<8; + } + + /* These seem to be magic, don't know why */ + macfont->widths[0] = 0; + macfont->widths['\t'] = 6; + macfont->widths['\r'] = 0; +} + +static void ParseRow(struct macfont *macfont,int ch,int row, char *hexbits) { + int loc = macfont->locs[ch], bits=macfont->locs[ch+1]-loc; + unsigned short word; + + if ( row>=macfont->fRectHeight || row<0 ) +return; + + while ( *hexbits!='\0' && bits>0 ) { + if ( isdigit(*hexbits)) word = (*hexbits-'0')<<12; + else if ( *hexbits>='a' && *hexbits<='f' ) word = (*hexbits-'a'+10)<<12; + else if ( *hexbits>='A' && *hexbits<='F' ) word = (*hexbits-'A'+10)<<12; + else word = 0; + ++hexbits; + if ( isdigit(*hexbits)) word |= (*hexbits-'0')<<8; + else if ( *hexbits>='a' && *hexbits<='f' ) word |= (*hexbits-'a'+10)<<8; + else if ( *hexbits>='A' && *hexbits<='F' ) word |= (*hexbits-'A'+10)<<8; + else --hexbits; + ++hexbits; + if ( isdigit(*hexbits)) word |= (*hexbits-'0')<<4; + else if ( *hexbits>='a' && *hexbits<='f' ) word |= (*hexbits-'a'+10)<<4; + else if ( *hexbits>='A' && *hexbits<='F' ) word |= (*hexbits-'A'+10)<<4; + else --hexbits; + ++hexbits; + if ( isdigit(*hexbits)) word |= (*hexbits-'0'); + else if ( *hexbits>='a' && *hexbits<='f' ) word |= (*hexbits-'a'+10); + else if ( *hexbits>='A' && *hexbits<='F' ) word |= (*hexbits-'A'+10); + else --hexbits; + ++hexbits; + if ( (loc&15)==0 ) + macfont->rows[row][loc>>4] = word; + else { + macfont->rows[row][loc>>4] |= (word>>(loc&15)); + if ( bits-(16-(loc&15))<=0 ) + break; + macfont->rows[row][(loc>>4)+1] = (word<<(16-(loc&15))); + } + loc += 16; + bits -= 16; + } +} + +static void ParseBitmap(struct macfont *macfont,int ch,char **chlist) { + int height, descent, ascent,off,i; + + sscanf(chlist[4],"BBX %*d %d %*d %d", &height, &descent ); + ascent = height+descent; + off = macfont->ascent-ascent; + for ( i=0; i<height; ++i ) + ParseRow(macfont,ch,i+off,chlist[i+6]); +} + +static void DummyUpFakeBitmap(struct macfont *macfont,int ch) { + /* Create a vertical line for the implicit char displayed for missing characters */ + int loc = macfont->locs[ch], lw = (loc>>4), lb= (1<<(15-(loc&15))); + int i; + + for ( i=0; i<macfont->fRectHeight; ++i ) + macfont->rows[i][lw] |= lb; +} + +static struct macfont *CvtBdfToNfnt(struct bdffont *bdf,Face *face) { + struct macfont *macfont; + int i, loc, ch; + + if ( bdf==NULL ) +return( NULL ); + macfont = calloc(sizeof(struct macfont),sizeof(char)); + macfont->face = face; + macfont->widths = calloc(258,sizeof(short)); + macfont->lbearings = calloc(258,sizeof(short)); + macfont->locs = calloc(258,sizeof(short)); + ParseBdfHeader(macfont,bdf); + macfont->rows = malloc(macfont->fRectHeight*sizeof(char *)); + + loc = 0; + for ( i=0; i<256; ++i ) { + ch = i; + if ( ch<bdf->charmax && bdf->chars[ch]!=NULL ) + loc = ParseCharWidths(macfont,i,bdf->chars[ch],loc); + else { + macfont->widths[i] = -1; + macfont->locs[i] = loc; + } + } + macfont->locs[i] = loc; /* Char for unused letters */ + macfont->widths[i]=3; + macfont->face->metrics[i]=(3<<12)/macfont->fRectHeight; + macfont->lbearings[i]=1; + macfont->locs[i+1] = ++loc; /* one beyond, gives size to last character */ + macfont->widths[i+1]=-1; + + macfont->rowWords = (loc+15)/16; + for ( i=0; i<macfont->fRectHeight; ++i ) + macfont->rows[i] = calloc(macfont->rowWords,sizeof(short)); + + for ( i=0; i<256; ++i ) { + ch = i; + if ( ch<bdf->charmax && bdf->chars[ch]!=NULL ) + ParseBitmap(macfont,i,bdf->chars[ch]); + } + DummyUpFakeBitmap(macfont,i); + + ProcessLBearings(macfont); +return( macfont ); +} + +static struct macfont *ProcessBdfFile(Face *face) { + struct bdffont *bdf = SlurpFont(face); + struct macfont *macfont = CvtBdfToNfnt(bdf,face); + FreeBdfFont(bdf); +return( macfont ); +} + +static void FreeMacFont(struct macfont *macfont) { + int i; + + for ( i=0; i<macfont->fRectHeight; ++i ) + free(macfont->rows[i]); + free(macfont->rows); + free(macfont->lbearings); + free(macfont->widths); + free(macfont->locs); + free(macfont); +} + +static long DumpMacFont(FILE *resfile, struct macfont *macfont) { + int size, i,j; + long here; + + size = 13*sizeof(short) + + macfont->fRectHeight*macfont->rowWords*sizeof(short) + + 258*sizeof(short) + + 258*sizeof(short); + macfont->owTLoc = (size- 258*sizeof(short)- (8*sizeof(short)))/ + /* Offset to owTLoc itself*/ + sizeof(short); + + here = ftell(resfile); + putlong(0,resfile); /* Resources start with a size field */ + putshort(macfont->fontType,resfile); + putshort(macfont->firstChar,resfile); + putshort(macfont->lastChar,resfile); + putshort(macfont->widmax,resfile); + putshort(macfont->kernMax,resfile); + putshort(macfont->nDescent,resfile); + putshort(macfont->fRectWidth,resfile); + putshort(macfont->fRectHeight,resfile); + putshort(macfont->owTLoc,resfile); + putshort(macfont->ascent,resfile); + putshort(macfont->descent,resfile); + putshort(macfont->leading,resfile); + putshort(macfont->rowWords,resfile); + for ( i=0; i<macfont->fRectHeight; ++i ) { + for ( j=0; j<macfont->rowWords; ++j ) + putshort( macfont->rows[i][j],resfile ); + } + for ( i=0; i<258; ++i ) + putshort(macfont->locs[i],resfile); + for ( i=0; i<258; ++i ) + putshort(macfont->widths[i],resfile); + + if ( size!=ftell(resfile)-here-4 ) + printf( "IE: expected %d found %d\n", size, ftell(resfile)-here-4 ); + size = ftell(resfile)-here-4; + fseek(resfile,here,SEEK_SET); + putlong(size,resfile); + fseek(resfile,0,SEEK_END); +return( here ); +} + +long BDFToResource(FILE *res,Face *face) { + struct macfont *macfont = ProcessBdfFile(face); + long ret; + if ( macfont==NULL ) +return( 0 ); + ret = DumpMacFont(res, macfont); + FreeMacFont(macfont); +return( ret ); +} diff --git a/ufondpfb.c b/ufondpfb.c new file mode 100644 index 0000000..10adb51 --- /dev/null +++ b/ufondpfb.c @@ -0,0 +1,177 @@ +/* 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 <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include "ufond.h" + +/* Process postscript files to make them useable on the mac */ +/* this involves almost no work, because all the hard stuff is done on the bitmap */ + +static long getpfblong(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|(ch2<<8)|(ch3<<16)|(ch4<<24) ); +} + +int PSGetNames(Face *face) { + /* Get the font and family names by reading the fontfile */ + FILE *pf = fopen( face->filename, "r" ); + char buffer[512]; + int ch; + char *pt, *npt; + + if ( pf==NULL ) { + fprintf( stderr, "Can't open %s for reading\n", face->filename ); +return(false); + } + ch = getc(pf); + if ( ch==0x80 ) { /* skip over the pfb header */ + getc(pf); getc(pf); getc(pf); getc(pf); getc(pf); + } else { + ungetc(ch,pf); + fprintf( stderr, "Hmm, %s doesn't look like a pfb font,\nif it's a pfa just convert it to pfb and try again.\n", face->filename ); + fclose(pf); +return( false ); + } + buffer[0]='\0'; + fgets(buffer,sizeof(buffer),pf); + if ( buffer[0]!='%' || buffer[1]!='!' ) { + fprintf( stderr, "%s does not look like a postscript font\n", face->fontname); + fclose(pf); +return( false ); + } + + while ( fgets(buffer,sizeof(buffer),pf)!=NULL ) { + if ( (pt=strstr(buffer,"/FamilyName"))!=NULL ) { + pt += strlen("/FamilyName"); + while ( *pt==' ' ) ++pt; + if ( *pt=='(' ) ++pt; + /* don't deal with the full complexities of strings, just look for*/ + /* the final ) and assume we've got normal chars, no nested parens*/ + for ( npt=pt; *npt!=')' && *npt!='\0'; ++npt ); + *npt = '\0'; + face->family = strdup(pt); + if ( face->fontname!=NULL ) + break; + } else if ( (pt=strstr(buffer,"/FontName"))!=NULL ) { + pt += strlen("/FontName"); + while ( *pt==' ' ) ++pt; + if ( *pt=='/' ) ++pt; + for ( npt=pt; *npt!=' ' && *npt!='\0'; ++npt ); + *npt = '\0'; + face->fontname = strdup(pt); + if ( face->family!=NULL ) + break; + } + } + fclose(pf); + if ( face->fontname==NULL && face->family!=NULL ) + face->fontname = strdup(face->family); + if ( face->fontname!=NULL ) { + if ( strstr(face->fontname,"Bold")!=NULL ) { + face->style |= sf_bold; + face->psstyle |= psf_bold; + } + if ( strstr(face->fontname,"Italic")!=NULL || strstr(face->fontname,"Oblique")!=NULL ) { + face->style |= sf_italic; + face->psstyle |= psf_italic; + } + if ( strstr(face->fontname,"Outline")!=NULL ) { + face->style |= sf_outline; + face->psstyle |= psf_outline; + } + if ( strstr(face->fontname,"Shadow")!=NULL ) { + face->style |= sf_shadow; + face->psstyle |= psf_shadow; + } + if ( strstr(face->fontname,"Condense")!=NULL ) { + face->style |= sf_condense; + face->psstyle |= psf_condense; + } + if ( strstr(face->fontname,"Extend")!=NULL ) { + face->style |= sf_extend; + face->psstyle |= psf_extend; + } + } +return( face->fontname!=NULL ); +} + +struct resource *PSToResources(FILE *res,Face *face) { + /* split the font up into as many small resources as we need and return */ + /* an array pointing to the start of each */ + struct stat statb; + int cnt, type, len, i; + struct resource *resstarts; + FILE *pf; + + stat(face->filename,&statb); + cnt = 3*(statb.st_size+0x800)/(0x800-2)+1; /* should be (usually) a vast over estimate */ + resstarts = calloc(cnt+1,sizeof(struct resource)); + + pf = fopen(face->filename,"r"); + cnt = 0; + forever { + if ( getc(pf)!=0x80 ) { + fprintf( stderr, "Missing pfb section head in %s\n", face->fontname ); + fclose(pf); +return( NULL ); + } + type = getc(pf); + if ( type==3 ) { + resstarts[cnt].id = 501+cnt; /* 501 appears to be magic */ + resstarts[cnt++].pos = ftell(res); + putlong(2,res); /* length */ + putc(5,res); /* eof mark */ + putc(0,res); + break; + } + len = getpfblong(pf); + while ( len>0 ) { + int ilen = len; + if ( ilen>0x800-2 ) + ilen = 0x800-2; + len -= ilen; + resstarts[cnt].id = 501+cnt; + resstarts[cnt++].pos = ftell(res); + putlong(ilen+2,res); /* length */ + putc(type,res); /* section type mark */ + putc(0,res); + for ( i=0; i<ilen; ++i ) + putc(getc(pf),res); + } + } + fclose(pf); + resstarts[cnt].pos = 0; +return( resstarts ); +} diff --git a/ufondttf.c b/ufondttf.c new file mode 100644 index 0000000..052408c --- /dev/null +++ b/ufondttf.c @@ -0,0 +1,271 @@ +/* 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 <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include "ufond.h" + +struct ttfinfo { + long cmap_start; + long head_start; + long hhea_start; + long hmtx_start; + long maxp_start; + long name_start; + long post_start; + int max_glyph; + int glyphs[256]; /* Glyph ids of the first 256 encoding entries */ + int emsize; + int macstyle; + int longmtx; + int isfixed; + short metrics[256]; + char *fontname, *familyname; +}; + +static char *ReadUnicode(FILE *ttf,long pos, int len) { + /* len is in bytes, not unicode-chars */ + char *str = malloc(len/2+1), *pt = str; + int ch; + long here = ftell(ttf); + fseek(ttf,pos,SEEK_SET); + while ( len>0 ) { + ch = getushort(ttf); + if ( ch>=' ' && ch<127 ) + *pt++ = ch; + len -= 2; + } + *pt = '\0'; + fseek(ttf,here,SEEK_SET); +return( str ); +} + +static char *Read1Byte(FILE *ttf,long pos, int len) { + char *str = malloc(len+1), *pt = str; + int ch; + long here = ftell(ttf); + fseek(ttf,pos,SEEK_SET); + while ( len>0 ) { + ch = getc(ttf); + if ( ch>=' ' && ch<127 ) + *pt++ = ch; + --len; + } + *pt = '\0'; + fseek(ttf,here,SEEK_SET); +return( str ); +} + +int TTFGetNames(Face *face) { + /* Get a bunch of info including the font and family names */ + FILE *ttf = fopen( face->filename, "r" ); + int ch1, ch2, ch3, ch4; + struct ttfinfo info; + int i, cnt, tag; + int platform, specific, offset, format, len, lang, name, stroff; + long strbase; + char *str; + + if ( ttf==NULL ) { + fprintf( stderr, "Can't open %s for reading\n", face->filename ); +return(false); + } + ch1 = getc(ttf); + ch2 = getc(ttf); + ch3 = getc(ttf); + ch4 = getc(ttf); + if (!(( ch1==0 && ch2==1 && ch3==0 && ch4==0 ) || + (ch1=='O' && ch2=='T' && ch3=='T' && ch4=='O') || + (ch1=='t' && ch2=='r' && ch3=='u' && ch4=='e')) ) { + fprintf( stderr, "Hmm, %s doesn't look like a true or open type font.\n", face->filename ); + fclose(ttf); +return( false ); + } + memset(&info,0,sizeof(info)); + + cnt = getushort(ttf); + /* searchRange = */ getushort(ttf); + /* entrySelector = */ getushort(ttf); + /* rangeshift = */ getushort(ttf); + + for ( i=0; i<cnt; ++i ) { + tag = getlong(ttf); + /*checksum = */getlong(ttf); + offset = getlong(ttf); + /*length = */getlong(ttf); +#ifdef DEBUG + printf( "%c%c%c%c\n", tag>>24, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff ); +#endif + switch ( tag ) { + case CHR('c','m','a','p'): + info.cmap_start = offset; + break; + case CHR('h','e','a','d'): + info.head_start = offset; + break; + case CHR('h','h','e','a'): + info.hhea_start = offset; + break; + case CHR('h','m','t','x'): + info.hmtx_start = offset; + break; + case CHR('m','a','x','p'): + info.maxp_start = offset; + break; + case CHR('n','a','m','e'): + info.name_start = offset; + break; + case CHR('p','o','s','t'): + info.post_start = offset; + break; + } + } + if ( info.cmap_start==0 || info.head_start==0 || info.hhea_start==0 || + info.hmtx_start==0 || info.maxp_start==0 || info.name_start==0 ) { + fprintf( stderr, "Hmm, %s is missing some required tables. I can't deal with it.\n", face->filename ); + fclose(ttf); +return( false ); + } + + if ( info.post_start ) { + fseek(ttf,info.post_start+12,SEEK_SET); + info.isfixed = getlong(ttf); + } + fseek(ttf,info.maxp_start+4,SEEK_SET); + info.max_glyph = getushort(ttf); + fseek(ttf,info.head_start+18,SEEK_SET); + info.emsize = getushort(ttf); + fseek(ttf,info.head_start+36,SEEK_SET); + face->xmin = getushort(ttf); + face->ymin = getushort(ttf); + face->xmax = getushort(ttf); + face->ymax = getushort(ttf); + info.macstyle = getushort(ttf); + fseek(ttf,info.hhea_start+4,SEEK_SET); + face->ascent = getushort(ttf); + face->descent = -getushort(ttf); + face->linegap = getushort(ttf); + fseek(ttf,info.hhea_start+34,SEEK_SET); + info.longmtx = getushort(ttf); + + if ( face->ascent+face->descent!=info.emsize ) { + face->ascent = .8*info.emsize; + face->descent = info.emsize-face->ascent; + } + + /* We need to get an encoding vector so we'll know what glyphs go to */ + /* what encodings. We need this so we can read in the metrics info */ + /* we need that so we can fill in the width table of the FOND */ + fseek(ttf,info.cmap_start+2,SEEK_SET); + cnt = getushort(ttf); + for ( i=0; i<cnt; ++i ) { + platform = getushort(ttf); + specific = getushort(ttf); + offset = getlong(ttf); + if ( platform==1 && ( specific!=1 && specific!=2 && specific!=3 && specific!=25 )) + break; /* Search for a single byte encoding */ + } + fseek(ttf,info.cmap_start+offset,SEEK_SET); + format = getushort(ttf); + len = getushort(ttf); + if ( i==cnt || format!=0 ) { + fprintf( stderr, "%s has a more complicated encoding vector than I am prepared to deal with\n", face->filename ); + fclose(ttf); +return( false ); + } + /*language = */ getushort(ttf); + for ( i=0; i<256; ++i ) + info.glyphs[i] = getc(ttf); + + for ( i=0; i<256; ++i ) { + int k = info.glyphs[i]; + if ( k>=info.longmtx ) + k = info.longmtx-1; + fseek(ttf,info.hmtx_start+k*4,SEEK_SET); + info.metrics[i] = getushort(ttf); + } + + fseek(ttf,info.name_start+2,SEEK_SET); + cnt = getushort(ttf); + strbase = getushort(ttf)+info.name_start; + for ( i=0; i<cnt; ++i ) { + platform = getushort(ttf); + specific = getushort(ttf); + lang = getushort(ttf); + name = getushort(ttf); + len = getushort(ttf); + stroff = getushort(ttf); + if ( name==1 /* Family */ || name==6 /* Postscript name */ ) { + if (( platform==3 && specific==1 && (lang&0xff)==9 ) || + ( platform==0 /* any specific, any lang */ ) ) + str = ReadUnicode(ttf, strbase+stroff,len); + else if ( platform==1 && specific==0 && lang==0 ) + str = Read1Byte(ttf, strbase+stroff,len); + if ( name==1 ) + info.familyname = str; + else + info.fontname = str; + } + } + + fclose(ttf); + + if ( info.fontname==NULL && info.familyname!=NULL ) + info.fontname = strdup(info.familyname); + else if ( info.fontname==NULL ) { + fprintf( stderr, "%s has no font name.\n", face->filename ); +return( false ); + } + + face->fontname = info.fontname; + face->family = info.familyname; + face->style = info.macstyle; + face->size = 0; + face->fixed = info.isfixed; + for ( i=0; i<256; ++i ) + face->metrics[i] = (info.metrics[i]<<12)/info.emsize; +return( true ); +} + +long TTFToResource(FILE *res,Face *face) { + /* Just put the ttf(otf) file into a resource */ + struct stat statb; + int ch; + FILE *ttf; + long here = ftell(res); + + stat(face->filename,&statb); + putlong(statb.st_size,res); + + ttf = fopen(face->filename,"r"); + while ( (ch=getc(ttf))!=EOF ) + putc(ch,res); + fclose(ttf); +return( here ); +} |