Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/pdf/xpdf/FontFile.cc
diff options
context:
space:
mode:
authorMartin Kretzschmar <mkretzschmar@src.gnome.org>2002-09-18 22:20:42 (GMT)
committer Martin Kretzschmar <mkretzschmar@src.gnome.org>2002-09-18 22:20:42 (GMT)
commit2a393c134fe3fe8eb85bf818cb7ad6ae4396322a (patch)
treeeba8b0dcaba42d799ed8313faee15fb74a5a0cd2 /pdf/xpdf/FontFile.cc
parent7aac8dc8533347e21311b15186e0af82f1b22fd6 (diff)
Synched with Xpdf 1.01
Diffstat (limited to 'pdf/xpdf/FontFile.cc')
-rw-r--r--pdf/xpdf/FontFile.cc3342
1 files changed, 2695 insertions, 647 deletions
diff --git a/pdf/xpdf/FontFile.cc b/pdf/xpdf/FontFile.cc
index 777b56a..ae58547 100644
--- a/pdf/xpdf/FontFile.cc
+++ b/pdf/xpdf/FontFile.cc
@@ -2,7 +2,7 @@
//
// FontFile.cc
//
-// Copyright 1999 Derek B. Noonburg
+// Copyright 1999-2002 Glyph & Cog, LLC
//
//========================================================================
@@ -10,6 +10,7 @@
#pragma implementation
#endif
+#include <aconf.h>
#include <math.h>
#include <stdlib.h>
#include <stddef.h>
@@ -17,18 +18,12 @@
#include <ctype.h>
#include "gmem.h"
#include "Error.h"
+#include "GlobalParams.h"
+#include "CharCodeToUnicode.h"
+#include "FontEncodingTables.h"
#include "FontFile.h"
-#include "StdFontInfo.h"
-#include "CompactFontInfo.h"
-
-//------------------------------------------------------------------------
-
-static Guint getWord(Guchar *ptr, int size);
-static double getNum(Guchar **ptr, GBool *fp);
-static char *getString(int sid, Guchar *stringIdxPtr,
- Guchar *stringStartPtr, int stringOffSize,
- char *buf);
+#include "CompactFontTables.h"
//------------------------------------------------------------------------
@@ -58,34 +53,46 @@ FontFile::~FontFile() {
Type1FontFile::Type1FontFile(char *file, int len) {
char *line, *line1, *p, *p2;
+ GBool haveEncoding;
char buf[256];
char c;
- int n, code, i;
+ int n, code, i, j;
name = NULL;
- encoding = NULL;
- freeEnc = gTrue;
+ encoding = (char **)gmalloc(256 * sizeof(char *));
+ for (i = 0; i < 256; ++i) {
+ encoding[i] = NULL;
+ }
+ haveEncoding = gFalse;
- for (i = 1, line = file; i <= 100 && line < file + len && !encoding; ++i) {
+ for (i = 1, line = file;
+ i <= 100 && line < file + len && !haveEncoding;
+ ++i) {
// get font name
if (!strncmp(line, "/FontName", 9)) {
strncpy(buf, line, 255);
buf[255] = '\0';
if ((p = strchr(buf+9, '/')) &&
- (p = strtok(p+1, " \t\n\r")))
+ (p = strtok(p+1, " \t\n\r"))) {
name = copyString(p);
+ }
line = nextLine(line, file + len);
// get encoding
} else if (!strncmp(line, "/Encoding StandardEncoding def", 30)) {
- encoding = type1StdEncoding.copy();
+ for (j = 0; j < 256; ++j) {
+ if (standardEncoding[j]) {
+ encoding[j] = copyString(standardEncoding[j]);
+ }
+ }
+ haveEncoding = gTrue;
} else if (!strncmp(line, "/Encoding 256 array", 19)) {
- encoding = new FontEncoding();
- for (i = 0; i < 300; ++i) {
+ for (j = 0; j < 300; ++j) {
line1 = nextLine(line, file + len);
- if ((n = line1 - line) > 255)
+ if ((n = line1 - line) > 255) {
n = 255;
+ }
strncpy(buf, line, n);
buf[n] = '\0';
for (p = buf; *p == ' ' || *p == '\t'; ++p) ;
@@ -102,7 +109,7 @@ Type1FontFile::Type1FontFile(char *file, int len) {
++p;
for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ;
*p2 = '\0';
- encoding->addChar(code, copyString(p));
+ encoding[code] = copyString(p);
}
}
}
@@ -115,6 +122,7 @@ Type1FontFile::Type1FontFile(char *file, int len) {
line = line1;
}
//~ check for getinterval/putinterval junk
+ haveEncoding = gTrue;
} else {
line = nextLine(line, file + len);
@@ -123,77 +131,143 @@ Type1FontFile::Type1FontFile(char *file, int len) {
}
Type1FontFile::~Type1FontFile() {
- if (name)
- gfree(name);
- if (encoding && freeEnc)
- delete encoding;
-}
+ int i;
-FontEncoding *Type1FontFile::getEncoding(GBool taken) {
- if (taken)
- freeEnc = gFalse;
- return encoding;
+ if (name) {
+ gfree(name);
+ }
+ for (i = 0; i < 256; ++i) {
+ gfree(encoding[i]);
+ }
+ gfree(encoding);
}
//------------------------------------------------------------------------
// Type1CFontFile
//------------------------------------------------------------------------
-Type1CFontFile::Type1CFontFile(char *file, int len) {
+struct Type1CTopDict {
+ int version;
+ int notice;
+ int copyright;
+ int fullName;
+ int familyName;
+ int weight;
+ int isFixedPitch;
+ double italicAngle;
+ double underlinePosition;
+ double underlineThickness;
+ int paintType;
+ int charstringType;
+ double fontMatrix[6];
+ int uniqueID;
+ double fontBBox[4];
+ double strokeWidth;
+ int charset;
+ int encoding;
+ int charStrings;
+ int privateSize;
+ int privateOffset;
+
+ //----- CIDFont entries
+ int registry;
+ int ordering;
+ int supplement;
+ int fdArrayOffset;
+ int fdSelectOffset;
+};
+
+struct Type1CPrivateDict {
+ GString *dictData;
+ int subrsOffset;
+ double defaultWidthX;
+ GBool defaultWidthXFP;
+ double nominalWidthX;
+ GBool nominalWidthXFP;
+};
+
+Type1CFontFile::Type1CFontFile(char *fileA, int lenA) {
+ Guchar *nameIdxPtr, *idxPtr0, *idxPtr1;
+
+ file = fileA;
+ len = lenA;
+ name = NULL;
+ encoding = NULL;
+
+ // some tools embed Type 1C fonts with an extra whitespace char at
+ // the beginning
+ if (file[0] != '\x01') {
+ ++file;
+ }
+
+ // read header
+ topOffSize = file[3] & 0xff;
+
+ // read name index (first font only)
+ nameIdxPtr = (Guchar *)file + (file[2] & 0xff);
+ idxPtr0 = getIndexValPtr(nameIdxPtr, 0);
+ idxPtr1 = getIndexValPtr(nameIdxPtr, 1);
+ name = new GString((char *)idxPtr0, idxPtr1 - idxPtr0);
+
+ topDictIdxPtr = getIndexEnd(nameIdxPtr);
+ stringIdxPtr = getIndexEnd(topDictIdxPtr);
+ gsubrIdxPtr = getIndexEnd(stringIdxPtr);
+}
+
+Type1CFontFile::~Type1CFontFile() {
+ int i;
+
+ delete name;
+ if (encoding) {
+ for (i = 0; i < 256; ++i) {
+ gfree(encoding[i]);
+ }
+ gfree(encoding);
+ }
+}
+
+char *Type1CFontFile::getName() {
+ return name->getCString();
+}
+
+char **Type1CFontFile::getEncoding() {
+ if (!encoding) {
+ readNameAndEncoding();
+ }
+ return encoding;
+}
+
+void Type1CFontFile::readNameAndEncoding() {
char buf[256];
- Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
- Guchar *stringIdxPtr, *stringStartPtr;
- int topOffSize, idxOffSize, stringOffSize;
- int nFonts, nStrings, nGlyphs;
+ Guchar *idxPtr0, *idxPtr1, *ptr;
+ int nGlyphs;
int nCodes, nRanges, nLeft, nSups;
Gushort *glyphNames;
int charset, enc, charstrings;
- int charsetFormat, encFormat;
+ int encFormat;
int c, sid;
- double op[48];
double x;
GBool isFP;
int key;
- int i, j, n;
+ int i, j;
- name = NULL;
- encoding = NULL;
- freeEnc = gTrue;
-
- // read header
- topPtr = (Guchar *)file + (file[2] & 0xff);
- topOffSize = file[3] & 0xff;
+ encoding = (char **)gmalloc(256 * sizeof(char *));
+ for (i = 0; i < 256; ++i) {
+ encoding[i] = NULL;
+ }
- // read name index (first font only)
- nFonts = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
- idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
- idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
- idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
- if ((n = idxPtr1 - idxPtr0) > 255)
- n = 255;
- strncpy(buf, (char *)idxPtr0, n);
- buf[n] = '\0';
- name = copyString(buf);
- topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
-
- // read top dict index (first font only)
- nFonts = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
- idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
- idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
- idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
- charset = 0;
- enc = 0;
- charstrings = 0;
+ // read top dict (first font only)
+ idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
+ idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
+ charset = enc = charstrings = 0;
i = 0;
- while (idxPtr0 < idxPtr1) {
- if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
- key = *idxPtr0++;
- if (key == 0x0c)
- key = (key << 8) | *idxPtr0++;
+ ptr = idxPtr0;
+ while (ptr < idxPtr1) {
+ if (*ptr <= 27 || *ptr == 31) {
+ key = *ptr++;
+ if (key == 0x0c) {
+ key = (key << 8) | *ptr++;
+ }
if (key == 0x0f) { // charset
charset = (int)op[0];
} else if (key == 0x10) { // encoding
@@ -203,445 +277,130 @@ Type1CFontFile::Type1CFontFile(char *file, int len) {
}
i = 0;
} else {
- x = getNum(&idxPtr0, &isFP);
- if (i < 48)
+ x = getNum(&ptr, &isFP);
+ if (i < 48) {
op[i++] = x;
+ }
}
}
- topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
-
- // read string index
- nStrings = getWord(topPtr, 2);
- stringOffSize = topPtr[2];
- topPtr += 3;
- stringIdxPtr = topPtr;
- stringStartPtr = topPtr + (nStrings + 1) * stringOffSize - 1;
- topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize,
- stringOffSize);
// get number of glyphs from charstrings index
- topPtr = (Guchar *)file + charstrings;
- nGlyphs = getWord(topPtr, 2);
+ nGlyphs = getIndexLen((Guchar *)file + charstrings);
- // read charset
- if (charset == 0) {
- glyphNames = type1CISOAdobeCharset;
- } else if (charset == 1) {
- glyphNames = type1CExpertCharset;
- } else if (charset == 2) {
- glyphNames = type1CExpertSubsetCharset;
- } else {
- glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
- glyphNames[0] = 0;
- topPtr = (Guchar *)file + charset;
- charsetFormat = *topPtr++;
- if (charsetFormat == 0) {
- for (i = 1; i < nGlyphs; ++i) {
- glyphNames[i] = getWord(topPtr, 2);
- topPtr += 2;
- }
- } else if (charsetFormat == 1) {
- i = 1;
- while (i < nGlyphs) {
- c = getWord(topPtr, 2);
- topPtr += 2;
- nLeft = *topPtr++;
- for (j = 0; j <= nLeft; ++j)
- glyphNames[i++] = c++;
- }
- } else if (charsetFormat == 2) {
- i = 1;
- while (i < nGlyphs) {
- c = getWord(topPtr, 2);
- topPtr += 2;
- nLeft = getWord(topPtr, 2);
- topPtr += 2;
- for (j = 0; j <= nLeft; ++j)
- glyphNames[i++] = c++;
- }
- }
- }
+ // read charset (GID -> name mapping)
+ glyphNames = readCharset(charset, nGlyphs);
- // read encoding (glyph -> code mapping)
+ // read encoding (GID -> code mapping)
if (enc == 0) {
- encoding = type1StdEncoding.copy();
+ for (i = 0; i < 256; ++i) {
+ if (standardEncoding[i]) {
+ encoding[i] = copyString(standardEncoding[i]);
+ }
+ }
} else if (enc == 1) {
- encoding = type1ExpertEncoding.copy();
+ for (i = 0; i < 256; ++i) {
+ if (expertEncoding[i]) {
+ encoding[i] = copyString(expertEncoding[i]);
+ }
+ }
} else {
- encoding = new FontEncoding();
- topPtr = (Guchar *)file + enc;
- encFormat = *topPtr++;
+ ptr = (Guchar *)file + enc;
+ encFormat = *ptr++;
if ((encFormat & 0x7f) == 0) {
- nCodes = 1 + *topPtr++;
+ nCodes = 1 + *ptr++;
if (nCodes > nGlyphs) {
nCodes = nGlyphs;
}
for (i = 1; i < nCodes; ++i) {
- c = *topPtr++;
- getString(glyphNames[i], stringIdxPtr, stringStartPtr,
- stringOffSize, buf);
- encoding->addChar(c, copyString(buf));
+ c = *ptr++;
+ encoding[c] = copyString(getString(glyphNames[i], buf));
}
} else if ((encFormat & 0x7f) == 1) {
- nRanges = *topPtr++;
+ nRanges = *ptr++;
nCodes = 1;
for (i = 0; i < nRanges; ++i) {
- c = *topPtr++;
- nLeft = *topPtr++;
+ c = *ptr++;
+ nLeft = *ptr++;
for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
- getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr,
- stringOffSize, buf);
- encoding->addChar(c, copyString(buf));
+ encoding[c] = copyString(getString(glyphNames[nCodes], buf));
++nCodes;
++c;
}
}
}
if (encFormat & 0x80) {
- nSups = *topPtr++;
+ nSups = *ptr++;
for (i = 0; i < nSups; ++i) {
- c = *topPtr++;
- sid = getWord(topPtr, 2);
- topPtr += 2;
- getString(sid, stringIdxPtr, stringStartPtr,
- stringOffSize, buf);
- encoding->addChar(c, copyString(buf));
+ c = *ptr++;
+ sid = getWord(ptr, 2);
+ ptr += 2;
+ encoding[c] = copyString(getString(sid, buf));
}
}
}
- if (charset > 2)
+ if (charset > 2) {
gfree(glyphNames);
-}
-
-Type1CFontFile::~Type1CFontFile() {
- if (name)
- gfree(name);
- if (encoding && freeEnc)
- delete encoding;
-}
-
-FontEncoding *Type1CFontFile::getEncoding(GBool taken) {
- if (taken)
- freeEnc = gFalse;
- return encoding;
-}
-
-static Guint getWord(Guchar *ptr, int size) {
- Guint x;
- int i;
-
- x = 0;
- for (i = 0; i < size; ++i)
- x = (x << 8) + *ptr++;
- return x;
-}
-
-static double getNum(Guchar **ptr, GBool *fp) {
- static char nybChars[16] = "0123456789.ee -";
- int b0, b, nyb0, nyb1;
- double x;
- char buf[65];
- int i;
-
- x = 0;
- *fp = gFalse;
- b0 = (*ptr)[0];
- if (b0 < 28) {
- x = 0;
- } else if (b0 == 28) {
- x = ((*ptr)[1] << 8) + (*ptr)[2];
- *ptr += 3;
- } else if (b0 == 29) {
- x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4];
- *ptr += 5;
- } else if (b0 == 30) {
- *ptr += 1;
- i = 0;
- do {
- b = *(*ptr)++;
- nyb0 = b >> 4;
- nyb1 = b & 0x0f;
- if (nyb0 == 0xf)
- break;
- buf[i++] = nybChars[nyb0];
- if (i == 64)
- break;
- if (nyb0 == 0xc)
- buf[i++] = '-';
- if (i == 64)
- break;
- if (nyb1 == 0xf)
- break;
- buf[i++] = nybChars[nyb1];
- if (i == 64)
- break;
- if (nyb1 == 0xc)
- buf[i++] = '-';
- } while (i < 64);
- buf[i] = '\0';
- x = atof(buf);
- *fp = gTrue;
- } else if (b0 == 31) {
- x = 0;
- } else if (b0 < 247) {
- x = b0 - 139;
- *ptr += 1;
- } else if (b0 < 251) {
- x = ((b0 - 247) << 8) + (*ptr)[1] + 108;
- *ptr += 2;
- } else {
- x = -((b0 - 251) << 8) - (*ptr)[1] - 108;
- *ptr += 2;
}
- return x;
}
-static char *getString(int sid, Guchar *stringIdxPtr,
- Guchar *stringStartPtr, int stringOffSize,
- char *buf) {
- Guchar *idxPtr0, *idxPtr1;
- int len;
-
- if (sid < 391) {
- strcpy(buf, type1CStdStrings[sid]);
- } else {
- sid -= 391;
- idxPtr0 = stringStartPtr + getWord(stringIdxPtr + sid * stringOffSize,
- stringOffSize);
- idxPtr1 = stringStartPtr + getWord(stringIdxPtr + (sid+1) * stringOffSize,
- stringOffSize);
- if ((len = idxPtr1 - idxPtr0) > 255)
- len = 255;
- strncpy(buf, (char *)idxPtr0, len);
- buf[len] = '\0';
- }
- return buf;
-}
-
-//------------------------------------------------------------------------
-// Type1CFontConverter
-//------------------------------------------------------------------------
-
-Type1CFontConverter::Type1CFontConverter(char *file, int len, FILE *out) {
- this->file = file;
- this->len = len;
- this->out = out;
- r1 = 55665;
- line = 0;
-}
-
-Type1CFontConverter::~Type1CFontConverter() {
-}
-
-void Type1CFontConverter::convert() {
- char *fontName;
- struct {
- int version;
- int notice;
- int copyright;
- int fullName;
- int familyName;
- int weight;
- int isFixedPitch;
- double italicAngle;
- double underlinePosition;
- double underlineThickness;
- int paintType;
- int charstringType; //~ ???
- double fontMatrix[6];
- int uniqueID;
- double fontBBox[4];
- double strokeWidth; //~ ???
- int charset;
- int encoding;
- int charStrings;
- int privateSize;
- int privateOffset;
- } dict;
+void Type1CFontFile::convertToType1(FILE *outA) {
+ Type1CTopDict dict;
+ Type1CPrivateDict privateDict;
char buf[256], eBuf[256];
- Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
- Guchar *stringIdxPtr, *stringStartPtr;
- int topOffSize, idxOffSize, stringOffSize;
- int nFonts, nStrings, nGlyphs;
- int nCodes, nRanges, nLeft, nSups;
+ Guchar *idxPtr0, *idxPtr1, *subrsIdxPtr, *charStringsIdxPtr, *ptr;
+ int nGlyphs, nCodes, nRanges, nLeft, nSups;
Gushort *glyphNames;
- int charsetFormat, encFormat;
- int subrsOffset, nSubrs;
- int nCharStrings;
+ int encFormat, nSubrs, nCharStrings;
int c, sid;
- double x;
- GBool isFP;
- int key;
int i, j, n;
- // read header
- topPtr = (Guchar *)file + (file[2] & 0xff);
- topOffSize = file[3] & 0xff;
-
- // read name (first font only)
- nFonts = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
- idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
- idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
- idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
- if ((n = idxPtr1 - idxPtr0) > 255)
- n = 255;
- strncpy(buf, (char *)idxPtr0, n);
- buf[n] = '\0';
- fontName = copyString(buf);
- topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
+ out = outA;
// read top dict (first font only)
- nFonts = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
- idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
- idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
- idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
- dict.version = 0;
- dict.notice = 0;
- dict.copyright = 0;
- dict.fullName = 0;
- dict.familyName = 0;
- dict.weight = 0;
- dict.isFixedPitch = 0;
- dict.italicAngle = 0;
- dict.underlinePosition = -100;
- dict.underlineThickness = 50;
- dict.paintType = 0;
- dict.charstringType = 2;
- dict.fontMatrix[0] = 0.001;
- dict.fontMatrix[1] = 0;
- dict.fontMatrix[2] = 0;
- dict.fontMatrix[3] = 0.001;
- dict.fontMatrix[4] = 0;
- dict.fontMatrix[5] = 0;
- dict.uniqueID = 0;
- dict.fontBBox[0] = 0;
- dict.fontBBox[1] = 0;
- dict.fontBBox[2] = 0;
- dict.fontBBox[3] = 0;
- dict.strokeWidth = 0;
- dict.charset = 0;
- dict.encoding = 0;
- dict.charStrings = 0;
- dict.privateSize = 0;
- dict.privateOffset = 0;
- i = 0;
- while (idxPtr0 < idxPtr1) {
- if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
- key = *idxPtr0++;
- if (key == 0x0c)
- key = (key << 8) | *idxPtr0++;
- switch (key) {
- case 0x0000: dict.version = (int)op[0]; break;
- case 0x0001: dict.notice = (int)op[0]; break;
- case 0x0c00: dict.copyright = (int)op[0]; break;
- case 0x0002: dict.fullName = (int)op[0]; break;
- case 0x0003: dict.familyName = (int)op[0]; break;
- case 0x0004: dict.weight = (int)op[0]; break;
- case 0x0c01: dict.isFixedPitch = (int)op[0]; break;
- case 0x0c02: dict.italicAngle = op[0]; break;
- case 0x0c03: dict.underlinePosition = op[0]; break;
- case 0x0c04: dict.underlineThickness = op[0]; break;
- case 0x0c05: dict.paintType = (int)op[0]; break;
- case 0x0c06: dict.charstringType = (int)op[0]; break;
- case 0x0c07: dict.fontMatrix[0] = op[0];
- dict.fontMatrix[1] = op[1];
- dict.fontMatrix[2] = op[2];
- dict.fontMatrix[3] = op[3];
- dict.fontMatrix[4] = op[4];
- dict.fontMatrix[5] = op[5]; break;
- case 0x000d: dict.uniqueID = (int)op[0]; break;
- case 0x0005: dict.fontBBox[0] = op[0];
- dict.fontBBox[1] = op[1];
- dict.fontBBox[2] = op[2];
- dict.fontBBox[3] = op[3]; break;
- case 0x0c08: dict.strokeWidth = op[0]; break;
- case 0x000f: dict.charset = (int)op[0]; break;
- case 0x0010: dict.encoding = (int)op[0]; break;
- case 0x0011: dict.charStrings = (int)op[0]; break;
- case 0x0012: dict.privateSize = (int)op[0];
- dict.privateOffset = (int)op[1]; break;
- }
- i = 0;
- } else {
- x = getNum(&idxPtr0, &isFP);
- if (i < 48) {
- op[i] = x;
- fp[i++] = isFP;
- }
- }
- }
- topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
-
- // read string index
- nStrings = getWord(topPtr, 2);
- stringOffSize = topPtr[2];
- topPtr += 3;
- stringIdxPtr = topPtr;
- stringStartPtr = topPtr + (nStrings + 1) * stringOffSize - 1;
- topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize,
- stringOffSize);
+ readTopDict(&dict);
-#if 1 //~
// get global subrs
- int nGSubrs;
- int gSubrOffSize;
-
- nGSubrs = getWord(topPtr, 2);
- gSubrOffSize = topPtr[2];
- topPtr += 3;
-#endif
+ //~ ... global subrs are unimplemented
// write header and font dictionary, up to encoding
- fprintf(out, "%%!FontType1-1.0: %s", fontName);
+ fprintf(out, "%%!FontType1-1.0: %s", name->getCString());
if (dict.version != 0) {
- fprintf(out, "%s",
- getString(dict.version, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ fprintf(out, "%s", getString(dict.version, buf));
}
fprintf(out, "\n");
fprintf(out, "11 dict begin\n");
fprintf(out, "/FontInfo 10 dict dup begin\n");
if (dict.version != 0) {
fprintf(out, "/version (%s) readonly def\n",
- getString(dict.version, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.version, buf));
}
if (dict.notice != 0) {
fprintf(out, "/Notice (%s) readonly def\n",
- getString(dict.notice, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.notice, buf));
}
if (dict.copyright != 0) {
fprintf(out, "/Copyright (%s) readonly def\n",
- getString(dict.copyright, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.copyright, buf));
}
if (dict.fullName != 0) {
fprintf(out, "/FullName (%s) readonly def\n",
- getString(dict.fullName, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.fullName, buf));
}
if (dict.familyName != 0) {
fprintf(out, "/FamilyName (%s) readonly def\n",
- getString(dict.familyName, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.familyName, buf));
}
if (dict.weight != 0) {
fprintf(out, "/Weight (%s) readonly def\n",
- getString(dict.weight, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.weight, buf));
}
fprintf(out, "/isFixedPitch %s def\n", dict.isFixedPitch ? "true" : "false");
fprintf(out, "/ItalicAngle %g def\n", dict.italicAngle);
fprintf(out, "/UnderlinePosition %g def\n", dict.underlinePosition);
fprintf(out, "/UnderlineThickness %g def\n", dict.underlineThickness);
fprintf(out, "end readonly def\n");
- fprintf(out, "/FontName /%s def\n", fontName);
+ fprintf(out, "/FontName /%s def\n", name->getCString());
fprintf(out, "/PaintType %d def\n", dict.paintType);
fprintf(out, "/FontType 1 def\n");
fprintf(out, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
@@ -650,52 +409,16 @@ void Type1CFontConverter::convert() {
fprintf(out, "/FontBBox [%g %g %g %g] readonly def\n",
dict.fontBBox[0], dict.fontBBox[1],
dict.fontBBox[2], dict.fontBBox[3]);
+ fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
if (dict.uniqueID != 0) {
fprintf(out, "/UniqueID %d def\n", dict.uniqueID);
}
// get number of glyphs from charstrings index
- topPtr = (Guchar *)file + dict.charStrings;
- nGlyphs = getWord(topPtr, 2);
+ nGlyphs = getIndexLen((Guchar *)file + dict.charStrings);
// read charset
- if (dict.charset == 0) {
- glyphNames = type1CISOAdobeCharset;
- } else if (dict.charset == 1) {
- glyphNames = type1CExpertCharset;
- } else if (dict.charset == 2) {
- glyphNames = type1CExpertSubsetCharset;
- } else {
- glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
- glyphNames[0] = 0;
- topPtr = (Guchar *)file + dict.charset;
- charsetFormat = *topPtr++;
- if (charsetFormat == 0) {
- for (i = 1; i < nGlyphs; ++i) {
- glyphNames[i] = getWord(topPtr, 2);
- topPtr += 2;
- }
- } else if (charsetFormat == 1) {
- i = 1;
- while (i < nGlyphs) {
- c = getWord(topPtr, 2);
- topPtr += 2;
- nLeft = *topPtr++;
- for (j = 0; j <= nLeft; ++j)
- glyphNames[i++] = c++;
- }
- } else if (charsetFormat == 2) {
- i = 1;
- while (i < nGlyphs) {
- c = getWord(topPtr, 2);
- topPtr += 2;
- nLeft = getWord(topPtr, 2);
- topPtr += 2;
- for (j = 0; j <= nLeft; ++j)
- glyphNames[i++] = c++;
- }
- }
- }
+ glyphNames = readCharset(dict.charset, nGlyphs);
// read encoding (glyph -> code mapping), write Type 1 encoding
fprintf(out, "/Encoding ");
@@ -706,54 +429,55 @@ void Type1CFontConverter::convert() {
fprintf(out, "0 1 255 {1 index exch /.notdef put} for\n");
if (dict.encoding == 1) {
for (i = 0; i < 256; ++i) {
- if (type1ExpertEncodingNames[i])
- fprintf(out, "dup %d /%s put\n", i, type1ExpertEncodingNames[i]);
+ if (expertEncoding[i]) {
+ fprintf(out, "dup %d /%s put\n", i, expertEncoding[i]);
+ }
}
} else {
- topPtr = (Guchar *)file + dict.encoding;
- encFormat = *topPtr++;
+ ptr = (Guchar *)file + dict.encoding;
+ encFormat = *ptr++;
if ((encFormat & 0x7f) == 0) {
- nCodes = 1 + *topPtr++;
+ nCodes = 1 + *ptr++;
if (nCodes > nGlyphs) {
nCodes = nGlyphs;
}
for (i = 1; i < nCodes; ++i) {
- c = *topPtr++;
- fprintf(out, "dup %d /%s put\n", c,
- getString(glyphNames[i], stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ c = *ptr++;
+ fprintf(out, "dup %d /%s put\n",
+ c, getString(glyphNames[i], buf));
}
} else if ((encFormat & 0x7f) == 1) {
- nRanges = *topPtr++;
+ nRanges = *ptr++;
nCodes = 1;
for (i = 0; i < nRanges; ++i) {
- c = *topPtr++;
- nLeft = *topPtr++;
+ c = *ptr++;
+ nLeft = *ptr++;
for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
- fprintf(out, "dup %d /%s put\n", c,
- getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ fprintf(out, "dup %d /%s put\n",
+ c, getString(glyphNames[nCodes], buf));
++nCodes;
++c;
}
}
}
if (encFormat & 0x80) {
- nSups = *topPtr++;
+ nSups = *ptr++;
for (i = 0; i < nSups; ++i) {
- c = *topPtr++;
- sid = getWord(topPtr, 2);
- topPtr += 2;
- fprintf(out, "dup %d /%s put\n", c,
- getString(sid, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ c = *ptr++;
+ sid = getWord(ptr, 2);
+ ptr += 2;
+ fprintf(out, "dup %d /%s put\n", c, getString(sid, buf));
}
}
}
fprintf(out, "readonly def\n");
}
fprintf(out, "currentdict end\n");
+
+ // start the binary section
fprintf(out, "currentfile eexec\n");
+ r1 = 55665;
+ line = 0;
// get private dictionary
eexecWrite("\x83\xca\x73\xd5");
@@ -762,173 +486,842 @@ void Type1CFontConverter::convert() {
eexecWrite("/ND {noaccess def} executeonly def\n");
eexecWrite("/NP {noaccess put} executeonly def\n");
eexecWrite("/MinFeature {16 16} ND\n");
- eexecWrite("/password 5839 def\n");
- subrsOffset = 0;
- defaultWidthX = 0;
- nominalWidthX = 0;
- topPtr = (Guchar *)file + dict.privateOffset;
- idxPtr0 = topPtr;
- idxPtr1 = idxPtr0 + dict.privateSize;
+ readPrivateDict(&privateDict, dict.privateOffset, dict.privateSize);
+ eexecWrite(privateDict.dictData->getCString());
+ defaultWidthX = privateDict.defaultWidthX;
+ defaultWidthXFP = privateDict.defaultWidthXFP;
+ nominalWidthX = privateDict.nominalWidthX;
+ nominalWidthXFP = privateDict.nominalWidthXFP;
+
+ // get subrs
+ if (privateDict.subrsOffset != 0) {
+ subrsIdxPtr = (Guchar *)file + dict.privateOffset +
+ privateDict.subrsOffset;
+ nSubrs = getIndexLen(subrsIdxPtr);
+ sprintf(eBuf, "/Subrs %d array\n", nSubrs);
+ eexecWrite(eBuf);
+ idxPtr1 = getIndexValPtr(subrsIdxPtr, 0);
+ for (i = 0; i < nSubrs; ++i) {
+ idxPtr0 = idxPtr1;
+ idxPtr1 = getIndexValPtr(subrsIdxPtr, i+1);
+ n = idxPtr1 - idxPtr0;
+#if 1 //~ Type 2 subrs are unimplemented
+ error(-1, "Unimplemented Type 2 subrs");
+#else
+ sprintf(eBuf, "dup %d %d RD ", i, n);
+ eexecWrite(eBuf);
+ eexecCvtGlyph(idxPtr0, n);
+ eexecWrite(" NP\n");
+#endif
+ }
+ eexecWrite("ND\n");
+ }
+
+ // get CharStrings
+ charStringsIdxPtr = (Guchar *)file + dict.charStrings;
+ nCharStrings = getIndexLen(charStringsIdxPtr);
+ sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings);
+ eexecWrite(eBuf);
+ idxPtr1 = getIndexValPtr(charStringsIdxPtr, 0);
+ for (i = 0; i < nCharStrings; ++i) {
+ idxPtr0 = idxPtr1;
+ idxPtr1 = getIndexValPtr(charStringsIdxPtr, i+1);
+ n = idxPtr1 - idxPtr0;
+ eexecCvtGlyph(getString(glyphNames[i], buf), idxPtr0, n);
+ }
+ eexecWrite("end\n");
+ eexecWrite("end\n");
+ eexecWrite("readonly put\n");
+ eexecWrite("noaccess put\n");
+ eexecWrite("dup /FontName get exch definefont pop\n");
+ eexecWrite("mark currentfile closefile\n");
+
+ // trailer
+ if (line > 0) {
+ fputc('\n', out);
+ }
+ for (i = 0; i < 8; ++i) {
+ fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
+ }
+ fprintf(out, "cleartomark\n");
+
+ // clean up
+ delete privateDict.dictData;
+ if (dict.charset > 2) {
+ gfree(glyphNames);
+ }
+}
+
+void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
+ Type1CTopDict dict;
+ Type1CPrivateDict *privateDicts;
+ GString *charStrings;
+ int *charStringOffsets;
+ Gushort *charset;
+ int *cidMap;
+ Guchar *fdSelect;
+ Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
+ char buf[256];
+ int nGlyphs, nCIDs, gdBytes, nFDs;
+ int fdSelectFmt, nRanges, gid0, gid1, fd, offset;
+ int key;
+ double x;
+ GBool isFP;
+ int i, j, k, n;
+
+ out = outA;
+
+ fprintf(out, "/CIDInit /ProcSet findresource begin\n");
+
+ // read top dict (first font only)
+ readTopDict(&dict);
+
+ // read the FDArray dictionaries and Private dictionaries
+ if (dict.fdArrayOffset == 0) {
+ nFDs = 1;
+ privateDicts = (Type1CPrivateDict *)
+ gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ privateDicts[0].dictData = new GString();
+ privateDicts[0].subrsOffset = 0;
+ privateDicts[0].defaultWidthX = 0;
+ privateDicts[0].defaultWidthXFP = gFalse;
+ privateDicts[0].nominalWidthX = 0;
+ privateDicts[0].nominalWidthXFP = gFalse;
+ } else {
+ fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
+ nFDs = getIndexLen(fdArrayIdx);
+ privateDicts = (Type1CPrivateDict *)
+ gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
+ for (i = 0; i < nFDs; ++i) {
+ privateDicts[i].dictData = NULL;
+ idxPtr0 = idxPtr1;
+ idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
+ ptr = idxPtr0;
+ j = 0;
+ while (ptr < idxPtr1) {
+ if (*ptr <= 27 || *ptr == 31) {
+ key = *ptr++;
+ if (key == 0x0c) {
+ key = (key << 8) | *ptr++;
+ }
+ if (key == 0x0012) {
+ readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
+ }
+ j = 0;
+ } else {
+ x = getNum(&ptr, &isFP);
+ if (j < 48) {
+ op[j] = x;
+ fp[j++] = isFP;
+ }
+ }
+ }
+ if (!privateDicts[i].dictData) {
+ privateDicts[i].dictData = new GString();
+ privateDicts[i].subrsOffset = 0;
+ privateDicts[i].defaultWidthX = 0;
+ privateDicts[i].defaultWidthXFP = gFalse;
+ privateDicts[i].nominalWidthX = 0;
+ privateDicts[i].nominalWidthXFP = gFalse;
+ }
+ }
+ }
+
+ // get the glyph count
+ charStringsIdxPtr = (Guchar *)file + dict.charStrings;
+ nGlyphs = getIndexLen(charStringsIdxPtr);
+
+ // read the FDSelect table
+ fdSelect = (Guchar *)gmalloc(nGlyphs);
+ if (dict.fdSelectOffset == 0) {
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ } else {
+ ptr = (Guchar *)file + dict.fdSelectOffset;
+ fdSelectFmt = *ptr++;
+ if (fdSelectFmt == 0) {
+ memcpy(fdSelect, ptr, nGlyphs);
+ } else if (fdSelectFmt == 3) {
+ nRanges = getWord(ptr, 2);
+ ptr += 2;
+ gid0 = getWord(ptr, 2);
+ ptr += 2;
+ for (i = 1; i <= nRanges; ++i) {
+ fd = *ptr++;
+ gid1 = getWord(ptr, 2);
+ ptr += 2;
+ for (j = gid0; j < gid1; ++j) {
+ fdSelect[j] = fd;
+ }
+ gid0 = gid1;
+ }
+ } else {
+ error(-1, "Unknown FDSelect table format in CID font");
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ }
+ }
+
+ // read the charset, compute the CID-to-GID mapping
+ charset = readCharset(dict.charset, nGlyphs);
+ nCIDs = 0;
+ for (i = 0; i < nGlyphs; ++i) {
+ if (charset[i] >= nCIDs) {
+ nCIDs = charset[i] + 1;
+ }
+ }
+ cidMap = (int *)gmalloc(nCIDs * sizeof(int));
+ for (i = 0; i < nCIDs; ++i) {
+ cidMap[i] = -1;
+ }
+ for (i = 0; i < nGlyphs; ++i) {
+ cidMap[charset[i]] = i;
+ }
+
+ // build the charstrings
+ charStrings = new GString();
+ charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int));
+ for (i = 0; i < nCIDs; ++i) {
+ charStringOffsets[i] = charStrings->getLength();
+ if (cidMap[i] >= 0) {
+ idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i]);
+ idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i]+1);
+ n = idxPtr1 - idxPtr0;
+ j = fdSelect[cidMap[i]];
+ defaultWidthX = privateDicts[j].defaultWidthX;
+ defaultWidthXFP = privateDicts[j].defaultWidthXFP;
+ nominalWidthX = privateDicts[j].nominalWidthX;
+ nominalWidthXFP = privateDicts[j].nominalWidthXFP;
+ cvtGlyph(idxPtr0, n);
+ charStrings->append(charBuf);
+ delete charBuf;
+ }
+ }
+ charStringOffsets[nCIDs] = charStrings->getLength();
+
+ // compute gdBytes = number of bytes needed for charstring offsets
+ // (offset size needs to account for the charstring offset table,
+ // with a worst case of five bytes per entry, plus the charstrings
+ // themselves)
+ i = (nCIDs + 1) * 5 + charStrings->getLength();
+ if (i < 0x100) {
+ gdBytes = 1;
+ } else if (i < 0x10000) {
+ gdBytes = 2;
+ } else if (i < 0x1000000) {
+ gdBytes = 3;
+ } else {
+ gdBytes = 4;
+ }
+
+ // begin the font dictionary
+ fprintf(out, "20 dict begin\n");
+ fprintf(out, "/CIDFontName /%s def\n", psName);
+ fprintf(out, "/CIDFontType 0 def\n");
+ fprintf(out, "/CIDSystemInfo 3 dict dup begin\n");
+ if (dict.registry > 0 && dict.ordering > 0) {
+ fprintf(out, " /Registry (%s) def\n", getString(dict.registry, buf));
+ fprintf(out, " /Ordering (%s) def\n", getString(dict.ordering, buf));
+ } else {
+ fprintf(out, " /Registry (Adobe) def\n");
+ fprintf(out, " /Ordering (Identity) def\n");
+ }
+ fprintf(out, " /Supplement %d def\n", dict.supplement);
+ fprintf(out, "end def\n");
+ fprintf(out, "/FontMatrix [%g %g %g %g %g %g] def\n",
+ dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
+ dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
+ fprintf(out, "/FontBBox [%g %g %g %g] def\n",
+ dict.fontBBox[0], dict.fontBBox[1],
+ dict.fontBBox[2], dict.fontBBox[3]);
+ fprintf(out, "/FontInfo 1 dict dup begin\n");
+ fprintf(out, " /FSType 8 def\n");
+ fprintf(out, "end def\n");
+
+ // CIDFont-specific entries
+ fprintf(out, "/CIDCount %d def\n", nCIDs);
+ fprintf(out, "/FDBytes 1 def\n");
+ fprintf(out, "/GDBytes %d def\n", gdBytes);
+ fprintf(out, "/CIDMapOffset 0 def\n");
+ if (dict.paintType != 0) {
+ fprintf(out, "/PaintType %d def\n", dict.paintType);
+ fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
+ }
+
+ // FDArray entry
+ fprintf(out, "/FDArray %d array\n", nFDs);
+ for (i = 0; i < nFDs; ++i) {
+ fprintf(out, "dup %d 10 dict begin\n", i);
+ fprintf(out, "/FontType 1 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/PaintType %d def\n", dict.paintType);
+ fprintf(out, "/Private 32 dict begin\n");
+ fwrite(privateDicts[i].dictData->getCString(), 1,
+ privateDicts[i].dictData->getLength(), out);
+ fprintf(out, "currentdict end def\n");
+ fprintf(out, "currentdict end put\n");
+ }
+ fprintf(out, "def\n");
+
+ //~ need to deal with subrs
+
+ // start the binary section
+ offset = (nCIDs + 1) * (1 + gdBytes);
+ fprintf(out, "(Hex) %d StartData\n",
+ offset + charStrings->getLength());
+
+ // write the charstring offset (CIDMap) table
+ for (i = 0; i <= nCIDs; i += 6) {
+ for (j = 0; j < 6 && i+j <= nCIDs; ++j) {
+ if (cidMap[i+j] >= 0) {
+ buf[0] = (char)fdSelect[cidMap[i+j]];
+ } else {
+ buf[0] = (char)0;
+ }
+ n = offset + charStringOffsets[i+j];
+ for (k = gdBytes; k >= 1; --k) {
+ buf[k] = (char)(n & 0xff);
+ n >>= 8;
+ }
+ for (k = 0; k <= gdBytes; ++k) {
+ fprintf(out, "%02x", buf[k] & 0xff);
+ }
+ }
+ fputc('\n', out);
+ }
+
+ // write the charstring data
+ n = charStrings->getLength();
+ for (i = 0; i < n; i += 32) {
+ for (j = 0; j < 32 && i+j < n; ++j) {
+ fprintf(out, "%02x", charStrings->getChar(i+j) & 0xff);
+ }
+ if (i + 32 >= n) {
+ fputc('>', out);
+ }
+ fputc('\n', out);
+ }
+
+ for (i = 0; i < nFDs; ++i) {
+ delete privateDicts[i].dictData;
+ }
+ gfree(privateDicts);
+ gfree(cidMap);
+ gfree(charset);
+ gfree(charStringOffsets);
+ delete charStrings;
+ gfree(fdSelect);
+}
+
+void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
+ Type1CTopDict dict;
+ Type1CPrivateDict *privateDicts;
+ Gushort *charset;
+ int *cidMap;
+ Guchar *fdSelect;
+ Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
+ char buf[256];
+ char eBuf[256];
+ int nGlyphs, nCIDs, nFDs;
+ int fdSelectFmt, nRanges, gid0, gid1, fd;
+ int key;
+ double x;
+ GBool isFP;
+ int i, j, n;
+
+ out = outA;
+
+ // read top dict (first font only)
+ readTopDict(&dict);
+
+ // read the FDArray dictionaries and Private dictionaries
+ if (dict.fdArrayOffset == 0) {
+ nFDs = 1;
+ privateDicts = (Type1CPrivateDict *)
+ gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ privateDicts[0].dictData = new GString();
+ privateDicts[0].subrsOffset = 0;
+ privateDicts[0].defaultWidthX = 0;
+ privateDicts[0].defaultWidthXFP = gFalse;
+ privateDicts[0].nominalWidthX = 0;
+ privateDicts[0].nominalWidthXFP = gFalse;
+ } else {
+ fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
+ nFDs = getIndexLen(fdArrayIdx);
+ privateDicts = (Type1CPrivateDict *)
+ gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
+ for (i = 0; i < nFDs; ++i) {
+ privateDicts[i].dictData = NULL;
+ idxPtr0 = idxPtr1;
+ idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
+ ptr = idxPtr0;
+ j = 0;
+ while (ptr < idxPtr1) {
+ if (*ptr <= 27 || *ptr == 31) {
+ key = *ptr++;
+ if (key == 0x0c) {
+ key = (key << 8) | *ptr++;
+ }
+ if (key == 0x0012) {
+ readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
+ }
+ j = 0;
+ } else {
+ x = getNum(&ptr, &isFP);
+ if (j < 48) {
+ op[j] = x;
+ fp[j++] = isFP;
+ }
+ }
+ }
+ if (!privateDicts[i].dictData) {
+ privateDicts[i].dictData = new GString();
+ privateDicts[i].subrsOffset = 0;
+ privateDicts[i].defaultWidthX = 0;
+ privateDicts[i].defaultWidthXFP = gFalse;
+ privateDicts[i].nominalWidthX = 0;
+ privateDicts[i].nominalWidthXFP = gFalse;
+ }
+ }
+ }
+
+ // get the glyph count
+ charStringsIdxPtr = (Guchar *)file + dict.charStrings;
+ nGlyphs = getIndexLen(charStringsIdxPtr);
+
+ // read the FDSelect table
+ fdSelect = (Guchar *)gmalloc(nGlyphs);
+ if (dict.fdSelectOffset == 0) {
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ } else {
+ ptr = (Guchar *)file + dict.fdSelectOffset;
+ fdSelectFmt = *ptr++;
+ if (fdSelectFmt == 0) {
+ memcpy(fdSelect, ptr, nGlyphs);
+ } else if (fdSelectFmt == 3) {
+ nRanges = getWord(ptr, 2);
+ ptr += 2;
+ gid0 = getWord(ptr, 2);
+ ptr += 2;
+ for (i = 1; i <= nRanges; ++i) {
+ fd = *ptr++;
+ gid1 = getWord(ptr, 2);
+ ptr += 2;
+ for (j = gid0; j < gid1; ++j) {
+ fdSelect[j] = fd;
+ }
+ gid0 = gid1;
+ }
+ } else {
+ error(-1, "Unknown FDSelect table format in CID font");
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ }
+ }
+
+ // read the charset, compute the CID-to-GID mapping
+ charset = readCharset(dict.charset, nGlyphs);
+ nCIDs = 0;
+ for (i = 0; i < nGlyphs; ++i) {
+ if (charset[i] >= nCIDs) {
+ nCIDs = charset[i] + 1;
+ }
+ }
+ cidMap = (int *)gmalloc(nCIDs * sizeof(int));
+ for (i = 0; i < nCIDs; ++i) {
+ cidMap[i] = -1;
+ }
+ for (i = 0; i < nGlyphs; ++i) {
+ cidMap[charset[i]] = i;
+ }
+
+ // write the descendant Type 1 fonts
+ for (i = 0; i < nCIDs; i += 256) {
+
+ //~ this assumes that all CIDs in this block have the same FD --
+ //~ to handle multiple FDs correctly, need to somehow divide the
+ //~ font up by FD
+ fd = 0;
+ for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+ if (cidMap[i+j] >= 0) {
+ fd = fdSelect[cidMap[i+j]];
+ break;
+ }
+ }
+
+ // font dictionary (unencrypted section)
+ fprintf(out, "16 dict begin\n");
+ fprintf(out, "/FontName /%s_%02x def\n", psName, i >> 8);
+ fprintf(out, "/FontType 1 def\n");
+ fprintf(out, "/FontMatrix [%g %g %g %g %g %g] def\n",
+ dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
+ dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
+ fprintf(out, "/FontBBox [%g %g %g %g] def\n",
+ dict.fontBBox[0], dict.fontBBox[1],
+ dict.fontBBox[2], dict.fontBBox[3]);
+ fprintf(out, "/PaintType %d def\n", dict.paintType);
+ if (dict.paintType != 0) {
+ fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
+ }
+ fprintf(out, "/Encoding 256 array\n");
+ for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+ fprintf(out, "dup %d /c%02x put\n", j, j);
+ }
+ fprintf(out, "readonly def\n");
+ fprintf(out, "currentdict end\n");
+
+ // start the binary section
+ fprintf(out, "currentfile eexec\n");
+ r1 = 55665;
+ line = 0;
+
+ // start the private dictionary
+ eexecWrite("\x83\xca\x73\xd5");
+ eexecWrite("dup /Private 32 dict dup begin\n");
+ eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n");
+ eexecWrite("/ND {noaccess def} executeonly def\n");
+ eexecWrite("/NP {noaccess put} executeonly def\n");
+ eexecWrite("/MinFeature {16 16} ND\n");
+ eexecWrite(privateDicts[fd].dictData->getCString());
+ defaultWidthX = privateDicts[fd].defaultWidthX;
+ defaultWidthXFP = privateDicts[fd].defaultWidthXFP;
+ nominalWidthX = privateDicts[fd].nominalWidthX;
+ nominalWidthXFP = privateDicts[fd].nominalWidthXFP;
+
+ // start the CharStrings
+ sprintf(eBuf, "2 index /CharStrings 256 dict dup begin\n");
+ eexecWrite(eBuf);
+
+ // write the .notdef CharString
+ idxPtr0 = getIndexValPtr(charStringsIdxPtr, 0);
+ idxPtr1 = getIndexValPtr(charStringsIdxPtr, 1);
+ n = idxPtr1 - idxPtr0;
+ eexecCvtGlyph(".notdef", idxPtr0, n);
+
+ // write the CharStrings
+ for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+ if (cidMap[i+j] >= 0) {
+ idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]);
+ idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]+1);
+ n = idxPtr1 - idxPtr0;
+ sprintf(buf, "c%02x", j);
+ eexecCvtGlyph(buf, idxPtr0, n);
+ }
+ }
+ eexecWrite("end\n");
+ eexecWrite("end\n");
+ eexecWrite("readonly put\n");
+ eexecWrite("noaccess put\n");
+ eexecWrite("dup /FontName get exch definefont pop\n");
+ eexecWrite("mark currentfile closefile\n");
+
+ // trailer
+ if (line > 0) {
+ fputc('\n', out);
+ }
+ for (j = 0; j < 8; ++j) {
+ fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
+ }
+ fprintf(out, "cleartomark\n");
+ }
+
+ // write the Type 0 parent font
+ fprintf(out, "16 dict begin\n");
+ fprintf(out, "/FontName /%s def\n", psName);
+ fprintf(out, "/FontType 0 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FMapType 2 def\n");
+ fprintf(out, "/Encoding [\n");
+ for (i = 0; i < nCIDs; i += 256) {
+ fprintf(out, "%d\n", i >> 8);
+ }
+ fprintf(out, "] def\n");
+ fprintf(out, "/FDepVector [\n");
+ for (i = 0; i < nCIDs; i += 256) {
+ fprintf(out, "/%s_%02x findfont\n", psName, i >> 8);
+ }
+ fprintf(out, "] def\n");
+ fprintf(out, "FontName currentdict end definefont pop\n");
+
+ // clean up
+ for (i = 0; i < nFDs; ++i) {
+ delete privateDicts[i].dictData;
+ }
+ gfree(privateDicts);
+ gfree(cidMap);
+ gfree(charset);
+ gfree(fdSelect);
+}
+
+void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
+ Guchar *idxPtr0, *idxPtr1, *ptr;
+ double x;
+ GBool isFP;
+ int key;
+ int i;
+
+ idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
+ idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
+ dict->version = 0;
+ dict->notice = 0;
+ dict->copyright = 0;
+ dict->fullName = 0;
+ dict->familyName = 0;
+ dict->weight = 0;
+ dict->isFixedPitch = 0;
+ dict->italicAngle = 0;
+ dict->underlinePosition = -100;
+ dict->underlineThickness = 50;
+ dict->paintType = 0;
+ dict->charstringType = 2;
+ dict->fontMatrix[0] = 0.001;
+ dict->fontMatrix[1] = 0;
+ dict->fontMatrix[2] = 0;
+ dict->fontMatrix[3] = 0.001;
+ dict->fontMatrix[4] = 0;
+ dict->fontMatrix[5] = 0;
+ dict->uniqueID = 0;
+ dict->fontBBox[0] = 0;
+ dict->fontBBox[1] = 0;
+ dict->fontBBox[2] = 0;
+ dict->fontBBox[3] = 0;
+ dict->strokeWidth = 0;
+ dict->charset = 0;
+ dict->encoding = 0;
+ dict->charStrings = 0;
+ dict->privateSize = 0;
+ dict->privateOffset = 0;
+ dict->registry = 0;
+ dict->ordering = 0;
+ dict->supplement = 0;
+ dict->fdArrayOffset = 0;
+ dict->fdSelectOffset = 0;
i = 0;
- while (idxPtr0 < idxPtr1) {
- if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
- key = *idxPtr0++;
- if (key == 0x0c)
- key = (key << 8) | *idxPtr0++;
+ ptr = idxPtr0;
+ while (ptr < idxPtr1) {
+ if (*ptr <= 27 || *ptr == 31) {
+ key = *ptr++;
+ if (key == 0x0c) {
+ key = (key << 8) | *ptr++;
+ }
+ switch (key) {
+ case 0x0000: dict->version = (int)op[0]; break;
+ case 0x0001: dict->notice = (int)op[0]; break;
+ case 0x0c00: dict->copyright = (int)op[0]; break;
+ case 0x0002: dict->fullName = (int)op[0]; break;
+ case 0x0003: dict->familyName = (int)op[0]; break;
+ case 0x0004: dict->weight = (int)op[0]; break;
+ case 0x0c01: dict->isFixedPitch = (int)op[0]; break;
+ case 0x0c02: dict->italicAngle = op[0]; break;
+ case 0x0c03: dict->underlinePosition = op[0]; break;
+ case 0x0c04: dict->underlineThickness = op[0]; break;
+ case 0x0c05: dict->paintType = (int)op[0]; break;
+ case 0x0c06: dict->charstringType = (int)op[0]; break;
+ case 0x0c07: dict->fontMatrix[0] = op[0];
+ dict->fontMatrix[1] = op[1];
+ dict->fontMatrix[2] = op[2];
+ dict->fontMatrix[3] = op[3];
+ dict->fontMatrix[4] = op[4];
+ dict->fontMatrix[5] = op[5]; break;
+ case 0x000d: dict->uniqueID = (int)op[0]; break;
+ case 0x0005: dict->fontBBox[0] = op[0];
+ dict->fontBBox[1] = op[1];
+ dict->fontBBox[2] = op[2];
+ dict->fontBBox[3] = op[3]; break;
+ case 0x0c08: dict->strokeWidth = op[0]; break;
+ case 0x000f: dict->charset = (int)op[0]; break;
+ case 0x0010: dict->encoding = (int)op[0]; break;
+ case 0x0011: dict->charStrings = (int)op[0]; break;
+ case 0x0012: dict->privateSize = (int)op[0];
+ dict->privateOffset = (int)op[1]; break;
+ case 0x0c1e: dict->registry = (int)op[0];
+ dict->ordering = (int)op[1];
+ dict->supplement = (int)op[2]; break;
+ case 0x0c24: dict->fdArrayOffset = (int)op[0]; break;
+ case 0x0c25: dict->fdSelectOffset = (int)op[0]; break;
+ }
+ i = 0;
+ } else {
+ x = getNum(&ptr, &isFP);
+ if (i < 48) {
+ op[i] = x;
+ fp[i++] = isFP;
+ }
+ }
+ }
+}
+
+void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
+ int offset, int size) {
+ Guchar *idxPtr0, *idxPtr1, *ptr;
+ char eBuf[256];
+ int key;
+ double x;
+ GBool isFP;
+ int i;
+
+ privateDict->dictData = new GString();
+ privateDict->subrsOffset = 0;
+ privateDict->defaultWidthX = 0;
+ privateDict->defaultWidthXFP = gFalse;
+ privateDict->nominalWidthX = 0;
+ privateDict->nominalWidthXFP = gFalse;
+ idxPtr0 = (Guchar *)file + offset;
+ idxPtr1 = idxPtr0 + size;
+ ptr = idxPtr0;
+ i = 0;
+ while (ptr < idxPtr1) {
+ if (*ptr <= 27 || *ptr == 31) {
+ key = *ptr++;
+ if (key == 0x0c) {
+ key = (key << 8) | *ptr++;
+ }
switch (key) {
case 0x0006:
getDeltaInt(eBuf, "BlueValues", op, i);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0007:
getDeltaInt(eBuf, "OtherBlues", op, i);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0008:
getDeltaInt(eBuf, "FamilyBlues", op, i);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0009:
getDeltaInt(eBuf, "FamilyOtherBlues", op, i);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0c09:
sprintf(eBuf, "/BlueScale %g def\n", op[0]);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0c0a:
sprintf(eBuf, "/BlueShift %d def\n", (int)op[0]);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0c0b:
sprintf(eBuf, "/BlueFuzz %d def\n", (int)op[0]);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x000a:
sprintf(eBuf, "/StdHW [%g] def\n", op[0]);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x000b:
sprintf(eBuf, "/StdVW [%g] def\n", op[0]);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0c0c:
getDeltaReal(eBuf, "StemSnapH", op, i);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0c0d:
getDeltaReal(eBuf, "StemSnapV", op, i);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0c0e:
sprintf(eBuf, "/ForceBold %s def\n", op[0] ? "true" : "false");
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0c0f:
sprintf(eBuf, "/ForceBoldThreshold %g def\n", op[0]);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0c11:
sprintf(eBuf, "/LanguageGroup %d def\n", (int)op[0]);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0c12:
sprintf(eBuf, "/ExpansionFactor %g def\n", op[0]);
- eexecWrite(eBuf);
+ privateDict->dictData->append(eBuf);
break;
case 0x0c13:
error(-1, "Got Type 1C InitialRandomSeed");
break;
case 0x0013:
- subrsOffset = (int)op[0];
+ privateDict->subrsOffset = (int)op[0];
break;
case 0x0014:
- defaultWidthX = op[0];
- defaultWidthXFP = fp[0];
+ privateDict->defaultWidthX = op[0];
+ privateDict->defaultWidthXFP = fp[0];
break;
case 0x0015:
- nominalWidthX = op[0];
- nominalWidthXFP = fp[0];
+ privateDict->nominalWidthX = op[0];
+ privateDict->nominalWidthXFP = fp[0];
break;
default:
- error(-1, "Uknown Type 1C private dict entry %04x", key);
+ error(-1, "Unknown Type 1C private dict entry %04x", key);
break;
}
i = 0;
} else {
- x = getNum(&idxPtr0, &isFP);
+ x = getNum(&ptr, &isFP);
if (i < 48) {
op[i] = x;
fp[i++] = isFP;
}
}
}
+}
- // get subrs
- if (subrsOffset != 0) {
- topPtr += subrsOffset;
- nSubrs = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
- sprintf(eBuf, "/Subrs %d array\n", nSubrs);
- eexecWrite(eBuf);
- idxStartPtr = topPtr + (nSubrs + 1) * idxOffSize - 1;
- idxPtr1 = idxStartPtr + getWord(topPtr, idxOffSize);
- for (i = 0; i < nSubrs; ++i) {
- idxPtr0 = idxPtr1;
- idxPtr1 = idxStartPtr + getWord(topPtr + (i+1)*idxOffSize, idxOffSize);
- n = idxPtr1 - idxPtr0;
-#if 1 //~
- error(-1, "Unimplemented Type 2 subrs");
-#else
- sprintf(eBuf, "dup %d %d RD ", i, n);
- eexecWrite(eBuf);
- cvtGlyph(idxPtr0, n);
- eexecWrite(" NP\n");
-#endif
- }
- eexecWrite("ND\n");
- }
-
- // get CharStrings
- topPtr = (Guchar *)file + dict.charStrings;
- nCharStrings = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
- sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings);
- eexecWrite(eBuf);
- idxStartPtr = topPtr + (nCharStrings + 1) * idxOffSize - 1;
- idxPtr1 = idxStartPtr + getWord(topPtr, idxOffSize);
- for (i = 0; i < nCharStrings; ++i) {
- idxPtr0 = idxPtr1;
- idxPtr1 = idxStartPtr + getWord(topPtr + (i+1)*idxOffSize, idxOffSize);
- n = idxPtr1 - idxPtr0;
- cvtGlyph(getString(glyphNames[i], stringIdxPtr, stringStartPtr,
- stringOffSize, buf),
- idxPtr0, n);
- }
- eexecWrite("end\n");
- eexecWrite("end\n");
- eexecWrite("readonly put\n");
- eexecWrite("noaccess put\n");
- eexecWrite("dup /FontName get exch definefont pop\n");
- eexecWrite("mark currentfile closefile\n");
+Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
+ Gushort *glyphNames;
+ Guchar *ptr;
+ int charsetFormat, c;
+ int nLeft, i, j;
- // trailer
- if (line > 0)
- fputc('\n', out);
- for (i = 0; i < 8; ++i) {
- fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
+ if (charset == 0) {
+ glyphNames = type1CISOAdobeCharset;
+ } else if (charset == 1) {
+ glyphNames = type1CExpertCharset;
+ } else if (charset == 2) {
+ glyphNames = type1CExpertSubsetCharset;
+ } else {
+ glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
+ glyphNames[0] = 0;
+ ptr = (Guchar *)file + charset;
+ charsetFormat = *ptr++;
+ if (charsetFormat == 0) {
+ for (i = 1; i < nGlyphs; ++i) {
+ glyphNames[i] = getWord(ptr, 2);
+ ptr += 2;
+ }
+ } else if (charsetFormat == 1) {
+ i = 1;
+ while (i < nGlyphs) {
+ c = getWord(ptr, 2);
+ ptr += 2;
+ nLeft = *ptr++;
+ for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
+ glyphNames[i++] = c++;
+ }
+ }
+ } else if (charsetFormat == 2) {
+ i = 1;
+ while (i < nGlyphs) {
+ c = getWord(ptr, 2);
+ ptr += 2;
+ nLeft = getWord(ptr, 2);
+ ptr += 2;
+ for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
+ glyphNames[i++] = c++;
+ }
+ }
+ }
}
- fprintf(out, "cleartomark\n");
-
- // clean up
- if (dict.charset > 2)
- gfree(glyphNames);
- gfree(fontName);
+ return glyphNames;
}
-void Type1CFontConverter::eexecWrite(char *s) {
+void Type1CFontFile::eexecWrite(char *s) {
Guchar *p;
Guchar x;
@@ -945,13 +1338,25 @@ void Type1CFontConverter::eexecWrite(char *s) {
}
}
-void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
+void Type1CFontFile::eexecCvtGlyph(char *glyphName, Guchar *s, int n) {
+ char eBuf[256];
+
+ cvtGlyph(s, n);
+ sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength());
+ eexecWrite(eBuf);
+ eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
+ eexecWrite(" ND\n");
+ delete charBuf;
+}
+
+void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
int nHints;
int x;
GBool first = gTrue;
- char eBuf[256];
double d, dx, dy;
GBool dFP;
+ Gushort r2;
+ Guchar byte;
int i, k;
charBuf = new GString();
@@ -967,7 +1372,7 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
if (s[i] == 12) {
switch (s[i+1]) {
case 0: // dotsection (should be Type 1 only?)
- //~ ignored
+ // ignored
break;
case 34: // hflex
if (nOps != 7) {
@@ -1083,7 +1488,7 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
i += 2;
nOps = 0;
} else if (s[i] == 19) { // hintmask
- //~ ignored
+ // ignored
if (first) {
cvtGlyphWidth(nOps == 1);
first = gFalse;
@@ -1098,7 +1503,7 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
i += 1 + ((nHints + 7) >> 3);
nOps = 0;
} else if (s[i] == 20) { // cntrmask
- //~ ignored
+ // ignored
if (first) {
cvtGlyphWidth(nOps == 1);
first = gFalse;
@@ -1114,8 +1519,9 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
nOps = 0;
} else if (s[i] == 28) {
x = (s[i+1] << 8) + s[i+2];
- if (x & 0x8000)
+ if (x & 0x8000) {
x |= -1 << 15;
+ }
if (nOps < 48) {
fp[nOps] = gFalse;
op[nOps++] = x;
@@ -1128,14 +1534,16 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
cvtGlyphWidth(nOps == 2);
first = gFalse;
}
- if (nOps != 1)
+ if (nOps != 1) {
error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps);
+ }
eexecDumpNum(op[0], fp[0]);
eexecDumpOp1(4);
break;
case 5: // rlineto
- if (nOps < 2 || nOps % 2 != 0)
+ if (nOps < 2 || nOps % 2 != 0) {
error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps);
+ }
for (k = 0; k < nOps; k += 2) {
eexecDumpNum(op[k], fp[k]);
eexecDumpNum(op[k+1], fp[k+1]);
@@ -1143,24 +1551,27 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
}
break;
case 6: // hlineto
- if (nOps < 1)
+ if (nOps < 1) {
error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps);
+ }
for (k = 0; k < nOps; ++k) {
eexecDumpNum(op[k], fp[k]);
eexecDumpOp1((k & 1) ? 7 : 6);
}
break;
case 7: // vlineto
- if (nOps < 1)
+ if (nOps < 1) {
error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps);
+ }
for (k = 0; k < nOps; ++k) {
eexecDumpNum(op[k], fp[k]);
eexecDumpOp1((k & 1) ? 6 : 7);
}
break;
case 8: // rrcurveto
- if (nOps < 6 || nOps % 6 != 0)
+ if (nOps < 6 || nOps % 6 != 0) {
error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps);
+ }
for (k = 0; k < nOps; k += 6) {
eexecDumpNum(op[k], fp[k]);
eexecDumpNum(op[k+1], fp[k+1]);
@@ -1194,8 +1605,9 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
cvtGlyphWidth(nOps == 3);
first = gFalse;
}
- if (nOps != 2)
+ if (nOps != 2) {
error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps);
+ }
eexecDumpNum(op[0], fp[0]);
eexecDumpNum(op[1], fp[1]);
eexecDumpOp1(21);
@@ -1205,14 +1617,16 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
cvtGlyphWidth(nOps == 2);
first = gFalse;
}
- if (nOps != 1)
+ if (nOps != 1) {
error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps);
+ }
eexecDumpNum(op[0], fp[0]);
eexecDumpOp1(22);
break;
case 24: // rcurveline
- if (nOps < 8 || (nOps - 2) % 6 != 0)
+ if (nOps < 8 || (nOps - 2) % 6 != 0) {
error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps);
+ }
for (k = 0; k < nOps - 2; k += 6) {
eexecDumpNum(op[k], fp[k]);
eexecDumpNum(op[k+1], fp[k+1]);
@@ -1227,8 +1641,9 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
eexecDumpOp1(5);
break;
case 25: // rlinecurve
- if (nOps < 8 || (nOps - 6) % 2 != 0)
+ if (nOps < 8 || (nOps - 6) % 2 != 0) {
error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps);
+ }
for (k = 0; k < nOps - 6; k += 2) {
eexecDumpNum(op[k], fp[k]);
eexecDumpNum(op[k+1], fp[k]);
@@ -1243,8 +1658,9 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
eexecDumpOp1(8);
break;
case 26: // vvcurveto
- if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps);
+ }
if (nOps % 2 == 1) {
eexecDumpNum(op[0], fp[0]);
eexecDumpNum(op[1], fp[1]);
@@ -1268,8 +1684,9 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
}
break;
case 27: // hhcurveto
- if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps);
+ }
if (nOps % 2 == 1) {
eexecDumpNum(op[1], fp[1]);
eexecDumpNum(op[0], fp[0]);
@@ -1293,8 +1710,9 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
}
break;
case 30: // vhcurveto
- if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps);
+ }
for (k = 0; k < nOps && k != nOps-5; k += 4) {
if (k % 8 == 0) {
eexecDumpNum(op[k], fp[k]);
@@ -1330,8 +1748,9 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
}
break;
case 31: // hvcurveto
- if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps);
+ }
for (k = 0; k < nOps && k != nOps-5; k += 4) {
if (k % 8 == 0) {
eexecDumpNum(op[k], fp[k]);
@@ -1423,7 +1842,7 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
nHints += nOps / 2;
break;
case 18: // hstemhm
- //~ ignored
+ // ignored
if (first) {
cvtGlyphWidth(nOps & 1);
first = gFalse;
@@ -1434,7 +1853,7 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
nHints += nOps / 2;
break;
case 23: // vstemhm
- //~ ignored
+ // ignored
if (first) {
cvtGlyphWidth(nOps & 1);
first = gFalse;
@@ -1486,14 +1905,16 @@ void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
}
}
- sprintf(eBuf, "/%s %d RD ", name, charBuf->getLength());
- eexecWrite(eBuf);
- eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
- eexecWrite(" ND\n");
- delete charBuf;
+ // charstring encryption
+ r2 = 4330;
+ for (i = 0; i < charBuf->getLength(); ++i) {
+ byte = charBuf->getChar(i) ^ (r2 >> 8);
+ charBuf->setChar(i, byte);
+ r2 = (byte + r2) * 52845 + 22719;
+ }
}
-void Type1CFontConverter::cvtGlyphWidth(GBool useOp) {
+void Type1CFontFile::cvtGlyphWidth(GBool useOp) {
double w;
GBool wFP;
int i;
@@ -1515,12 +1936,12 @@ void Type1CFontConverter::cvtGlyphWidth(GBool useOp) {
eexecDumpOp1(13);
}
-void Type1CFontConverter::eexecDumpNum(double x, GBool fp) {
+void Type1CFontFile::eexecDumpNum(double x, GBool fpA) {
Guchar buf[12];
int y, n;
n = 0;
- if (fp) {
+ if (fpA) {
if (x >= -32768 && x < 32768) {
y = (int)(x * 256.0);
buf[0] = 255;
@@ -1566,30 +1987,22 @@ void Type1CFontConverter::eexecDumpNum(double x, GBool fp) {
charBuf->append((char *)buf, n);
}
-void Type1CFontConverter::eexecDumpOp1(int op) {
- charBuf->append((char)op);
+void Type1CFontFile::eexecDumpOp1(int opA) {
+ charBuf->append((char)opA);
}
-void Type1CFontConverter::eexecDumpOp2(int op) {
+void Type1CFontFile::eexecDumpOp2(int opA) {
charBuf->append((char)12);
- charBuf->append((char)op);
+ charBuf->append((char)opA);
}
-void Type1CFontConverter::eexecWriteCharstring(Guchar *s, int n) {
- Gushort r2;
+void Type1CFontFile::eexecWriteCharstring(Guchar *s, int n) {
Guchar x;
int i;
- r2 = 4330;
-
+ // eexec encryption
for (i = 0; i < n; ++i) {
- // charstring encryption
- x = s[i];
- x ^= (r2 >> 8);
- r2 = (x + r2) * 52845 + 22719;
-
- // eexec encryption
- x ^= (r1 >> 8);
+ x = s[i] ^ (r1 >> 8);
r1 = (x + r1) * 52845 + 22719;
fputc(hexChars[x >> 4], out);
fputc(hexChars[x & 0x0f], out);
@@ -1601,33 +2014,1668 @@ void Type1CFontConverter::eexecWriteCharstring(Guchar *s, int n) {
}
}
-void Type1CFontConverter::getDeltaInt(char *buf, char *name, double *op,
- int n) {
+void Type1CFontFile::getDeltaInt(char *buf, char *key, double *opA,
+ int n) {
int x, i;
- sprintf(buf, "/%s [", name);
+ sprintf(buf, "/%s [", key);
buf += strlen(buf);
x = 0;
for (i = 0; i < n; ++i) {
- x += (int)op[i];
+ x += (int)opA[i];
sprintf(buf, "%s%d", i > 0 ? " " : "", x);
buf += strlen(buf);
}
sprintf(buf, "] def\n");
}
-void Type1CFontConverter::getDeltaReal(char *buf, char *name, double *op,
- int n) {
+void Type1CFontFile::getDeltaReal(char *buf, char *key, double *opA,
+ int n) {
double x;
int i;
- sprintf(buf, "/%s [", name);
+ sprintf(buf, "/%s [", key);
buf += strlen(buf);
x = 0;
for (i = 0; i < n; ++i) {
- x += op[i];
+ x += opA[i];
sprintf(buf, "%s%g", i > 0 ? " " : "", x);
buf += strlen(buf);
}
sprintf(buf, "] def\n");
}
+
+int Type1CFontFile::getIndexLen(Guchar *indexPtr) {
+ return (int)getWord(indexPtr, 2);
+}
+
+Guchar *Type1CFontFile::getIndexValPtr(Guchar *indexPtr, int i) {
+ int n, offSize;
+ Guchar *idxStartPtr;
+
+ n = (int)getWord(indexPtr, 2);
+ offSize = indexPtr[2];
+ idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
+ return idxStartPtr + getWord(indexPtr + 3 + i * offSize, offSize);
+}
+
+Guchar *Type1CFontFile::getIndexEnd(Guchar *indexPtr) {
+ int n, offSize;
+ Guchar *idxStartPtr;
+
+ n = (int)getWord(indexPtr, 2);
+ offSize = indexPtr[2];
+ idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
+ return idxStartPtr + getWord(indexPtr + 3 + n * offSize, offSize);
+}
+
+Guint Type1CFontFile::getWord(Guchar *ptr, int size) {
+ Guint x;
+ int i;
+
+ x = 0;
+ for (i = 0; i < size; ++i) {
+ x = (x << 8) + *ptr++;
+ }
+ return x;
+}
+
+double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) {
+ static char nybChars[16] = "0123456789.ee -";
+ int b0, b, nyb0, nyb1;
+ double x;
+ char buf[65];
+ int i;
+
+ x = 0;
+ *isFP = gFalse;
+ b0 = (*ptr)[0];
+ if (b0 < 28) {
+ x = 0;
+ } else if (b0 == 28) {
+ x = ((*ptr)[1] << 8) + (*ptr)[2];
+ *ptr += 3;
+ } else if (b0 == 29) {
+ x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4];
+ *ptr += 5;
+ } else if (b0 == 30) {
+ *ptr += 1;
+ i = 0;
+ do {
+ b = *(*ptr)++;
+ nyb0 = b >> 4;
+ nyb1 = b & 0x0f;
+ if (nyb0 == 0xf) {
+ break;
+ }
+ buf[i++] = nybChars[nyb0];
+ if (i == 64) {
+ break;
+ }
+ if (nyb0 == 0xc) {
+ buf[i++] = '-';
+ }
+ if (i == 64) {
+ break;
+ }
+ if (nyb1 == 0xf) {
+ break;
+ }
+ buf[i++] = nybChars[nyb1];
+ if (i == 64) {
+ break;
+ }
+ if (nyb1 == 0xc) {
+ buf[i++] = '-';
+ }
+ } while (i < 64);
+ buf[i] = '\0';
+ x = atof(buf);
+ *isFP = gTrue;
+ } else if (b0 == 31) {
+ x = 0;
+ } else if (b0 < 247) {
+ x = b0 - 139;
+ *ptr += 1;
+ } else if (b0 < 251) {
+ x = ((b0 - 247) << 8) + (*ptr)[1] + 108;
+ *ptr += 2;
+ } else {
+ x = -((b0 - 251) << 8) - (*ptr)[1] - 108;
+ *ptr += 2;
+ }
+ return x;
+}
+
+char *Type1CFontFile::getString(int sid, char *buf) {
+ Guchar *idxPtr0, *idxPtr1;
+ int n;
+
+ if (sid < 391) {
+ strcpy(buf, type1CStdStrings[sid]);
+ } else {
+ sid -= 391;
+ idxPtr0 = getIndexValPtr(stringIdxPtr, sid);
+ idxPtr1 = getIndexValPtr(stringIdxPtr, sid + 1);
+ if ((n = idxPtr1 - idxPtr0) > 255) {
+ n = 255;
+ }
+ strncpy(buf, (char *)idxPtr0, n);
+ buf[n] = '\0';
+ }
+ return buf;
+}
+
+//------------------------------------------------------------------------
+// TrueTypeFontFile
+//------------------------------------------------------------------------
+
+//
+// Terminology
+// -----------
+//
+// character code = number used as an element of a text string
+//
+// character name = glyph name = name for a particular glyph within a
+// font
+//
+// glyph index = position (within some internal table in the font)
+// where the instructions to draw a particular glyph are
+// stored
+//
+// Type 1 fonts
+// ------------
+//
+// Type 1 fonts contain:
+//
+// Encoding: array of glyph names, maps char codes to glyph names
+//
+// Encoding[charCode] = charName
+//
+// CharStrings: dictionary of instructions, keyed by character names,
+// maps character name to glyph data
+//
+// CharStrings[charName] = glyphData
+//
+// TrueType fonts
+// --------------
+//
+// TrueType fonts contain:
+//
+// 'cmap' table: mapping from character code to glyph index; there may
+// be multiple cmaps in a TrueType font
+//
+// cmap[charCode] = glyphIdx
+//
+// 'post' table: mapping from glyph index to glyph name
+//
+// post[glyphIdx] = glyphName
+//
+// Type 42 fonts
+// -------------
+//
+// Type 42 fonts contain:
+//
+// Encoding: array of glyph names, maps char codes to glyph names
+//
+// Encoding[charCode] = charName
+//
+// CharStrings: dictionary of glyph indexes, keyed by character names,
+// maps character name to glyph index
+//
+// CharStrings[charName] = glyphIdx
+//
+
+struct TTFontTableHdr {
+ char tag[4];
+ Guint checksum;
+ Guint offset;
+ Guint length;
+};
+
+struct T42Table {
+ char *tag; // 4-byte tag
+ GBool required; // required by the TrueType spec?
+};
+
+// TrueType tables to be embedded in Type 42 fonts.
+// NB: the table names must be in alphabetical order here.
+#define nT42Tables 11
+static T42Table t42Tables[nT42Tables] = {
+ { "cvt ", gTrue },
+ { "fpgm", gTrue },
+ { "glyf", gTrue },
+ { "head", gTrue },
+ { "hhea", gTrue },
+ { "hmtx", gTrue },
+ { "loca", gTrue },
+ { "maxp", gTrue },
+ { "prep", gTrue },
+ { "vhea", gFalse },
+ { "vmtx", gFalse }
+};
+#define t42HeadTable 3
+#define t42LocaTable 6
+#define t42GlyfTable 2
+
+// Glyph names in some arbitrary standard that Apple uses for their
+// TrueType fonts.
+static char *macGlyphNames[258] = {
+ ".notdef",
+ "null",
+ "CR",
+ "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",
+ "mu1",
+ "partialdiff",
+ "summation",
+ "product",
+ "pi",
+ "integral",
+ "ordfeminine",
+ "ordmasculine",
+ "Ohm",
+ "ae",
+ "oslash",
+ "questiondown",
+ "exclamdown",
+ "logicalnot",
+ "radical",
+ "florin",
+ "approxequal",
+ "increment",
+ "guillemotleft",
+ "guillemotright",
+ "ellipsis",
+ "nbspace",
+ "Agrave",
+ "Atilde",
+ "Otilde",
+ "OE",
+ "oe",
+ "endash",
+ "emdash",
+ "quotedblleft",
+ "quotedblright",
+ "quoteleft",
+ "quoteright",
+ "divide",
+ "lozenge",
+ "ydieresis",
+ "Ydieresis",
+ "fraction",
+ "currency",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "daggerdbl",
+ "periodcentered",
+ "quotesinglbase",
+ "quotedblbase",
+ "perthousand",
+ "Acircumflex",
+ "Ecircumflex",
+ "Aacute",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Oacute",
+ "Ocircumflex",
+ "applelogo",
+ "Ograve",
+ "Uacute",
+ "Ucircumflex",
+ "Ugrave",
+ "dotlessi",
+ "circumflex",
+ "tilde",
+ "overscore",
+ "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",
+ "Idot",
+ "Scedilla",
+ "scedilla",
+ "Cacute",
+ "cacute",
+ "Ccaron",
+ "ccaron",
+ "dmacron"
+};
+
+enum T42FontIndexMode {
+ t42FontModeUnicode,
+ t42FontModeCharCode,
+ t42FontModeCharCodeOffset,
+ t42FontModeMacRoman
+};
+
+TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
+ int pos, i;
+
+ file = fileA;
+ len = lenA;
+
+ encoding = NULL;
+
+ // read table directory
+ nTables = getUShort(4);
+ tableHdrs = (TTFontTableHdr *)gmalloc(nTables * sizeof(TTFontTableHdr));
+ pos = 12;
+ for (i = 0; i < nTables; ++i) {
+ tableHdrs[i].tag[0] = getByte(pos+0);
+ tableHdrs[i].tag[1] = getByte(pos+1);
+ tableHdrs[i].tag[2] = getByte(pos+2);
+ tableHdrs[i].tag[3] = getByte(pos+3);
+ tableHdrs[i].checksum = getULong(pos+4);
+ tableHdrs[i].offset = getULong(pos+8);
+ tableHdrs[i].length = getULong(pos+12);
+ pos += 16;
+ }
+
+ // check for tables that are required by both the TrueType spec
+ // and the Type 42 spec
+ if (seekTable("head") < 0 ||
+ seekTable("hhea") < 0 ||
+ seekTable("loca") < 0 ||
+ seekTable("maxp") < 0 ||
+ seekTable("glyf") < 0 ||
+ seekTable("hmtx") < 0) {
+ error(-1, "TrueType font file is missing a required table");
+ return;
+ }
+
+ // read the 'head' table
+ pos = seekTable("head");
+ bbox[0] = getShort(pos + 36);
+ bbox[1] = getShort(pos + 38);
+ bbox[2] = getShort(pos + 40);
+ bbox[3] = getShort(pos + 42);
+ locaFmt = getShort(pos + 50);
+
+ // read the 'maxp' table
+ pos = seekTable("maxp");
+ nGlyphs = getUShort(pos + 4);
+}
+
+TrueTypeFontFile::~TrueTypeFontFile() {
+ int i;
+
+ if (encoding) {
+ for (i = 0; i < 256; ++i) {
+ gfree(encoding[i]);
+ }
+ gfree(encoding);
+ }
+ gfree(tableHdrs);
+}
+
+char *TrueTypeFontFile::getName() {
+ return NULL;
+}
+
+char **TrueTypeFontFile::getEncoding() {
+ int cmap[256];
+ int nCmaps, cmapPlatform, cmapEncoding, cmapFmt;
+ int cmapLen, cmapOffset, cmapFirst;
+ int segCnt, segStart, segEnd, segDelta, segOffset;
+ int pos, i, j, k;
+ Guint fmt;
+ GString *s;
+ int stringIdx, stringPos, n;
+
+ if (encoding) {
+ return encoding;
+ }
+
+ //----- construct the (char code) -> (glyph idx) mapping
+
+ // map everything to the missing glyph
+ for (i = 0; i < 256; ++i) {
+ cmap[i] = 0;
+ }
+
+ // look for the 'cmap' table
+ if ((pos = seekTable("cmap")) >= 0) {
+ nCmaps = getUShort(pos+2);
+
+ // if the font has a Windows-symbol cmap, use it;
+ // otherwise, use the first cmap in the table
+ for (i = 0; i < nCmaps; ++i) {
+ cmapPlatform = getUShort(pos + 4 + 8*i);
+ cmapEncoding = getUShort(pos + 4 + 8*i + 2);
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ break;
+ }
+ }
+ if (i >= nCmaps) {
+ i = 0;
+ cmapPlatform = getUShort(pos + 4);
+ cmapEncoding = getUShort(pos + 4 + 2);
+ }
+ pos += getULong(pos + 4 + 8*i + 4);
+
+ // read the cmap
+ cmapFmt = getUShort(pos);
+ switch (cmapFmt) {
+ case 0: // byte encoding table (Apple standard)
+ cmapLen = getUShort(pos + 2);
+ for (i = 0; i < cmapLen && i < 256; ++i) {
+ cmap[i] = getByte(pos + 6 + i);
+ }
+ break;
+ case 4: // segment mapping to delta values (Microsoft standard)
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ // Windows-symbol uses char codes 0xf000 - 0xf0ff
+ cmapOffset = 0xf000;
+ } else {
+ cmapOffset = 0;
+ }
+ segCnt = getUShort(pos + 6) / 2;
+ for (i = 0; i < segCnt; ++i) {
+ segEnd = getUShort(pos + 14 + 2*i);
+ segStart = getUShort(pos + 16 + 2*segCnt + 2*i);
+ segDelta = getUShort(pos + 16 + 4*segCnt + 2*i);
+ segOffset = getUShort(pos + 16 + 6*segCnt + 2*i);
+ if (segStart - cmapOffset <= 0xff &&
+ segEnd - cmapOffset >= 0) {
+ for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset;
+ j <= segEnd && j - cmapOffset <= 0xff;
+ ++j) {
+ if (segOffset == 0) {
+ k = (j + segDelta) & 0xffff;
+ } else {
+ k = getUShort(pos + 16 + 6*segCnt + 2*i +
+ segOffset + 2 * (j - segStart));
+ if (k != 0) {
+ k = (k + segDelta) & 0xffff;
+ }
+ }
+ cmap[j - cmapOffset] = k;
+ }
+ }
+ }
+ break;
+ case 6: // trimmed table mapping
+ cmapFirst = getUShort(pos + 6);
+ cmapLen = getUShort(pos + 8);
+ for (i = cmapFirst; i < 256 && i < cmapFirst + cmapLen; ++i) {
+ cmap[i] = getUShort(pos + 10 + 2*i);
+ }
+ break;
+ default:
+ error(-1, "Unimplemented cmap format (%d) in TrueType font file",
+ cmapFmt);
+ break;
+ }
+ }
+
+ //----- construct the (glyph idx) -> (glyph name) mapping
+ //----- and compute the (char code) -> (glyph name) mapping
+
+ encoding = (char **)gmalloc(256 * sizeof(char *));
+ for (i = 0; i < 256; ++i) {
+ encoding[i] = NULL;
+ }
+
+ if ((pos = seekTable("post")) >= 0) {
+ fmt = getULong(pos);
+
+ // Apple font
+ if (fmt == 0x00010000) {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding[i] = copyString(macGlyphNames[j]);
+ }
+
+ // Microsoft font
+ } else if (fmt == 0x00020000) {
+ stringIdx = 0;
+ stringPos = pos + 34 + 2*nGlyphs;
+ for (i = 0; i < 256; ++i) {
+ if (cmap[i] < nGlyphs) {
+ j = getUShort(pos + 34 + 2 * cmap[i]);
+ if (j < 258) {
+ encoding[i] = copyString(macGlyphNames[j]);
+ } else {
+ j -= 258;
+ if (j != stringIdx) {
+ for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs;
+ stringIdx < j;
+ ++stringIdx, stringPos += 1 + getByte(stringPos)) ;
+ }
+ n = getByte(stringPos);
+ s = new GString(file + stringPos + 1, n);
+ encoding[i] = copyString(s->getCString());
+ delete s;
+ ++stringIdx;
+ stringPos += 1 + n;
+ }
+ } else {
+ encoding[i] = copyString(macGlyphNames[0]);
+ }
+ }
+
+ // Apple subset
+ } else if (fmt == 0x000280000) {
+ for (i = 0; i < 256; ++i) {
+ if (cmap[i] < nGlyphs) {
+ j = i + getChar(pos + 32 + cmap[i]);
+ } else {
+ j = 0;
+ }
+ encoding[i] = copyString(macGlyphNames[j]);
+ }
+
+ // Ugh, just assume the Apple glyph set
+ } else {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding[i] = copyString(macGlyphNames[j]);
+ }
+ }
+
+ // no "post" table: assume the Apple glyph set
+ } else {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding[i] = copyString(macGlyphNames[j]);
+ }
+ }
+
+ return encoding;
+}
+
+void TrueTypeFontFile::convertToType42(char *name, char **encodingA,
+ CharCodeToUnicode *toUnicode,
+ GBool pdfFontHasEncoding, FILE *out) {
+ // write the header
+ fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+
+ // begin the font dictionary
+ fprintf(out, "10 dict begin\n");
+ fprintf(out, "/FontName /%s def\n", name);
+ fprintf(out, "/FontType 42 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ fprintf(out, "/PaintType 0 def\n");
+
+ // write the guts of the dictionary
+ cvtEncoding(encodingA, out);
+ cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, out);
+ cvtSfnts(out, NULL);
+
+ // end the dictionary and define the font
+ fprintf(out, "FontName currentdict end definefont pop\n");
+}
+
+void TrueTypeFontFile::convertToCIDType2(char *name, Gushort *cidMap,
+ int nCIDs, FILE *out) {
+ Gushort cid;
+ int i, j, k;
+
+ // write the header
+ fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+
+ // begin the font dictionary
+ fprintf(out, "20 dict begin\n");
+ fprintf(out, "/CIDFontName /%s def\n", name);
+ fprintf(out, "/CIDFontType 2 def\n");
+ fprintf(out, "/FontType 42 def\n");
+ fprintf(out, "/CIDSystemInfo 3 dict dup begin\n");
+ fprintf(out, " /Registry (Adobe) def\n");
+ fprintf(out, " /Ordering (Identity) def\n");
+ fprintf(out, " /Supplement 0 def\n");
+ fprintf(out, " end def\n");
+ fprintf(out, "/GDBytes 2 def\n");
+ if (cidMap) {
+ fprintf(out, "/CIDCount %d def\n", nCIDs);
+ if (nCIDs > 32767) {
+ fprintf(out, "/CIDMap [");
+ for (i = 0; i < nCIDs; i += 32768 - 16) {
+ fprintf(out, "<\n");
+ for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
+ fprintf(out, " ");
+ for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
+ cid = cidMap[i+j+k];
+ fprintf(out, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+ }
+ fprintf(out, "\n");
+ }
+ fprintf(out, " >");
+ }
+ fprintf(out, "\n");
+ fprintf(out, "] def\n");
+ } else {
+ fprintf(out, "/CIDMap <\n");
+ for (i = 0; i < nCIDs; i += 16) {
+ fprintf(out, " ");
+ for (j = 0; j < 16 && i+j < nCIDs; ++j) {
+ cid = cidMap[i+j];
+ fprintf(out, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+ }
+ fprintf(out, "\n");
+ }
+ fprintf(out, "> def\n");
+ }
+ } else {
+ // direct mapping - just fill the string(s) with s[i]=i
+ fprintf(out, "/CIDCount %d def\n", nGlyphs);
+ if (nGlyphs > 32767) {
+ fprintf(out, "/CIDMap [\n");
+ for (i = 0; i < nGlyphs; i += 32767) {
+ j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
+ fprintf(out, " %d string 0 1 %d {\n", 2 * j, j - 1);
+ fprintf(out, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
+ fprintf(out, " 1 index exch dup 2 mul 1 add exch %d add"
+ " 255 and put\n", i);
+ fprintf(out, " } for\n");
+ }
+ fprintf(out, "] def\n");
+ } else {
+ fprintf(out, "/CIDMap %d string\n", 2 * nGlyphs);
+ fprintf(out, " 0 1 %d {\n", nGlyphs - 1);
+ fprintf(out, " 2 copy dup 2 mul exch -8 bitshift put\n");
+ fprintf(out, " 1 index exch dup 2 mul 1 add exch 255 and put\n");
+ fprintf(out, " } for\n");
+ fprintf(out, "def\n");
+ }
+ }
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ fprintf(out, "/PaintType 0 def\n");
+ fprintf(out, "/Encoding [] readonly def\n");
+ fprintf(out, "/CharStrings 1 dict dup begin\n");
+ fprintf(out, " /.notdef 0 def\n");
+ fprintf(out, " end readonly def\n");
+
+ // write the guts of the dictionary
+ cvtSfnts(out, NULL);
+
+ // end the dictionary and define the font
+ fprintf(out, "CIDFontName currentdict end /CIDFont defineresource pop\n");
+}
+
+void TrueTypeFontFile::convertToType0(char *name, Gushort *cidMap,
+ int nCIDs, FILE *out) {
+ GString *sfntsName;
+ int n, i, j;
+
+ // write the Type 42 sfnts array
+ sfntsName = (new GString(name))->append("_sfnts");
+ cvtSfnts(out, sfntsName);
+ delete sfntsName;
+
+ // write the descendant Type 42 fonts
+ n = cidMap ? nCIDs : nGlyphs;
+ for (i = 0; i < n; i += 256) {
+ fprintf(out, "10 dict begin\n");
+ fprintf(out, "/FontName /%s_%02x def\n", name, i >> 8);
+ fprintf(out, "/FontType 42 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ fprintf(out, "/PaintType 0 def\n");
+ fprintf(out, "/sfnts %s_sfnts def\n", name);
+ fprintf(out, "/Encoding 256 array\n");
+ for (j = 0; j < 256 && i+j < n; ++j) {
+ fprintf(out, "dup %d /c%02x put\n", j, j);
+ }
+ fprintf(out, "readonly def\n");
+ fprintf(out, "/CharStrings 257 dict dup begin\n");
+ fprintf(out, "/.notdef 0 def\n");
+ for (j = 0; j < 256 && i+j < n; ++j) {
+ fprintf(out, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
+ }
+ fprintf(out, "end readonly def\n");
+ fprintf(out, "FontName currentdict end definefont pop\n");
+ }
+
+ // write the Type 0 parent font
+ fprintf(out, "16 dict begin\n");
+ fprintf(out, "/FontName /%s def\n", name);
+ fprintf(out, "/FontType 0 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FMapType 2 def\n");
+ fprintf(out, "/Encoding [\n");
+ for (i = 0; i < n; i += 256) {
+ fprintf(out, "%d\n", i >> 8);
+ }
+ fprintf(out, "] def\n");
+ fprintf(out, "/FDepVector [\n");
+ for (i = 0; i < n; i += 256) {
+ fprintf(out, "/%s_%02x findfont\n", name, i >> 8);
+ }
+ fprintf(out, "] def\n");
+ fprintf(out, "FontName currentdict end definefont pop\n");
+}
+
+int TrueTypeFontFile::getByte(int pos) {
+ if (pos < 0 || pos >= len) {
+ return 0;
+ }
+ return file[pos] & 0xff;
+}
+
+int TrueTypeFontFile::getChar(int pos) {
+ int x;
+
+ if (pos < 0 || pos >= len) {
+ return 0;
+ }
+ x = file[pos] & 0xff;
+ if (x & 0x80)
+ x |= 0xffffff00;
+ return x;
+}
+
+int TrueTypeFontFile::getUShort(int pos) {
+ int x;
+
+ if (pos < 0 || pos+1 >= len) {
+ return 0;
+ }
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ return x;
+}
+
+int TrueTypeFontFile::getShort(int pos) {
+ int x;
+
+ if (pos < 0 || pos+1 >= len) {
+ return 0;
+ }
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ if (x & 0x8000)
+ x |= 0xffff0000;
+ return x;
+}
+
+Guint TrueTypeFontFile::getULong(int pos) {
+ int x;
+
+ if (pos < 0 || pos+3 >= len) {
+ return 0;
+ }
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ x = (x << 8) + (file[pos+2] & 0xff);
+ x = (x << 8) + (file[pos+3] & 0xff);
+ return x;
+}
+
+double TrueTypeFontFile::getFixed(int pos) {
+ int x, y;
+
+ x = getShort(pos);
+ y = getUShort(pos+2);
+ return (double)x + (double)y / 65536;
+}
+
+int TrueTypeFontFile::seekTable(char *tag) {
+ int i;
+
+ for (i = 0; i < nTables; ++i) {
+ if (!strncmp(tableHdrs[i].tag, tag, 4)) {
+ return tableHdrs[i].offset;
+ }
+ }
+ return -1;
+}
+
+int TrueTypeFontFile::seekTableIdx(char *tag) {
+ int i;
+
+ for (i = 0; i < nTables; ++i) {
+ if (!strncmp(tableHdrs[i].tag, tag, 4)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void TrueTypeFontFile::cvtEncoding(char **encodingA, FILE *out) {
+ char *name;
+ int i;
+
+ fprintf(out, "/Encoding 256 array\n");
+ for (i = 0; i < 256; ++i) {
+ if (!(name = encodingA[i])) {
+ name = ".notdef";
+ }
+ fprintf(out, "dup %d /%s put\n", i, name);
+ }
+ fprintf(out, "readonly def\n");
+}
+
+void TrueTypeFontFile::cvtCharStrings(char **encodingA,
+ CharCodeToUnicode *toUnicode,
+ GBool pdfFontHasEncoding, FILE *out) {
+ int unicodeCmap, macRomanCmap, msSymbolCmap;
+ int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapOffset;
+ T42FontIndexMode mode;
+ char *name;
+ Unicode u;
+ int pos, i, j, k;
+
+ // always define '.notdef'
+ fprintf(out, "/CharStrings 256 dict dup begin\n");
+ fprintf(out, "/.notdef 0 def\n");
+
+ // if there's no 'cmap' table, punt
+ if ((pos = seekTable("cmap")) < 0) {
+ goto err;
+ }
+
+ // To match up with the Adobe-defined behaviour, we choose a cmap
+ // like this:
+ // 1. If the PDF font has an encoding:
+ // 1a. If the TrueType font has a Microsoft Unicode cmap, use it,
+ // and use the Unicode indexes, not the char codes.
+ // 1b. If the TrueType font has a Macintosh Roman cmap, use it,
+ // and reverse map the char names through MacRomanEncoding to
+ // get char codes.
+ // 2. If the PDF font does not have an encoding:
+ // 2a. If the TrueType font has a Macintosh Roman cmap, use it,
+ // and use char codes directly.
+ // 2b. If the TrueType font has a Microsoft Symbol cmap, use it,
+ // and use (0xf000 + char code).
+ // 3. If none of these rules apply, use the first cmap and hope for
+ // the best (this shouldn't happen).
+ nCmaps = getUShort(pos+2);
+ unicodeCmap = macRomanCmap = msSymbolCmap = -1;
+ cmapOffset = 0;
+ for (i = 0; i < nCmaps; ++i) {
+ cmapPlatform = getUShort(pos + 4 + 8*i);
+ cmapEncoding = getUShort(pos + 4 + 8*i + 2);
+ if (cmapPlatform == 3 && cmapEncoding == 1) {
+ unicodeCmap = i;
+ } else if (cmapPlatform == 1 && cmapEncoding == 0) {
+ macRomanCmap = i;
+ } else if (cmapPlatform == 3 && cmapEncoding == 0) {
+ msSymbolCmap = i;
+ }
+ }
+ i = 0;
+ mode = t42FontModeCharCode;
+ if (pdfFontHasEncoding) {
+ if (unicodeCmap >= 0) {
+ i = unicodeCmap;
+ mode = t42FontModeUnicode;
+ } else if (macRomanCmap >= 0) {
+ i = macRomanCmap;
+ mode = t42FontModeMacRoman;
+ }
+ } else {
+ if (macRomanCmap >= 0) {
+ i = macRomanCmap;
+ mode = t42FontModeCharCode;
+ } else if (msSymbolCmap >= 0) {
+ i = msSymbolCmap;
+ mode = t42FontModeCharCodeOffset;
+ cmapOffset = 0xf000;
+ }
+ }
+ cmapPlatform = getUShort(pos + 4 + 8*i);
+ cmapEncoding = getUShort(pos + 4 + 8*i + 2);
+ pos += getULong(pos + 4 + 8*i + 4);
+ cmapFmt = getUShort(pos);
+ if (cmapFmt != 0 && cmapFmt != 4 && cmapFmt != 6) {
+ error(-1, "Unimplemented cmap format (%d) in TrueType font file",
+ cmapFmt);
+ goto err;
+ }
+
+ // map char name to glyph index:
+ // 1. use encoding to map name to char code
+ // 2. use cmap to map char code to glyph index
+ j = 0; // make gcc happy
+ for (i = 0; i < 256; ++i) {
+ name = encodingA[i];
+ if (name && strcmp(name, ".notdef")) {
+ switch (mode) {
+ case t42FontModeUnicode:
+ toUnicode->mapToUnicode((CharCode)i, &u, 1);
+ j = (int)u;
+ break;
+ case t42FontModeCharCode:
+ j = i;
+ break;
+ case t42FontModeCharCodeOffset:
+ j = cmapOffset + i;
+ break;
+ case t42FontModeMacRoman:
+ j = globalParams->getMacRomanCharCode(name);
+ break;
+ }
+ // note: Distiller (maybe Adobe's PS interpreter in general)
+ // doesn't like TrueType fonts that have CharStrings entries
+ // which point to nonexistent glyphs, hence the (k < nGlyphs)
+ // test
+ if ((k = getCmapEntry(cmapFmt, pos, j)) > 0 &&
+ k < nGlyphs) {
+ fprintf(out, "/%s %d def\n", name, k);
+ }
+ }
+ }
+
+ err:
+ fprintf(out, "end readonly def\n");
+}
+
+int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) {
+ int cmapLen, cmapFirst;
+ int segCnt, segEnd, segStart, segDelta, segOffset;
+ int a, b, m, i;
+
+ switch (cmapFmt) {
+ case 0: // byte encoding table (Apple standard)
+ cmapLen = getUShort(pos + 2);
+ if (code >= cmapLen) {
+ return 0;
+ }
+ return getByte(pos + 6 + code);
+
+ case 4: // segment mapping to delta values (Microsoft standard)
+ segCnt = getUShort(pos + 6) / 2;
+ a = -1;
+ b = segCnt - 1;
+ segEnd = getUShort(pos + 14 + 2*b);
+ if (code > segEnd) {
+ // malformed font -- the TrueType spec requires the last segEnd
+ // to be 0xffff
+ return 0;
+ }
+ // invariant: seg[a].end < code <= seg[b].end
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ segEnd = getUShort(pos + 14 + 2*m);
+ if (segEnd < code) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ segStart = getUShort(pos + 16 + 2*segCnt + 2*b);
+ segDelta = getUShort(pos + 16 + 4*segCnt + 2*b);
+ segOffset = getUShort(pos + 16 + 6*segCnt + 2*b);
+ if (segOffset == 0) {
+ i = (code + segDelta) & 0xffff;
+ } else {
+ i = getUShort(pos + 16 + 6*segCnt + 2*b +
+ segOffset + 2 * (code - segStart));
+ if (i != 0) {
+ i = (i + segDelta) & 0xffff;
+ }
+ }
+ return i;
+
+ case 6: // trimmed table mapping
+ cmapFirst = getUShort(pos + 6);
+ cmapLen = getUShort(pos + 8);
+ if (code < cmapFirst || code >= cmapFirst + cmapLen) {
+ return 0;
+ }
+ return getUShort(pos + 10 + 2*(code - cmapFirst));
+
+ default:
+ // shouldn't happen - this is checked earlier
+ break;
+ }
+ return 0;
+}
+
+void TrueTypeFontFile::cvtSfnts(FILE *out, GString *name) {
+ TTFontTableHdr newTableHdrs[nT42Tables];
+ char tableDir[12 + nT42Tables*16];
+ char headTable[54];
+ int *origLocaTable;
+ char *locaTable;
+ int nNewTables;
+ Guint checksum;
+ int pos, glyfPos, length, glyphLength, pad;
+ int i, j, k;
+
+ // construct the 'head' table, zero out the font checksum
+ memcpy(headTable, file + seekTable("head"), 54);
+ headTable[8] = headTable[9] = headTable[10] = headTable[11] = (char)0;
+
+ // read the original 'loca' table and construct the new one
+ // (pad each glyph out to a multiple of 4 bytes)
+ origLocaTable = (int *)gmalloc((nGlyphs + 1) * sizeof(int));
+ pos = seekTable("loca");
+ for (i = 0; i <= nGlyphs; ++i) {
+ if (locaFmt) {
+ origLocaTable[i] = getULong(pos + 4*i);
+ } else {
+ origLocaTable[i] = 2 * getUShort(pos + 2*i);
+ }
+ }
+ locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
+ if (locaFmt) {
+ locaTable[0] = locaTable[1] = locaTable[2] = locaTable[3] = 0;
+ } else {
+ locaTable[0] = locaTable[1] = 0;
+ }
+ pos = 0;
+ for (i = 1; i <= nGlyphs; ++i) {
+ length = origLocaTable[i] - origLocaTable[i-1];
+ if (length & 3) {
+ length += 4 - (length & 3);
+ }
+ pos += length;
+ if (locaFmt) {
+ locaTable[4*i ] = (char)(pos >> 24);
+ locaTable[4*i+1] = (char)(pos >> 16);
+ locaTable[4*i+2] = (char)(pos >> 8);
+ locaTable[4*i+3] = (char) pos;
+ } else {
+ locaTable[2*i ] = (char)(pos >> 9);
+ locaTable[2*i+1] = (char)(pos >> 1);
+ }
+ }
+
+ // count the number of tables
+ nNewTables = 0;
+ for (i = 0; i < nT42Tables; ++i) {
+ if (t42Tables[i].required ||
+ seekTable(t42Tables[i].tag) >= 0) {
+ ++nNewTables;
+ }
+ }
+
+ // construct the new table headers, including table checksums
+ // (pad each table out to a multiple of 4 bytes)
+ pos = 12 + nNewTables*16;
+ k = 0;
+ for (i = 0; i < nT42Tables; ++i) {
+ length = -1;
+ checksum = 0; // make gcc happy
+ if (i == t42HeadTable) {
+ length = 54;
+ checksum = computeTableChecksum(headTable, 54);
+ } else if (i == t42LocaTable) {
+ length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+ checksum = computeTableChecksum(locaTable, length);
+ } else if (i == t42GlyfTable) {
+ length = 0;
+ checksum = 0;
+ glyfPos = seekTable("glyf");
+ for (j = 0; j < nGlyphs; ++j) {
+ glyphLength = origLocaTable[j+1] - origLocaTable[j];
+ pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0;
+ length += glyphLength + pad;
+ checksum += computeTableChecksum(file + glyfPos + origLocaTable[j],
+ glyphLength);
+ }
+ } else {
+ if ((j = seekTableIdx(t42Tables[i].tag)) >= 0) {
+ length = tableHdrs[j].length;
+ checksum = computeTableChecksum(file + tableHdrs[j].offset, length);
+ } else if (t42Tables[i].required) {
+ error(-1, "Embedded TrueType font is missing a required table ('%s')",
+ t42Tables[i].tag);
+ length = 0;
+ checksum = 0;
+ }
+ }
+ if (length >= 0) {
+ strncpy(newTableHdrs[k].tag, t42Tables[i].tag, 4);
+ newTableHdrs[k].checksum = checksum;
+ newTableHdrs[k].offset = pos;
+ newTableHdrs[k].length = length;
+ pad = (length & 3) ? 4 - (length & 3) : 0;
+ pos += length + pad;
+ ++k;
+ }
+ }
+
+ // construct the table directory
+ tableDir[0] = 0x00; // sfnt version
+ tableDir[1] = 0x01;
+ tableDir[2] = 0x00;
+ tableDir[3] = 0x00;
+ tableDir[4] = 0; // numTables
+ tableDir[5] = nNewTables;
+ tableDir[6] = 0; // searchRange
+ tableDir[7] = (char)128;
+ tableDir[8] = 0; // entrySelector
+ tableDir[9] = 3;
+ tableDir[10] = 0; // rangeShift
+ tableDir[11] = (char)(16 * nNewTables - 128);
+ pos = 12;
+ for (i = 0; i < nNewTables; ++i) {
+ tableDir[pos ] = newTableHdrs[i].tag[0];
+ tableDir[pos+ 1] = newTableHdrs[i].tag[1];
+ tableDir[pos+ 2] = newTableHdrs[i].tag[2];
+ tableDir[pos+ 3] = newTableHdrs[i].tag[3];
+ tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24);
+ tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16);
+ tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >> 8);
+ tableDir[pos+ 7] = (char) newTableHdrs[i].checksum;
+ tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24);
+ tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16);
+ tableDir[pos+10] = (char)(newTableHdrs[i].offset >> 8);
+ tableDir[pos+11] = (char) newTableHdrs[i].offset;
+ tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24);
+ tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16);
+ tableDir[pos+14] = (char)(newTableHdrs[i].length >> 8);
+ tableDir[pos+15] = (char) newTableHdrs[i].length;
+ pos += 16;
+ }
+
+ // compute the font checksum and store it in the head table
+ checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
+ for (i = 0; i < nNewTables; ++i) {
+ checksum += newTableHdrs[i].checksum;
+ }
+ checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
+ headTable[ 8] = (char)(checksum >> 24);
+ headTable[ 9] = (char)(checksum >> 16);
+ headTable[10] = (char)(checksum >> 8);
+ headTable[11] = (char) checksum;
+
+ // start the sfnts array
+ if (name) {
+ fprintf(out, "/%s [\n", name->getCString());
+ } else {
+ fprintf(out, "/sfnts [\n");
+ }
+
+ // write the table directory
+ dumpString(tableDir, 12 + nNewTables*16, out);
+
+ // write the tables
+ for (i = 0; i < nNewTables; ++i) {
+ if (i == t42HeadTable) {
+ dumpString(headTable, 54, out);
+ } else if (i == t42LocaTable) {
+ length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+ dumpString(locaTable, length, out);
+ } else if (i == t42GlyfTable) {
+ glyfPos = seekTable("glyf");
+ for (j = 0; j < nGlyphs; ++j) {
+ length = origLocaTable[j+1] - origLocaTable[j];
+ if (length > 0) {
+ dumpString(file + glyfPos + origLocaTable[j], length, out);
+ }
+ }
+ } else {
+ // length == 0 means the table is missing and the error was
+ // already reported during the construction of the table
+ // headers
+ if ((length = newTableHdrs[i].length) > 0) {
+ dumpString(file + seekTable(t42Tables[i].tag), length, out);
+ }
+ }
+ }
+
+ // end the sfnts array
+ fprintf(out, "] def\n");
+
+ gfree(origLocaTable);
+ gfree(locaTable);
+}
+
+void TrueTypeFontFile::dumpString(char *s, int length, FILE *out) {
+ int pad, i, j;
+
+ fprintf(out, "<");
+ for (i = 0; i < length; i += 32) {
+ for (j = 0; j < 32 && i+j < length; ++j) {
+ fprintf(out, "%02X", s[i+j] & 0xff);
+ }
+ if (i % (65536 - 32) == 65536 - 64) {
+ fprintf(out, ">\n<");
+ } else if (i+32 < length) {
+ fprintf(out, "\n");
+ }
+ }
+ if (length & 3) {
+ pad = 4 - (length & 3);
+ for (i = 0; i < pad; ++i) {
+ fprintf(out, "00");
+ }
+ }
+ // add an extra zero byte because the Adobe Type 42 spec says so
+ fprintf(out, "00>\n");
+}
+
+Guint TrueTypeFontFile::computeTableChecksum(char *data, int length) {
+ Guint checksum, word;
+ int i;
+
+ checksum = 0;
+ for (i = 0; i+3 < length; i += 4) {
+ word = ((data[i ] & 0xff) << 24) +
+ ((data[i+1] & 0xff) << 16) +
+ ((data[i+2] & 0xff) << 8) +
+ (data[i+3] & 0xff);
+ checksum += word;
+ }
+ if (length & 3) {
+ word = 0;
+ i = length & ~3;
+ switch (length & 3) {
+ case 3:
+ word |= (data[i+2] & 0xff) << 8;
+ case 2:
+ word |= (data[i+1] & 0xff) << 16;
+ case 1:
+ word |= (data[i ] & 0xff) << 24;
+ break;
+ }
+ checksum += word;
+ }
+ return checksum;
+}
+
+void TrueTypeFontFile::writeTTF(FILE *out) {
+ static char cmapTab[20] = {
+ 0, 0, // table version number
+ 0, 1, // number of encoding tables
+ 0, 1, // platform ID
+ 0, 0, // encoding ID
+ 0, 0, 0, 12, // offset of subtable
+ 0, 0, // subtable format
+ 0, 1, // subtable length
+ 0, 1, // subtable version
+ 0, // map char 0 -> glyph 0
+ 0 // pad to multiple of four bytes
+ };
+ static char nameTab[8] = {
+ 0, 0, // format
+ 0, 0, // number of name records
+ 0, 6, // offset to start of string storage
+ 0, 0 // pad to multiple of four bytes
+ };
+ static char postTab[32] = {
+ 0, 1, 0, 0, // format
+ 0, 0, 0, 0, // italic angle
+ 0, 0, // underline position
+ 0, 0, // underline thickness
+ 0, 0, 0, 0, // fixed pitch
+ 0, 0, 0, 0, // min Type 42 memory
+ 0, 0, 0, 0, // max Type 42 memory
+ 0, 0, 0, 0, // min Type 1 memory
+ 0, 0, 0, 0 // max Type 1 memory
+ };
+ GBool haveCmap, haveName, havePost;
+ GBool dirCmap, dirName, dirPost;
+ int nNewTables, nAllTables, pad;
+ char *tableDir;
+ Guint t, pos;
+ int i, j;
+
+ // check for missing tables
+ haveCmap = seekTable("cmap") >= 0;
+ haveName = seekTable("name") >= 0;
+ havePost = seekTable("post") >= 0;
+ nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1);
+ if (!nNewTables) {
+ // none are missing - write the TTF file as is
+ fwrite(file, 1, len, out);
+ return;
+ }
+
+ // construct the new table directory
+ nAllTables = nTables + nNewTables;
+ tableDir = (char *)gmalloc(12 + nAllTables * 16);
+ memcpy(tableDir, file, 12 + nTables * 16);
+ tableDir[4] = (char)((nAllTables >> 8) & 0xff);
+ tableDir[5] = (char)(nAllTables & 0xff);
+ for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ;
+ t = 1 << (4 + i);
+ tableDir[6] = (char)((t >> 8) & 0xff);
+ tableDir[7] = (char)(t & 0xff);
+ tableDir[8] = (char)((i >> 8) & 0xff);
+ tableDir[9] = (char)(i & 0xff);
+ t = nAllTables * 16 - t;
+ tableDir[10] = (char)((t >> 8) & 0xff);
+ tableDir[11] = (char)(t & 0xff);
+ dirCmap = haveCmap;
+ dirName = haveName;
+ dirPost = havePost;
+ j = 0;
+ pad = (len & 3) ? 4 - (len & 3) : 0;
+ pos = len + pad + 16 * nNewTables;
+ for (i = 0; i < nTables; ++i) {
+ if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) {
+ tableDir[12 + 16*j ] = 'c';
+ tableDir[12 + 16*j + 1] = 'm';
+ tableDir[12 + 16*j + 2] = 'a';
+ tableDir[12 + 16*j + 3] = 'p';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff);
+ pos += sizeof(cmapTab);
+ ++j;
+ dirCmap = gTrue;
+ }
+ if (!dirName && strncmp(tableHdrs[i].tag, "name", 4) > 0) {
+ tableDir[12 + 16*j ] = 'n';
+ tableDir[12 + 16*j + 1] = 'a';
+ tableDir[12 + 16*j + 2] = 'm';
+ tableDir[12 + 16*j + 3] = 'e';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff);
+ pos += sizeof(nameTab);
+ ++j;
+ dirName = gTrue;
+ }
+ if (!dirName && strncmp(tableHdrs[i].tag, "post", 4) > 0) {
+ tableDir[12 + 16*j ] = 'p';
+ tableDir[12 + 16*j + 1] = 'o';
+ tableDir[12 + 16*j + 2] = 's';
+ tableDir[12 + 16*j + 3] = 't';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff);
+ pos += sizeof(postTab);
+ ++j;
+ dirPost = gTrue;
+ }
+ memcpy(&tableDir[12 + 16*j], file + 12 + 16*i, 16);
+ t = tableHdrs[i].offset + nNewTables * 16;
+ tableDir[12 + 16*j + 8] = (char)((t >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((t >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((t >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( t & 0xff);
+ ++j;
+ }
+ if (!dirCmap) {
+ tableDir[12 + 16*j ] = 'c';
+ tableDir[12 + 16*j + 1] = 'm';
+ tableDir[12 + 16*j + 2] = 'a';
+ tableDir[12 + 16*j + 3] = 'p';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff);
+ pos += sizeof(cmapTab);
+ ++j;
+ dirCmap = gTrue;
+ }
+ if (!dirName) {
+ tableDir[12 + 16*j ] = 'n';
+ tableDir[12 + 16*j + 1] = 'a';
+ tableDir[12 + 16*j + 2] = 'm';
+ tableDir[12 + 16*j + 3] = 'e';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff);
+ pos += sizeof(nameTab);
+ ++j;
+ dirName = gTrue;
+ }
+ if (!dirPost) {
+ tableDir[12 + 16*j ] = 'p';
+ tableDir[12 + 16*j + 1] = 'o';
+ tableDir[12 + 16*j + 2] = 's';
+ tableDir[12 + 16*j + 3] = 't';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff);
+ pos += sizeof(postTab);
+ ++j;
+ dirPost = gTrue;
+ }
+
+ // write the table directory
+ fwrite(tableDir, 1, 12 + 16 * nAllTables, out);
+
+ // write the original tables
+ fwrite(file + 12 + 16*nTables, 1, len - (12 + 16*nTables), out);
+
+ // write the new tables
+ for (i = 0; i < pad; ++i) {
+ fputc((char)0, out);
+ }
+ if (!haveCmap) {
+ fwrite(cmapTab, 1, sizeof(cmapTab), out);
+ }
+ if (!haveName) {
+ fwrite(nameTab, 1, sizeof(nameTab), out);
+ }
+ if (!havePost) {
+ fwrite(postTab, 1, sizeof(postTab), out);
+ }
+
+ gfree(tableDir);
+}