summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Williams <gww@silcom.com>2001-12-05 07:55:34 +0000
committerGeorge Williams <gww@silcom.com>2001-12-05 07:55:34 +0000
commit5a3715c05cd1e3f5c362a465bc5f2c6180fbe2be (patch)
treecc992b496635f7ad43df854c5633cc56e0c57fd6
parent5cef931ff57c8bc8259cc97d11a86782f885488e (diff)
First version of ufond
Fixes to fondu First version of showfond
-rw-r--r--LICENSE28
-rw-r--r--Makefile25
-rw-r--r--README16
-rw-r--r--crctab.c142
-rw-r--r--fondu.c20
-rw-r--r--readnfnt.c15
-rw-r--r--showfond.c692
-rw-r--r--ufond.c830
-rw-r--r--ufond.h140
-rw-r--r--ufondbdf.c449
-rw-r--r--ufondpfb.c177
-rw-r--r--ufondttf.c271
12 files changed, 2800 insertions, 5 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e6ec51c
--- /dev/null
+++ b/LICENSE
@@ -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)
diff --git a/README b/README
new file mode 100644
index 0000000..35ad169
--- /dev/null
+++ b/README
@@ -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 */
diff --git a/fondu.c b/fondu.c
index b2e2aa9..8608933 100644
--- a/fondu.c
+++ b/fondu.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 */
diff --git a/readnfnt.c b/readnfnt.c
index 231c90e..caf6285 100644
--- a/readnfnt.c
+++ b/readnfnt.c
@@ -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 );
+}
diff --git a/ufond.c b/ufond.c
new file mode 100644
index 0000000..b2cfe27
--- /dev/null
+++ b/ufond.c
@@ -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 );
+}
diff --git a/ufond.h b/ufond.h
new file mode 100644
index 0000000..a578787
--- /dev/null
+++ b/ufond.h
@@ -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 );
+}