summaryrefslogtreecommitdiff
path: root/Build/source/texk/xdv2pdf/T1Wrap.m
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/xdv2pdf/T1Wrap.m')
-rw-r--r--Build/source/texk/xdv2pdf/T1Wrap.m746
1 files changed, 746 insertions, 0 deletions
diff --git a/Build/source/texk/xdv2pdf/T1Wrap.m b/Build/source/texk/xdv2pdf/T1Wrap.m
new file mode 100644
index 00000000000..b982eabe81f
--- /dev/null
+++ b/Build/source/texk/xdv2pdf/T1Wrap.m
@@ -0,0 +1,746 @@
+#import <Foundation/Foundation.h>
+//#import <ATS/ATS.h> // you need ApplicationServices.framework
+
+#import "SimplePSInterpreter.h"
+
+#import <unistd.h> // for getopt()
+
+#include "config.h"
+
+static inline UInt16
+SWAP16(UInt16 v)
+{
+#ifdef WORDS_BIGENDIAN
+ return v;
+#else
+ return (v >> 8) | (v << 8);
+#endif
+}
+
+static inline UInt32
+SWAP32(UInt32 v)
+{
+#ifdef WORDS_BIGENDIAN
+ return v;
+#else
+ return (v >> 24) | ((v >> 8) & 0x0000FF00) | ((v << 8) & 0x00FF0000) | (v << 24);
+#endif
+}
+
+static NSString *T1WrapExceptionName = @"T1WrapException";
+
+/* typ1 Table */
+enum {
+ typ1TableTag = 0x54595031 // 'TYP1'
+};
+
+typedef struct {
+ FourCharCode version;
+ UInt16 flags;
+ UInt16 glyphCount;
+ UInt32 totalLength;
+ UInt32 asciiLength;
+ UInt32 binaryLength;
+ SInt32 subrMaxLength;
+} typ1Header;
+
+/* HFMX Table */
+enum {
+ HFMXTableTag = 0x48464D58 // 'HFMX'
+};
+
+typedef struct {
+ Fixed Version;
+ SInt16 Ascent;
+ SInt16 Descent;
+ SInt16 LineGap;
+ SInt16 CaretSlopeRise;
+ SInt16 CaretSlopeRun;
+ SInt16 CaretOffset;
+} HFMXHeader;
+
+// format 6 subheader structure
+struct sfntCMapSubHeader6 {
+ UInt16 format;
+ UInt16 length;
+ UInt16 languageID; /* base-1 */
+ UInt16 firstCode;
+ UInt16 entryCount;
+};
+typedef struct sfntCMapSubHeader6 sfntCMapSubHeader6;
+enum {
+ sizeof_sfntCMapSubHeader6 = 10
+};
+
+
+/* post Table */
+enum {
+ postTableTag = 0x706F7374 // 'post'
+};
+
+struct sfntPostHeader {
+ Fixed version; /* format version number */
+ Fixed italicAngle; /* italic angle in degrees */
+ SInt16 underlinePosition; /* underline position (in FUnits) */
+ SInt16 underlineThickness; /* underline thickness (in FUnits) */
+ UInt16 isFixedPitch; /* font is monospaced */
+ UInt16 reserved;
+ UInt32 minMemType42; /* Minimum memory usage when a TrueType font is downloaded */
+ UInt32 maxMemType42; /* Maximum memory usage when a TrueType font is downloaded as a Type 1 font */
+ UInt32 minMemType1; /* Minimum memory usage when a TrueType font is downloaded as a Type 1 font */
+ UInt32 maxMemType1; /* Maximum memory usage when a TrueType font is downloaded as a Type 1 font */
+// UInt16 glyphCount; /* this is for version 2.0 post header */
+};
+
+typedef struct sfntPostHeader sfntPostHeader;
+enum {
+ sizeof_sfntPostHeader = 32
+};
+/* BUG?: I do not know if it is a bug but it happens that sizeof(sfntPostHeader) = 36 !?! */
+/* No, it's not a bug, that would be due to long-alignment of the structure.
+ But the glyphCount field is not strictly part of the 'post' table header,
+ it is part of the format-specific data for 'post' format 2.0.
+ So I've removed that, and it is handled separately below. */
+
+unsigned long getPfbLong(const unsigned char *ptr)
+{
+ unsigned long c0 = ptr[0];
+ unsigned long c1 = ptr[1];
+ unsigned long c2 = ptr[2];
+ unsigned long c3 = ptr[3];
+
+ return (c0 | (c1 << 8) | (c2 <<16) | (c3<<24));
+}
+
+
+
+NSData *decrypt(const unsigned char* inbuf, unsigned int insize)
+{
+ NSMutableData *result = [NSMutableData dataWithLength:insize];
+ unsigned char *outbuf = [result mutableBytes];
+
+ unsigned short R = 55665; /* key */
+ unsigned short c1 = 52845;
+ unsigned short c2 = 22719;
+ unsigned long counter;
+
+ for(counter = 0; counter < insize; counter++) {
+ outbuf[counter] = (inbuf[counter] ^ (R>>8));
+ R = (inbuf[counter] + R) * c1 + c2;
+ }
+
+ return result;
+}
+
+/* provide strnstr here because it's not available on 10.2 */
+char *strnstr(const char *big, const char *little, size_t bigLen)
+{
+ unsigned littleLen = strlen(little);
+ if (littleLen > bigLen)
+ return 0;
+
+ unsigned n;
+ for (n = bigLen - littleLen + 1; n-- > 0; ++big) {
+ if (memcmp(big, little, littleLen) == 0)
+ return (char*)big;
+ }
+
+ return 0;
+}
+
+NSData *digestPfbForSfnt(NSString *pfbPath, typ1Header *t1h)
+{
+ static char *target1 = "currentfile eexec";
+ static char *target2 = "0000000000000000000000000000000000000000000000000000000000000000";
+ static char *target3 = "mark currentfile closefile";
+ /* despite what the "Type 1 sfnt" document says, these don't appear to be necessary */
+ static char *replacement1 = "\nsystemdict begin\n";
+ static char *replacement2 = "\nend\n";
+
+
+ NSData *pfbData = [NSData dataWithContentsOfFile:pfbPath];
+ if (!pfbData)
+ [NSException raise:T1WrapExceptionName format:@"Cannot read file:%@",pfbPath];
+
+ NSMutableData *outData = [NSMutableData dataWithCapacity:[pfbData length]];
+ if (!outData)
+ [NSException raise:T1WrapExceptionName format:@"Cannot allocate workspace"];
+
+ const char *pfbBytes = [pfbData bytes];
+ unsigned long chunkSize;
+ unsigned long asciiSize = 0, binSize = 0;
+ while (1) {
+ if ((unsigned char)pfbBytes[0] != 0x80 )
+ [NSException raise:T1WrapExceptionName format:@"Wrong PFB format"];
+
+ if (pfbBytes[1] == 0x01)
+ {
+ // read the ASCII chunk (before and after binary chunks)
+ chunkSize = getPfbLong(pfbBytes+2);
+
+ const char * p0 = pfbBytes+6;
+ char * p1, *p2;
+ p1 = strnstr(p0,target1,chunkSize);
+ if (p1) {
+ if (p1 != p0+chunkSize-strlen(target1)-1)
+ [NSException raise:T1WrapExceptionName format:@"I'm confused..."];
+ [outData appendBytes:p0 length:p1-p0];
+ [outData appendBytes:replacement1 length:strlen(replacement1)];
+ asciiSize = p1-p0+strlen(replacement1);
+ } else {
+ p2 = strnstr(p0,target2,chunkSize);
+ if (p2) {
+#if 0
+ /* the following test if false with: '\r00000...' */
+ if (p2 != p0)
+ [NSException raise:T1WrapExceptionName format:@"I'm confused..."];
+#endif
+ ;
+ //[outData appendBytes:p0 length:chunkSize];
+ }
+ else
+ [NSException raise:T1WrapExceptionName format:@"Cannot find begin/end of encrypted portion"];
+ }
+ }
+ else if (pfbBytes[1] == 0x02)
+ {
+ // read the binary chunk
+ chunkSize = getPfbLong(pfbBytes+2);
+ NSData *decryptedData = decrypt(pfbBytes+6,chunkSize);
+ const char *p0 = [decryptedData bytes];
+ const char *p1 = p0+chunkSize-(int)strlen(target3)-1;
+ if (strncmp(target3,p1,strlen(target3))!=0)
+ [NSException raise:T1WrapExceptionName format:@"Cannot find internal end of encrypted portion"];
+
+ [outData appendBytes:p0+4 length:p1-p0-4]; /* +4 is to skip YNDY */
+ [outData appendBytes:replacement2 length:strlen(replacement2)];
+ binSize = p1-p0-4+strlen(replacement2);
+ }
+ else if (pfbBytes[1] == 0x03)
+ break;
+ else
+ [NSException raise:T1WrapExceptionName format:@"Wrong PFB format"];
+ pfbBytes += chunkSize+6;
+ } // while (1)
+
+ // fill the table header
+
+ t1h->version = SWAP32(0x00010000);
+ t1h->flags = SWAP16(0);
+ t1h->glyphCount = SWAP16(130); /* number of elements of CharStrings array/dict */
+ t1h->totalLength = SWAP32(asciiSize+binSize);
+ t1h->asciiLength = SWAP32(asciiSize);
+ t1h->binaryLength = SWAP32(binSize);
+ t1h->subrMaxLength = SWAP32(-1);
+
+ // pad the data to long boundary
+ {
+ unsigned x = [outData length]%4;
+ unsigned long y = 0;
+ if (x) [outData appendBytes:&y length:4-x];
+ }
+
+ return outData;
+}
+
+
+
+void fillTag(FourCharCode *tag, char *str)
+{
+ char * p = (char*)tag;
+ p[0] = str[0];
+ p[1] = str[1];
+ p[2] = str[2];
+ p[3] = str[3];
+}
+
+unsigned long calcTableChecksum(register unsigned long *table, unsigned long length)
+{
+ register unsigned long sum = 0L;
+ register unsigned long *endptr = table+((length+3) & ~3) / sizeof(long);
+ while (table < endptr)
+ sum += SWAP32(*table++);
+ return sum;
+}
+
+unsigned four_align(unsigned a) { return ((a+3)/4)*4; }
+
+
+NSData *wrapPfb(NSString *fontPath, BOOL omitType1Data)
+{
+
+ unsigned totalSize = 0;
+
+ // needed tables: HFMX, TYP1, cmap, fdsc, name
+ // we add also a post table (suggested by Jonathan Kew)
+
+
+ // TYP1 table
+
+ typ1Header *t1h = calloc(1,sizeof(typ1Header));
+ NSData *type1Data = digestPfbForSfnt(fontPath,t1h);
+
+ totalSize += sizeof(typ1Header) + [type1Data length];
+
+ // parse pfb
+
+ NSDictionary *fontDir = nil;
+
+ {
+ SimplePSInterpreter *psi = [[SimplePSInterpreter alloc] init];
+// [psi doString:[NSString stringWithCString:[type1Data bytes] length:[type1Data length]]];
+ [psi doString:[[NSString alloc] initWithData:type1Data encoding:NSMacOSRomanStringEncoding]];
+ fontDir = [[[psi fontDir] retain] autorelease];
+ [psi release];
+ }
+
+ if ([fontDir count]!=1)
+ [NSException raise:T1WrapExceptionName format:@"expecting only one font definition in pfb (found many or none)"];
+
+ NSDictionary *fontDict = (NSDictionary*)[[fontDir allValues] objectAtIndex:0];
+ NSDictionary *fontInfo = [fontDict objectForKey:@"/FontInfo"];
+ NSDictionary *charStrings = [fontDict objectForKey:@"/CharStrings"];
+
+ int glyphCount = [charStrings count]-1; // subtract 1 for the [KEY ORDER] key added by the pseudo-interpreter
+
+ t1h->glyphCount = SWAP16(glyphCount);
+
+ NSMutableData *type1TableData = [NSMutableData dataWithCapacity:sizeof(typ1Header)+[type1Data length]];
+ [type1TableData appendBytes:t1h length:sizeof(typ1Header)];
+ [type1TableData appendData:type1Data];
+
+ // create glyphNames array
+
+ NSMutableArray *glyphNames = [NSMutableArray arrayWithCapacity:glyphCount];
+
+ {
+ NSEnumerator *en = [[charStrings objectForKey:@"[KEY ORDER]"] objectEnumerator];
+ NSString *name;
+ [glyphNames addObject:@"/.notdef"];
+ while ((name = [en nextObject]))
+ {
+ if (![name isEqualToString:@"/.notdef"]) [glyphNames addObject:name];
+ }
+ }
+
+ // HFMX table
+
+ unsigned HFMXTableSize = sizeof(HFMXHeader);
+ HFMXHeader *hh = calloc(1,HFMXTableSize);
+
+ hh->Version = SWAP32(0x00010000);
+ hh->Ascent = SWAP16([(NSNumber*)[(NSArray*)[(NSArray*)[fontDict objectForKey:@"/FontBBox"] objectAtIndex:1] objectAtIndex:3] intValue]);
+ hh->Descent = SWAP16(-[(NSNumber*)[(NSArray*)[(NSArray*)[fontDict objectForKey:@"/FontBBox"] objectAtIndex:1] objectAtIndex:1] intValue]);
+ hh->LineGap = SWAP16(0);
+ hh->CaretSlopeRise = SWAP16(1);
+ hh->CaretSlopeRun = SWAP16(0);
+ hh->CaretOffset = SWAP16(0);
+
+ totalSize += HFMXTableSize;
+
+ // name table
+
+ NSMutableArray *nameIdArray = [NSMutableArray arrayWithCapacity:10];
+ NSMutableArray *stringsArray = [NSMutableArray arrayWithCapacity:10];
+ NSString *string;
+
+ [nameIdArray addObject:[NSNumber numberWithInt:kFontPostscriptName]];
+ string = [fontDict objectForKey:@"/FontName"];
+ if ([string characterAtIndex:0] == '/') string = [string substringFromIndex:1];
+ [stringsArray addObject:string];
+
+ string = [fontInfo objectForKey:@"/FullName"];
+ if (string) {
+ [nameIdArray addObject:[NSNumber numberWithInt:kFontFullName]];
+ [stringsArray addObject:string];
+ }
+
+ string = [fontInfo objectForKey:@"/FamilyName"];
+ if (string) {
+ [nameIdArray addObject:[NSNumber numberWithInt:kFontFamilyName]];
+ [stringsArray addObject:string];
+ }
+
+ string = [fontInfo objectForKey:@"/Copyright"];
+ if (string) {
+ [nameIdArray addObject:[NSNumber numberWithInt:kFontCopyrightName]];
+ [stringsArray addObject:string];
+ }
+
+ string = [fontInfo objectForKey:@"/Notice"];
+ if (string) {
+ [nameIdArray addObject:[NSNumber numberWithInt:([fontDict objectForKey:@"/Copyright"] ? kFontCopyrightName : kFontDescriptionName)]];
+ [stringsArray addObject:string];
+ }
+
+ string = [fontInfo objectForKey:@"/version"];
+ if (string) {
+ [nameIdArray addObject:[NSNumber numberWithInt:kFontVersionName]];
+ [stringsArray addObject:string];
+ }
+
+
+
+ NSMutableData *nameRecs = [NSMutableData dataWithCapacity:100];
+ NSMutableData *nameStrings = [NSMutableData dataWithCapacity:100];
+
+ sfntNameRecord rec;
+ int nameRecords = 0;
+ rec.platformID = SWAP16(kFontMacintoshPlatform);
+ rec.scriptID = SWAP16(kFontRomanScript);
+ rec.languageID = SWAP16(kFontEnglishLanguage);
+
+ NSEnumerator *nameIdEn = [nameIdArray objectEnumerator];
+ NSEnumerator *stringsEn = [stringsArray objectEnumerator];
+ NSNumber *nameIdObj;
+ while ((nameIdObj = [nameIdEn nextObject]) && (string = [stringsEn nextObject]))
+ {
+ rec.nameID = SWAP16([nameIdObj intValue]);
+ rec.length = SWAP16([string length]);
+ rec.offset = SWAP16([nameStrings length]);
+ [nameStrings appendBytes:[string cString] length:[string cStringLength]];
+ [nameRecs appendBytes:&rec length:sizeof(sfntNameRecord)];
+ nameRecords++;
+ }
+
+ unsigned nameTableSize = four_align( sizeof_sfntNameHeader+
+ [nameRecs length]+
+ [nameStrings length]);
+
+
+ sfntNameHeader nameh;
+ nameh.format = SWAP16(0);
+ nameh.count = SWAP16(nameRecords);
+ nameh.stringOffset = SWAP16(sizeof_sfntNameHeader + [nameRecs length]);
+
+ NSMutableData *nameTable = [NSMutableData dataWithCapacity:nameTableSize];
+ [nameTable appendBytes:&nameh length:sizeof_sfntNameHeader];
+ [nameTable appendData:nameRecs];
+ [nameTable appendData:nameStrings];
+ [nameTable increaseLengthBy:nameTableSize-[nameTable length]]; // pad with zeros
+
+ totalSize += nameTableSize;
+
+ // fdsc table
+
+ unsigned fdscTableSize = four_align(sizeof_sfntDescriptorHeader+sizeof(sfntFontDescriptor)*2);
+ sfntDescriptorHeader *dh = calloc(1,fdscTableSize);
+ dh->version = SWAP32(0x00010000);
+ dh->descriptorCount = SWAP32(2);
+ /* FIXME: could try to infer better values from known font names like "bold", "condensed", etc */
+ dh->descriptor[0].name = SWAP32(0x77647468); /* wdth */
+ dh->descriptor[0].value = SWAP32(0x00010000); /* +1.0 */
+ dh->descriptor[1].name = SWAP32(0x77676874); /* wght */
+ dh->descriptor[1].value = SWAP32(0x00010000); /* +1.0 */
+
+ totalSize += fdscTableSize;
+
+ // cmap table
+ NSArray *encoding = [(NSArray*)[fontDict objectForKey:@"/Encoding"] objectAtIndex:1];
+ unsigned encsize = [encoding count];
+
+ unsigned cmapTableSize;
+ sfntCMapHeader *cmaph;
+
+ if (glyphCount > 256) {
+ // more than 256 glyphs: use format 6 cmap
+ cmapTableSize = four_align(sizeof_sfntCMapHeader+sizeof_sfntCMapEncoding+sizeof_sfntCMapSubHeader6+256*2);
+ cmaph = calloc(1,cmapTableSize);
+ sfntCMapSubHeader6 *cmapsh = (sfntCMapSubHeader6*)(((char*)cmaph)+12);
+ UInt16 *glyphIndexArray = (UInt16*)(((char*)cmaph)+12+sizeof_sfntCMapSubHeader6);
+ cmaph->version = 0;
+ cmaph->numTables = SWAP16(1);
+ cmaph->encoding[0].platformID = SWAP16(kFontMacintoshPlatform);
+ cmaph->encoding[0].scriptID = SWAP16(kFontRomanScript);
+ cmaph->encoding[0].offset = SWAP32(12);
+ cmapsh->format = SWAP16(6);
+ cmapsh->length = SWAP16(10+256*2);
+ cmapsh->languageID = SWAP16(0);
+ cmapsh->firstCode = SWAP16(0);
+ cmapsh->entryCount = SWAP16(256);
+ {
+ int i;
+ NSString *name;
+ for (i=0; i<256; i++) {
+ if (i < encsize) {
+ name = [encoding objectAtIndex:i];
+ if ([name isEqualToString:@" <NULL> "]) name = @"/.notdef";
+ } else name = @"/.notdef";
+ glyphIndexArray[i] = SWAP16([glyphNames indexOfObject:name]);
+ }
+ }
+ } else {
+ // less than 256 glyphs: use format 0 cmap
+ cmapTableSize = four_align(sizeof_sfntCMapHeader+sizeof_sfntCMapEncoding+sizeof_sfntCMapSubHeader+256);
+ cmaph = calloc(1,cmapTableSize);
+ sfntCMapSubHeader *cmapsh = (sfntCMapSubHeader*)(((char*)cmaph)+12);
+ UInt8 *glyphIndexArray = (UInt8*)(((char*)cmaph)+12+sizeof_sfntCMapSubHeader);
+ cmaph->version = 0;
+ cmaph->numTables = SWAP16(1);
+ cmaph->encoding[0].platformID = SWAP16(kFontMacintoshPlatform);
+ cmaph->encoding[0].scriptID = SWAP16(kFontRomanScript);
+ cmaph->encoding[0].offset = SWAP32(12);
+ cmapsh->format = SWAP16(0);
+ cmapsh->length = SWAP16(6+256);
+ cmapsh->languageID = SWAP16(0);
+ {
+ int i;
+ NSString *name;
+ for (i=0; i<256; i++) {
+ if (i < encsize) {
+ name = [encoding objectAtIndex:i];
+ if ([name isEqualToString:@" <NULL> "]) name = @"/.notdef";
+ } else name = @"/.notdef";
+ glyphIndexArray[i] = [glyphNames indexOfObject:name];
+ }
+ }
+ }
+
+ totalSize += cmapTableSize;
+
+ // post table
+
+ NSArray *appleGlyphNames = [NSArray arrayWithObjects:
+ @".notdef",@".null",@"nonmarkingreturn",@"space",@"exclam",@"quotedbl",@"numbersign",@"dollar",
+ @"percent",@"ampersand",@"quotesingle",@"parenleft",@"parenright",@"asterisk",@"plus",@"comma",
+ @"hyphen",@"period",@"slash",@"zero",@"one",@"two",@"three",@"four",
+ @"five",@"six",@"seven",@"eight",@"nine",@"colon",@"semicolon",@"less",
+ @"equal",@"greater",@"question",@"at",@"A",@"B",@"C",@"D",
+ @"E",@"F",@"G",@"H",@"I",@"J",@"K",@"L",
+ @"M",@"N",@"O",@"P",@"Q",@"R",@"S",@"T",
+ @"U",@"V",@"W",@"X",@"Y",@"Z",@"bracketleft",@"backslash",
+ @"bracketright",@"asciicircum",@"underscore",@"grave",@"a",@"b",@"c",@"d",
+ @"e",@"f",@"g",@"h",@"i",@"j",@"k",@"l",
+ @"m",@"n",@"o",@"p",@"q",@"r",@"s",@"t",
+ @"u",@"v",@"w",@"x",@"y",@"z",@"braceleft",@"bar",
+ @"braceright",@"asciitilde",@"Adieresis",@"Aring",@"Ccedilla",@"Eacute",@"Ntilde",@"Odieresis",
+ @"Udieresis",@"aacute",@"agrave",@"acircumflex",@"adieresis",@"atilde",@"aring",@"ccedilla",
+ @"eacute",@"egrave",@"ecircumflex",@"edieresis",@"iacute",@"igrave",@"icircumflex",@"idieresis",
+ @"ntilde",@"oacute",@"ograve",@"ocircumflex",@"odieresis",@"otilde",@"uacute",@"ugrave",
+ @"ucircumflex",@"udieresis",@"dagger",@"degree",@"cent",@"sterling",@"section",@"bullet",
+ @"paragraph",@"germandbls",@"registered",@"copyright",@"trademark",@"acute",@"dieresis",@"notequal",
+ @"AE",@"Oslash",@"infinity",@"plusminus",@"lessequal",@"greaterequal",@"yen",@"mu",
+ @"partialdiff",@"summation",@"product",@"pi",@"integral",@"ordfeminine",@"ordmasculine",@"Omega",
+ @"ae",@"oslash",@"questiondown",@"exclamdown",@"logicalnot",@"radical",@"florin",@"approxequal",
+ @"Delta",@"guillemotleft",@"guillemotright",@"ellipsis",@"nonbreakingspace",@"Agrave",@"Atilde",@"Otilde",
+ @"OE",@"oe",@"endash",@"emdash",@"quotedblleft",@"quotedblright",@"quoteleft",@"quoteright",
+ @"divide",@"lozenge",@"ydieresis",@"Ydieresis",@"fraction",@"currency",@"guilsinglleft",@"guilsinglright",
+ @"fi",@"fl",@"daggerdbl",@"periodcentered",@"quotesinglbase",@"quotedblbase",@"perthousand",@"Acircumflex",
+ @"Ecircumflex",@"Aacute",@"Edieresis",@"Egrave",@"Iacute",@"Icircumflex",@"Idieresis",@"Igrave",
+ @"Oacute",@"Ocircumflex",@"apple",@"Ograve",@"Uacute",@"Ucircumflex",@"Ugrave",@"dotlessi",
+ @"circumflex",@"tilde",@"macron",@"breve",@"dotaccent",@"ring",@"cedilla",@"hungarumlaut",
+ @"ogonek",@"caron",@"Lslash",@"lslash",@"Scaron",@"scaron",@"Zcaron",@"zcaron",
+ @"brokenbar",@"Eth",@"eth",@"Yacute",@"yacute",@"Thorn",@"thorn",@"minus",
+ @"multiply",@"onesuperior",@"twosuperior",@"threesuperior",@"onehalf",@"onequarter",@"threequarters",@"franc",
+ @"Gbreve",@"gbreve",@"Idotaccent",@"Scedilla",@"scedilla",@"Cacute",@"cacute",@"Ccaron",
+ @"ccaron",@"dcroat",
+ nil];
+
+
+ NSMutableData *postTableStrings = [NSMutableData dataWithCapacity:100];
+ UInt16 *postTableGlyphArray = calloc([glyphNames count],sizeof(UInt16));
+ UInt16 nGlyphs = 0;
+ {
+ NSEnumerator *gnEn = [glyphNames objectEnumerator];
+ int nStrings = 0;
+ NSString *string;
+ while ((string = [gnEn nextObject])) {
+ if ([string characterAtIndex:0]=='/') string = [string substringFromIndex:1];
+ unsigned index = [appleGlyphNames indexOfObject:string];
+ if (index != NSNotFound) {
+ postTableGlyphArray[nGlyphs] = SWAP16(index);
+ } else {
+ postTableGlyphArray[nGlyphs] = SWAP16(258+(nStrings++));
+ char strLength = [string cStringLength];
+ [postTableStrings appendBytes:&strLength length:1];
+ [postTableStrings appendBytes:[string cString] length:strLength];
+ }
+ nGlyphs++;
+ }
+ }
+
+
+ sfntPostHeader ph;
+ ph.version = SWAP32(0x00020000);
+ ph.italicAngle = SWAP32(0);
+ ph.underlinePosition = SWAP16([(NSNumber*)[fontInfo objectForKey:@"/UnderlinePosition"] intValue]);
+ ph.underlineThickness = SWAP16([(NSNumber*)[fontInfo objectForKey:@"/UnderlineThickness"] intValue]);
+ ph.isFixedPitch = SWAP16(([(NSNumber*)[fontInfo objectForKey:@"/isFixedPitch"] intValue] ? 1 : 0));
+ ph.reserved = 0;
+ ph.minMemType42 = 0;
+ ph.maxMemType42 = 0;
+ ph.minMemType1 = 0;
+ ph.maxMemType1 = 0;
+// ph.glyphCount = nGlyphs;
+
+ NSMutableData *postTable = [NSMutableData dataWithCapacity:100];
+ [postTable appendBytes:&ph length:sizeof_sfntPostHeader];
+ nGlyphs = SWAP16(nGlyphs);
+ [postTable appendBytes:&nGlyphs length:sizeof(UInt16)];
+ nGlyphs = SWAP16(nGlyphs);
+ [postTable appendBytes:postTableGlyphArray length:sizeof(UInt16)*nGlyphs];
+ [postTable appendData:postTableStrings];
+ [postTable increaseLengthBy:(4-([postTable length] % 4)) % 4]; // pad with zeros
+ free(postTableGlyphArray);
+
+
+ // sfnt directory
+
+ unsigned sfntDirectorySize = sizeof_sfntDirectory+sizeof(sfntDirectoryEntry)*6;
+ sfntDirectory *dir = calloc(1,sfntDirectorySize);
+ fillTag(&(dir->format),"typ1");
+ dir->numOffsets = SWAP16(6); /* number of tables */
+ dir->searchRange = SWAP16(4*16); /* (max pow 2 <= numOffsets)*16 */
+ dir->entrySelector = SWAP16(2);/* log2(max pow 2 <= numOffsets) */
+ dir->rangeShift = SWAP16(32); /* numOffsets*16-searchRange*/
+
+ unsigned totalOffset = sfntDirectorySize;
+
+ /* table directory entries must be sorted in ascending order by tag,
+ but we want to put the TYP1 table last because we optionally omit the data
+ (but still include the table header) */
+
+ dir->table[0].tableTag = SWAP32(HFMXTableTag);
+ dir->table[0].checkSum = SWAP32(calcTableChecksum((void*)hh,HFMXTableSize));
+ dir->table[0].offset = SWAP32(totalOffset);
+ dir->table[0].length = SWAP32(HFMXTableSize);
+ totalOffset += SWAP32(dir->table[0].length);
+
+ dir->table[2].tableTag = SWAP32(cmapFontTableTag);
+ dir->table[2].checkSum = SWAP32(calcTableChecksum((void*)cmaph,cmapTableSize));
+ dir->table[2].offset = SWAP32(totalOffset);
+ dir->table[2].length = SWAP32(cmapTableSize);
+ totalOffset += SWAP32(dir->table[2].length);
+
+ dir->table[3].tableTag = SWAP32(descriptorFontTableTag);
+ dir->table[3].checkSum = SWAP32(calcTableChecksum((void*)dh,fdscTableSize));
+ dir->table[3].offset = SWAP32(totalOffset);
+ dir->table[3].length = SWAP32(fdscTableSize);
+ totalOffset += SWAP32(dir->table[3].length);
+
+ dir->table[4].tableTag = SWAP32(nameFontTableTag);
+ dir->table[4].checkSum = SWAP32(calcTableChecksum((void*)[nameTable bytes], [nameTable length]));
+ dir->table[4].offset = SWAP32(totalOffset);
+ dir->table[4].length = SWAP32([nameTable length]);
+ totalOffset += SWAP32(dir->table[4].length);
+
+ dir->table[5].tableTag = SWAP32(postTableTag);
+ dir->table[5].checkSum = SWAP32(calcTableChecksum((void*)[postTable bytes],[postTable length]));
+ dir->table[5].offset = SWAP32(totalOffset);
+ dir->table[5].length = SWAP32([postTable length]);
+ totalOffset += SWAP32(dir->table[5].length);
+
+ dir->table[1].tableTag = SWAP32(typ1TableTag);
+ dir->table[1].checkSum = SWAP32(calcTableChecksum((void*)[type1TableData bytes],[type1TableData length]));
+ dir->table[1].offset = SWAP32(totalOffset);
+ dir->table[1].length = SWAP32([type1TableData length]);
+// totalOffset += dir->table[0].length;
+
+ NSMutableData *sfntData = [NSMutableData dataWithCapacity:totalSize];
+ [sfntData appendBytes:dir length:sfntDirectorySize];
+
+ /* append all the tables, matching the order of directory entry creation so that the offsets will be right */
+ [sfntData appendBytes:hh length:HFMXTableSize];
+ [sfntData appendBytes:cmaph length:cmapTableSize];
+ [sfntData appendBytes:dh length:fdscTableSize];
+ [sfntData appendData:nameTable];
+ [sfntData appendData:postTable];
+ if (omitType1Data)
+ [sfntData appendBytes:t1h length:sizeof(typ1Header)];
+ else
+ [sfntData appendData:type1TableData];
+ free(t1h);
+
+ free(dir);
+
+ free(cmaph); free(dh); free(hh);
+
+ return sfntData;
+}
+
+
+void usage(const char* progName)
+{
+ fprintf(stderr, "# usage: %s [-t | -T] pfbFile\n\
+# writes sfnt-wrapped Type 1 font to stdout\n\
+# options:\n\
+# -t omit TYP1 table from sfnt\n\
+# -T only generate TYP1 data\n", progName);
+ exit(1);
+}
+
+int main (int argc, char * const *argv) {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+
+#if 1
+ const char* progName = argv[0];
+ int ch;
+ BOOL omitTyp1 = NO;
+ BOOL onlyTyp1 = NO;
+ while ((ch = getopt(argc, argv, "tT")) != -1)
+ switch (ch) {
+ case 't':
+ omitTyp1 = YES;
+ break;
+ case 'T':
+ onlyTyp1 = YES;
+ break;
+ case '?':
+ default:
+ usage(progName);
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc != 1 || (omitTyp1 && onlyTyp1))
+ usage(progName);
+ NSString *pfbFilename = [NSString stringWithCString:argv[0]];
+ NS_DURING
+ if (onlyTyp1) {
+ typ1Header *t1h = calloc(1,sizeof(typ1Header));
+ NSData *type1Data = digestPfbForSfnt(pfbFilename, t1h);
+ fwrite([type1Data bytes], 1, [type1Data length], stdout);
+ }
+ else {
+ NSData *sfntData = wrapPfb(pfbFilename, omitTyp1);
+ fwrite([sfntData bytes], 1, [sfntData length], stdout);
+ }
+ NS_HANDLER
+ fprintf(stderr,"%s",[[NSString stringWithFormat:@"exception: %@ reason: %@\n",[localException name],[localException reason]] cString]);
+ NS_ENDHANDLER
+// [sfntData writeToFile:@"/Users/mgubi/Desktop/cmr10.sfnt" atomically:NO];
+
+#else
+ NSString *basePath = @"/usr/local/teTeX/share/texmf.tetex/fonts/type1";
+ NSDirectoryEnumerator *direnum = [[NSFileManager defaultManager]
+ enumeratorAtPath:basePath];
+ NSString *pname;
+ NSString *fullname;
+ BOOL fOk = YES;
+
+
+ while ((pname = [direnum nextObject])) {
+ if ([[pname pathExtension] isEqualToString:@"pfb"]) {
+ fullname = [basePath stringByAppendingPathComponent:pname];
+ fprintf(stdout,"testing %s\n",[fullname fileSystemRepresentation]);
+ NS_DURING
+ NSData *sfntData = wrapPfb(fullname);
+ NS_HANDLER
+
+ fOk = NO;
+ fprintf(stderr,"%s",[[NSString stringWithFormat:@"exception: %@ reason: %@",[localException name],[localException reason]] cString]);
+
+ NS_ENDHANDLER
+ }
+ }
+
+
+
+
+#endif
+
+
+
+ [pool release];
+ return 0;
+}
+