//
// FontFile.cc
//
-// Copyright 1999 Derek B. Noonburg
+// Copyright 1999-2003 Glyph & Cog, LLC
//
//========================================================================
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
+#include <locale.h>
#include <math.h>
#include <stdlib.h>
#include <stddef.h>
+#include <stdarg.h>
#include <string.h>
#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"
//------------------------------------------------------------------------
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) ;
++p;
for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ;
*p2 = '\0';
- encoding->addChar(code, copyString(p));
+ encoding[code] = copyString(p);
}
}
}
line = line1;
}
//~ check for getinterval/putinterval junk
+ haveEncoding = gTrue;
} else {
line = nextLine(line, file + 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) {
+ int nameIdxPos, namePos, nameLen;
+
+ file = (Guchar *)fileA;
+ len = lenA;
+ name = NULL;
+ encoding = NULL;
+ ok = gFalse;
+
+ // some tools embed Type 1C fonts with an extra whitespace char at
+ // the beginning
+ if (len > 0 && file[0] != '\x01') {
+ ++file;
+ --len;
+ }
+
+ // make sure the header exists
+ if (len < 4) {
+ return;
+ }
+
+ // read name index (first font only)
+ nameIdxPos = file[2] & 0xff;
+ if ((namePos = getIndexValPos(nameIdxPos, 0, &nameLen)) < 0) {
+ return;
+ }
+ name = new GString((char *)&file[namePos], nameLen);
+
+ topDictIdxPos = getIndexEnd(nameIdxPos);
+ stringIdxPos = getIndexEnd(topDictIdxPos);
+ gsubrIdxPos = getIndexEnd(stringIdxPos);
+
+ ok = gTrue;
+}
+
+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) {
+ readEncoding();
+ }
+ return encoding;
+}
+
+void Type1CFontFile::readEncoding() {
char buf[256];
- Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
- Guchar *stringIdxPtr, *stringStartPtr;
- int topOffSize, idxOffSize, stringOffSize;
- int nFonts, nStrings, nGlyphs;
+ int idxPos, idxLen, pos;
+ 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;
-
- name = NULL;
- encoding = NULL;
- freeEnc = gTrue;
+ int i, j;
- // 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)
+ if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) {
+ return;
+ }
+ charset = enc = charstrings = 0;
i = 0;
- while (idxPtr0 < idxPtr1) {
- if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
- key = *idxPtr0++;
- if (key == 0x0c)
- key = (key << 8) | *idxPtr0++;
+ pos = idxPos;
+ while (pos < idxPos + idxLen) {
+ if (file[pos] <= 27 || file[pos] == 31) {
+ key = file[pos++];
+ if (key == 0x0c) {
+ if (pos >= idxPos + idxLen) {
+ return;
+ }
+ key = (key << 8) | file[pos++];
+ }
if (key == 0x0f) { // charset
charset = (int)op[0];
} else if (key == 0x10) { // encoding
}
i = 0;
} else {
- x = getNum(&idxPtr0, &isFP);
- if (i < 48)
+ x = getNum(&pos, &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(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++;
+ pos = enc;
+ if (pos < 0 || pos >= len) {
+ goto err0;
+ }
+ encFormat = file[pos++];
if ((encFormat & 0x7f) == 0) {
- nCodes = 1 + *topPtr++;
+ if (pos >= len) {
+ goto err0;
+ }
+ nCodes = 1 + file[pos++];
if (nCodes > nGlyphs) {
nCodes = nGlyphs;
}
+ if (pos + nCodes - 1 > len) {
+ goto err0;
+ }
for (i = 1; i < nCodes; ++i) {
- c = *topPtr++;
- getString(glyphNames[i], stringIdxPtr, stringStartPtr,
- stringOffSize, buf);
- encoding->addChar(c, copyString(buf));
+ c = file[pos++];
+ if (encoding[c]) {
+ gfree(encoding[c]);
+ }
+ encoding[c] = copyString(getString(glyphNames[i], buf));
}
} else if ((encFormat & 0x7f) == 1) {
- nRanges = *topPtr++;
+ if (pos >= len) {
+ goto err0;
+ }
+ nRanges = file[pos++];
+ if (pos + 2 * nRanges > len) {
+ goto err0;
+ }
nCodes = 1;
for (i = 0; i < nRanges; ++i) {
- c = *topPtr++;
- nLeft = *topPtr++;
+ c = file[pos++];
+ nLeft = file[pos++];
for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
- getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr,
- stringOffSize, buf);
- encoding->addChar(c, copyString(buf));
+ if (encoding[c]) {
+ gfree(encoding[c]);
+ }
+ encoding[c] = copyString(getString(glyphNames[nCodes], buf));
++nCodes;
++c;
}
}
}
if (encFormat & 0x80) {
- nSups = *topPtr++;
+ if (pos >= len) {
+ goto err0;
+ }
+ nSups = file[pos++];
+ if (pos + nSups * 3 > len) {
+ goto err0;
+ }
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 = file[pos++];
+ sid = getWord(pos, 2);
+ pos += 2;
+ if (encoding[c]) {
+ gfree(encoding[c]);
+ }
+ encoding[c] = copyString(getString(sid, buf));
}
}
}
- if (charset > 2)
+ err0:
+ if (charset < 0 || 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;
- 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;
+void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
+ void *outputStreamA) {
+ Type1CTopDict dict;
+ Type1CPrivateDict privateDict;
+ char buf[512], eBuf[256];
+ int idxPos, idxLen, pos;
+ int nGlyphs, nCodes, nRanges, nLeft, nSups;
Gushort *glyphNames;
- int charsetFormat, encFormat;
- int subrsOffset, nSubrs;
- int nCharStrings;
+ int encFormat, 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);
-
- // 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);
+ int i, j;
- // 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);
+ outputFunc = outputFuncA;
+ outputStream = outputStreamA;
-#if 1 //~
- // get global subrs
- int nGSubrs;
- int gSubrOffSize;
-
- nGSubrs = getWord(topPtr, 2);
- gSubrOffSize = topPtr[2];
- topPtr += 3;
-#endif
+ // read top dict (first font only)
+ readTopDict(&dict);
// write header and font dictionary, up to encoding
- fprintf(out, "%%!FontType1-1.0: %s", fontName);
+ (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17);
+ (*outputFunc)(outputStream, name->getCString(), name->getLength());
if (dict.version != 0) {
- fprintf(out, "%s",
- getString(dict.version, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.version, buf);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "\n");
- fprintf(out, "11 dict begin\n");
- fprintf(out, "/FontInfo 10 dict dup begin\n");
+ (*outputFunc)(outputStream, "\n", 1);
+ (*outputFunc)(outputStream, "11 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28);
if (dict.version != 0) {
- fprintf(out, "/version (%s) readonly def\n",
- getString(dict.version, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ (*outputFunc)(outputStream, "/version (", 10);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
}
if (dict.notice != 0) {
- fprintf(out, "/Notice (%s) readonly def\n",
- getString(dict.notice, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.notice, buf);
+ (*outputFunc)(outputStream, "/Notice (", 9);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
}
if (dict.copyright != 0) {
- fprintf(out, "/Copyright (%s) readonly def\n",
- getString(dict.copyright, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.copyright, buf);
+ (*outputFunc)(outputStream, "/Copyright (", 12);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
}
if (dict.fullName != 0) {
- fprintf(out, "/FullName (%s) readonly def\n",
- getString(dict.fullName, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.fullName, buf);
+ (*outputFunc)(outputStream, "/FullName (", 11);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
}
if (dict.familyName != 0) {
- fprintf(out, "/FamilyName (%s) readonly def\n",
- getString(dict.familyName, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.familyName, buf);
+ (*outputFunc)(outputStream, "/FamilyName (", 13);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
}
if (dict.weight != 0) {
- fprintf(out, "/Weight (%s) readonly def\n",
- getString(dict.weight, stringIdxPtr, stringStartPtr,
- stringOffSize, 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, "/PaintType %d def\n", dict.paintType);
- fprintf(out, "/FontType 1 def\n");
- fprintf(out, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
+ getString(dict.weight, buf);
+ (*outputFunc)(outputStream, "/Weight (", 9);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
+ }
+ if (dict.isFixedPitch) {
+ (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23);
+ } else {
+ (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24);
+ }
+ sprintf(buf, "/ItalicAngle %g def\n", dict.italicAngle);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, "/UnderlinePosition %g def\n", dict.underlinePosition);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, "/UnderlineThickness %g def\n", dict.underlineThickness);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "end readonly def\n", 17);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, name->getCString(), name->getLength());
+ (*outputFunc)(outputStream, " def\n", 5);
+ sprintf(buf, "/PaintType %d def\n", dict.paintType);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
+ sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] readonly 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] readonly def\n",
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, "/FontBBox [%g %g %g %g] readonly def\n",
dict.fontBBox[0], dict.fontBBox[1],
dict.fontBBox[2], dict.fontBBox[3]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth);
+ (*outputFunc)(outputStream, buf, strlen(buf));
if (dict.uniqueID != 0) {
- fprintf(out, "/UniqueID %d def\n", dict.uniqueID);
+ sprintf(buf, "/UniqueID %d def\n", dict.uniqueID);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
// get number of glyphs from charstrings index
- topPtr = (Guchar *)file + dict.charStrings;
- nGlyphs = getWord(topPtr, 2);
+ nGlyphs = getIndexLen(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 ");
+ (*outputFunc)(outputStream, "/Encoding ", 10);
if (dict.encoding == 0) {
- fprintf(out, "StandardEncoding def\n");
+ (*outputFunc)(outputStream, "StandardEncoding def\n", 21);
} else {
- fprintf(out, "256 array\n");
- fprintf(out, "0 1 255 {1 index exch /.notdef put} for\n");
+ (*outputFunc)(outputStream, "256 array\n", 10);
+ (*outputFunc)(outputStream,
+ "0 1 255 {1 index exch /.notdef put} for\n", 40);
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]) {
+ sprintf(buf, "dup %d /%s put\n", i, expertEncoding[i]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
}
} else {
- topPtr = (Guchar *)file + dict.encoding;
- encFormat = *topPtr++;
+ pos = dict.encoding;
+ if (pos < 0 || pos >= len) {
+ goto err0;
+ }
+ encFormat = file[pos++];
if ((encFormat & 0x7f) == 0) {
- nCodes = 1 + *topPtr++;
+ if (pos >= len) {
+ goto err0;
+ }
+ nCodes = 1 + file[pos++];
if (nCodes > nGlyphs) {
nCodes = nGlyphs;
}
+ if (pos + nCodes - 1 > len) {
+ goto err0;
+ }
for (i = 1; i < nCodes; ++i) {
- c = *topPtr++;
- fprintf(out, "dup %d /%s put\n", c,
- getString(glyphNames[i], stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ c = file[pos++];
+ sprintf(buf, "dup %d /", c);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ getString(glyphNames[i], buf);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, " put\n", 5);
}
} else if ((encFormat & 0x7f) == 1) {
- nRanges = *topPtr++;
+ if (pos >= len) {
+ goto err0;
+ }
+ nRanges = file[pos++];
+ if (pos + 2 * nRanges > len) {
+ goto err0;
+ }
nCodes = 1;
for (i = 0; i < nRanges; ++i) {
- c = *topPtr++;
- nLeft = *topPtr++;
+ c = file[pos++];
+ nLeft = file[pos++];
for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
- fprintf(out, "dup %d /%s put\n", c,
- getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ sprintf(buf, "dup %d /", c);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ getString(glyphNames[nCodes], buf);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, " put\n", 5);
++nCodes;
++c;
}
}
}
if (encFormat & 0x80) {
- nSups = *topPtr++;
+ if (pos >= len) {
+ goto err0;
+ }
+ nSups = file[pos++];
+ if (pos + nSups * 3 > len) {
+ goto err0;
+ }
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 = file[pos++];
+ sid = getWord(pos, 2);
+ pos += 2;
+ sprintf(buf, "dup %d /", c);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ getString(sid, buf);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, " put\n", 5);
}
}
+ err0:;
}
- fprintf(out, "readonly def\n");
+ (*outputFunc)(outputStream, "readonly def\n", 13);
}
- fprintf(out, "currentdict end\n");
- fprintf(out, "currentfile eexec\n");
+ (*outputFunc)(outputStream, "currentdict end\n", 16);
+
+ // start the binary section
+ (*outputFunc)(outputStream, "currentfile eexec\n", 18);
+ r1 = 55665;
+ line = 0;
// get private dictionary
eexecWrite("\x83\xca\x73\xd5");
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;
- i = 0;
- while (idxPtr0 < idxPtr1) {
- if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
- key = *idxPtr0++;
- if (key == 0x0c)
- key = (key << 8) | *idxPtr0++;
- switch (key) {
- case 0x0006:
- getDeltaInt(eBuf, "BlueValues", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0007:
- getDeltaInt(eBuf, "OtherBlues", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0008:
- getDeltaInt(eBuf, "FamilyBlues", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0009:
- getDeltaInt(eBuf, "FamilyOtherBlues", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0c09:
- sprintf(eBuf, "/BlueScale %g def\n", op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c0a:
- sprintf(eBuf, "/BlueShift %d def\n", (int)op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c0b:
- sprintf(eBuf, "/BlueFuzz %d def\n", (int)op[0]);
- eexecWrite(eBuf);
- break;
- case 0x000a:
- sprintf(eBuf, "/StdHW [%g] def\n", op[0]);
- eexecWrite(eBuf);
- break;
- case 0x000b:
- sprintf(eBuf, "/StdVW [%g] def\n", op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c0c:
- getDeltaReal(eBuf, "StemSnapH", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0c0d:
- getDeltaReal(eBuf, "StemSnapV", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0c0e:
- sprintf(eBuf, "/ForceBold %s def\n", op[0] ? "true" : "false");
- eexecWrite(eBuf);
- break;
- case 0x0c0f:
- sprintf(eBuf, "/ForceBoldThreshold %g def\n", op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c11:
- sprintf(eBuf, "/LanguageGroup %d def\n", (int)op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c12:
- sprintf(eBuf, "/ExpansionFactor %g def\n", op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c13:
- error(-1, "Got Type 1C InitialRandomSeed");
- break;
- case 0x0013:
- subrsOffset = (int)op[0];
- break;
- case 0x0014:
- defaultWidthX = op[0];
- defaultWidthXFP = fp[0];
- break;
- case 0x0015:
- nominalWidthX = op[0];
- nominalWidthXFP = fp[0];
- break;
- default:
- error(-1, "Uknown Type 1C private dict entry %04x", key);
- break;
- }
- i = 0;
- } else {
- x = getNum(&idxPtr0, &isFP);
- if (i < 48) {
- op[i] = x;
- fp[i++] = isFP;
- }
- }
- }
+ 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 (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");
- }
+ // set up subroutines
+ subrIdxPos = dict.privateOffset + privateDict.subrsOffset;
+ i = getIndexLen(gsubrIdxPos);
+ gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
+ i = getIndexLen(subrIdxPos);
+ subrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
// get CharStrings
- topPtr = (Guchar *)file + dict.charStrings;
- nCharStrings = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
+ nCharStrings = getIndexLen(dict.charStrings);
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);
+ if ((idxPos = getIndexValPos(dict.charStrings, i, &idxLen)) >= 0) {
+ eexecCvtGlyph(getString(glyphNames[i], buf), idxPos, idxLen);
+ }
}
eexecWrite("end\n");
eexecWrite("end\n");
eexecWrite("mark currentfile closefile\n");
// trailer
- if (line > 0)
- fputc('\n', out);
+ if (line > 0) {
+ (*outputFunc)(outputStream, "\n", 1);
+ }
for (i = 0; i < 8; ++i) {
- fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
+ (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65);
}
- fprintf(out, "cleartomark\n");
+ (*outputFunc)(outputStream, "cleartomark\n", 12);
// clean up
- if (dict.charset > 2)
+ delete privateDict.dictData;
+ if (dict.charset > 2) {
gfree(glyphNames);
- gfree(fontName);
+ }
}
-void Type1CFontConverter::eexecWrite(char *s) {
- Guchar *p;
- Guchar x;
+void Type1CFontFile::convertToCIDType0(char *psName,
+ FontFileOutputFunc outputFuncA,
+ void *outputStreamA) {
+ Type1CTopDict dict;
+ Type1CPrivateDict *privateDicts;
+ GString *charStrings;
+ int *charStringOffsets;
+ Gushort *charset;
+ int *cidMap;
+ Guchar *fdSelect;
+ int idxPos, idxLen, pos;
+ char buf[512], buf2[16];
+ int nGlyphs, nCIDs, gdBytes, nFDs;
+ int fdSelectFmt, nRanges, gid0, gid1, fd, offset;
+ int key;
+ double x;
+ GBool isFP;
+ int i, j, k, n;
- for (p = (Guchar *)s; *p; ++p) {
- x = *p ^ (r1 >> 8);
- r1 = (x + r1) * 52845 + 22719;
- fputc(hexChars[x >> 4], out);
- fputc(hexChars[x & 0x0f], out);
- line += 2;
- if (line == 64) {
- fputc('\n', out);
- line = 0;
- }
- }
-}
+ outputFunc = outputFuncA;
+ outputStream = outputStreamA;
-void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
- int nHints;
- int x;
- GBool first = gTrue;
- char eBuf[256];
- double d, dx, dy;
- GBool dFP;
- int i, k;
+ (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37);
- charBuf = new GString();
- charBuf->append((char)73);
- charBuf->append((char)58);
- charBuf->append((char)147);
- charBuf->append((char)134);
+ // read top dict (first font only)
+ readTopDict(&dict);
- i = 0;
- nOps = 0;
- nHints = 0;
- while (i < n) {
- if (s[i] == 12) {
- switch (s[i+1]) {
- case 0: // dotsection (should be Type 1 only?)
- //~ ignored
- break;
- case 34: // hflex
- if (nOps != 7) {
- error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps);
- }
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(0, gFalse);
- eexecDumpOp1(8);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[5], fp[5]);
- eexecDumpNum(-op[2], fp[2]);
- eexecDumpNum(op[6], fp[6]);
- eexecDumpNum(0, gFalse);
- eexecDumpOp1(8);
- break;
- case 35: // flex
- if (nOps != 13) {
- error(-1, "Wrong number of args (%d) to Type 2 flex", nOps);
- }
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpNum(op[5], fp[5]);
- eexecDumpOp1(8);
- eexecDumpNum(op[6], fp[6]);
- eexecDumpNum(op[7], fp[7]);
- eexecDumpNum(op[8], fp[8]);
- eexecDumpNum(op[9], fp[9]);
- eexecDumpNum(op[10], fp[10]);
- eexecDumpNum(op[11], fp[11]);
- eexecDumpOp1(8);
- break;
- case 36: // hflex1
- if (nOps != 9) {
- error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps);
- }
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpNum(0, gFalse);
- eexecDumpOp1(8);
- eexecDumpNum(op[5], fp[5]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[6], fp[6]);
- eexecDumpNum(op[7], fp[7]);
- eexecDumpNum(op[8], fp[8]);
- eexecDumpNum(-(op[1] + op[3] + op[7]), fp[1] | fp[3] | fp[7]);
- eexecDumpOp1(8);
- break;
- case 37: // flex1
- if (nOps != 11) {
- error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps);
- }
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpNum(op[5], fp[5]);
- eexecDumpOp1(8);
- eexecDumpNum(op[6], fp[6]);
- eexecDumpNum(op[7], fp[7]);
- eexecDumpNum(op[8], fp[8]);
- eexecDumpNum(op[9], fp[9]);
- dx = op[0] + op[2] + op[4] + op[6] + op[8];
- dy = op[1] + op[3] + op[5] + op[7] + op[9];
- if (fabs(dx) > fabs(dy)) {
- eexecDumpNum(op[10], fp[10]);
- eexecDumpNum(-dy, fp[1] | fp[3] | fp[5] | fp[7] | fp[9]);
+ // 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 {
+ if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) {
+ goto err0;
+ }
+ privateDicts = (Type1CPrivateDict *)
+ gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ for (i = 0; i < nFDs; ++i) {
+ privateDicts[i].dictData = NULL;
+ }
+ for (i = 0; i < nFDs; ++i) {
+ privateDicts[i].dictData = NULL;
+ if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) {
+ goto err1;
+ }
+ pos = idxPos;
+ j = 0;
+ while (pos < idxPos + idxLen) {
+ if (file[pos] <= 27 || file[pos] == 31) {
+ key = file[pos++];
+ if (key == 0x0c) {
+ if (pos >= idxPos + idxLen) {
+ goto err1;
+ }
+ key = (key << 8) | file[pos++];
+ }
+ if (key == 0x0012) {
+ readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
+ }
+ j = 0;
} else {
- eexecDumpNum(-dx, fp[0] | fp[2] | fp[4] | fp[6] | fp[8]);
- eexecDumpNum(op[10], fp[10]);
+ x = getNum(&pos, &isFP);
+ if (j < 48) {
+ op[j] = x;
+ fp[j++] = isFP;
+ }
}
- eexecDumpOp1(8);
- break;
- case 3: // and
- case 4: // or
- case 5: // not
- case 8: // store
- case 9: // abs
- case 10: // add
- case 11: // sub
- case 12: // div
- case 13: // load
- case 14: // neg
- case 15: // eq
- case 18: // drop
- case 20: // put
- case 21: // get
- case 22: // ifelse
- case 23: // random
- case 24: // mul
- case 26: // sqrt
- case 27: // dup
- case 28: // exch
- case 29: // index
- case 30: // roll
- error(-1, "Unimplemented Type 2 charstring op: 12.%d", s[i+1]);
- break;
- default:
- error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]);
- break;
}
- i += 2;
- nOps = 0;
- } else if (s[i] == 19) { // hintmask
- //~ ignored
- if (first) {
- cvtGlyphWidth(nOps == 1);
- first = gFalse;
+ 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;
}
- if (nOps > 0) {
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm",
- nOps);
- }
- nHints += nOps / 2;
+ }
+ }
+
+ // get the glyph count
+ if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) {
+ goto err1;
+ }
+
+ // read the FDSelect table
+ fdSelect = (Guchar *)gmalloc(nGlyphs);
+ if (dict.fdSelectOffset == 0) {
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ } else {
+ pos = dict.fdSelectOffset;
+ if (pos < 0 || pos >= len) {
+ goto err2;
+ }
+ fdSelectFmt = file[pos++];
+ if (fdSelectFmt == 0) {
+ if (pos + nGlyphs > len) {
+ goto err2;
}
- i += 1 + ((nHints + 7) >> 3);
- nOps = 0;
- } else if (s[i] == 20) { // cntrmask
- //~ ignored
- if (first) {
- cvtGlyphWidth(nOps == 1);
- first = gFalse;
+ memcpy(fdSelect, file + pos, nGlyphs);
+ } else if (fdSelectFmt == 3) {
+ if (pos + 4 > len) {
+ goto err2;
}
- if (nOps > 0) {
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm",
- nOps);
+ nRanges = getWord(pos, 2);
+ pos += 2;
+ gid0 = getWord(pos, 2);
+ pos += 2;
+ if (pos + nRanges * 3 > len) {
+ goto err2;
+ }
+ for (i = 1; i <= nRanges; ++i) {
+ fd = file[pos++];
+ gid1 = getWord(pos, 2);
+ pos += 2;
+ for (j = gid0; j < gid1; ++j) {
+ fdSelect[j] = fd;
}
- nHints += nOps / 2;
+ gid0 = gid1;
}
- i += 1 + ((nHints + 7) >> 3);
- nOps = 0;
- } else if (s[i] == 28) {
- x = (s[i+1] << 8) + s[i+2];
- if (x & 0x8000)
- x |= -1 << 15;
- if (nOps < 48) {
- fp[nOps] = gFalse;
- op[nOps++] = x;
+ } else {
+ error(-1, "Unknown FDSelect table format in CID font");
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
}
- i += 3;
- } else if (s[i] <= 31) {
- switch (s[i]) {
- case 4: // vmoveto
- if (first) {
- cvtGlyphWidth(nOps == 2);
- first = gFalse;
- }
- 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)
- 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]);
- eexecDumpOp1(5);
- }
- break;
- case 6: // hlineto
- 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)
- 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)
- 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]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(op[k+4], fp[k+4]);
- eexecDumpNum(op[k+5], fp[k+5]);
- eexecDumpOp1(8);
- }
- break;
- case 14: // endchar / seac
- if (first) {
- cvtGlyphWidth(nOps == 1 || nOps == 5);
- first = gFalse;
- }
- if (nOps == 4) {
- eexecDumpNum(0, 0);
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpOp2(6);
- } else if (nOps == 0) {
- eexecDumpOp1(14);
+ }
+ }
+
+ // 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;
+ }
+
+ // set up global subroutines
+ i = getIndexLen(gsubrIdxPos);
+ gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
+
+ // 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) {
+ if ((idxPos = getIndexValPos(dict.charStrings,
+ cidMap[i], &idxLen)) >= 0) {
+ j = fdSelect[cidMap[i]];
+ defaultWidthX = privateDicts[j].defaultWidthX;
+ defaultWidthXFP = privateDicts[j].defaultWidthXFP;
+ nominalWidthX = privateDicts[j].nominalWidthX;
+ nominalWidthXFP = privateDicts[j].nominalWidthXFP;
+ subrIdxPos = dict.privateOffset + privateDicts[j].subrsOffset;
+ k = getIndexLen(subrIdxPos);
+ subrBias = (k < 1240) ? 107 : (k < 33900) ? 1131 : 32768;
+ cvtGlyph(idxPos, idxLen, gTrue);
+ 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
+ (*outputFunc)(outputStream, "20 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/CIDFontName /", 14);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ (*outputFunc)(outputStream, " def\n", 5);
+ (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19);
+ (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
+ if (dict.registry > 0 && dict.ordering > 0) {
+ getString(dict.registry, buf);
+ (*outputFunc)(outputStream, " /Registry (", 13);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, ") def\n", 6);
+ getString(dict.ordering, buf);
+ (*outputFunc)(outputStream, " /Ordering (", 13);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, ") def\n", 6);
+ } else {
+ (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24);
+ (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27);
+ }
+ sprintf(buf, " /Supplement %d def\n", dict.supplement);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "end def\n", 8);
+ sprintf(buf, "/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]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, "/FontBBox [%g %g %g %g] def\n",
+ dict.fontBBox[0], dict.fontBBox[1],
+ dict.fontBBox[2], dict.fontBBox[3]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27);
+ (*outputFunc)(outputStream, " /FSType 8 def\n", 16);
+ (*outputFunc)(outputStream, "end def\n", 8);
+
+ // CIDFont-specific entries
+ sprintf(buf, "/CIDCount %d def\n", nCIDs);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15);
+ sprintf(buf, "/GDBytes %d def\n", gdBytes);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20);
+ if (dict.paintType != 0) {
+ sprintf(buf, "/PaintType %d def\n", dict.paintType);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+
+ // FDArray entry
+ sprintf(buf, "/FDArray %d array\n", nFDs);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ for (i = 0; i < nFDs; ++i) {
+ sprintf(buf, "dup %d 10 dict begin\n", i);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ sprintf(buf, "/PaintType %d def\n", dict.paintType);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23);
+ (*outputFunc)(outputStream, privateDicts[i].dictData->getCString(),
+ privateDicts[i].dictData->getLength());
+ (*outputFunc)(outputStream, "currentdict end def\n", 20);
+ (*outputFunc)(outputStream, "currentdict end put\n", 20);
+ }
+ (*outputFunc)(outputStream, "def\n", 4);
+
+ // start the binary section
+ offset = (nCIDs + 1) * (1 + gdBytes);
+ sprintf(buf, "(Hex) %d StartData\n",
+ offset + charStrings->getLength());
+ (*outputFunc)(outputStream, buf, strlen(buf));
+
+ // write the charstring offset (CIDMap) table
+ for (i = 0; i <= nCIDs; i += 6) {
+ for (j = 0; j < 6 && i+j <= nCIDs; ++j) {
+ if (i+j < nCIDs && 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) {
+ sprintf(buf2, "%02x", buf[k] & 0xff);
+ (*outputFunc)(outputStream, buf2, 2);
+ }
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+
+ // write the charstring data
+ n = charStrings->getLength();
+ for (i = 0; i < n; i += 32) {
+ for (j = 0; j < 32 && i+j < n; ++j) {
+ sprintf(buf, "%02x", charStrings->getChar(i+j) & 0xff);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ if (i + 32 >= n) {
+ (*outputFunc)(outputStream, ">", 1);
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+
+ gfree(charStringOffsets);
+ delete charStrings;
+ gfree(cidMap);
+ gfree(charset);
+ err2:
+ gfree(fdSelect);
+ err1:
+ for (i = 0; i < nFDs; ++i) {
+ if (privateDicts[i].dictData) {
+ delete privateDicts[i].dictData;
+ }
+ }
+ gfree(privateDicts);
+ err0:;
+}
+
+void Type1CFontFile::convertToType0(char *psName,
+ FontFileOutputFunc outputFuncA,
+ void *outputStreamA) {
+ Type1CTopDict dict;
+ Type1CPrivateDict *privateDicts;
+ Gushort *charset;
+ int *cidMap;
+ Guchar *fdSelect;
+ int idxPos, idxLen, pos;
+ char buf[512];
+ char eBuf[256];
+ int nGlyphs, nCIDs, nFDs;
+ int fdSelectFmt, nRanges, gid0, gid1, fd;
+ int key;
+ double x;
+ GBool isFP;
+ int i, j;
+
+ outputFunc = outputFuncA;
+ outputStream = outputStreamA;
+
+ // 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 {
+ if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) {
+ goto err0;
+ }
+ privateDicts = (Type1CPrivateDict *)
+ gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ for (i = 0; i < nFDs; ++i) {
+ privateDicts[i].dictData = NULL;
+ }
+ for (i = 0; i < nFDs; ++i) {
+ privateDicts[i].dictData = NULL;
+ if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) {
+ goto err1;
+ }
+ pos = idxPos;
+ j = 0;
+ while (pos < idxPos + idxLen) {
+ if (file[pos] <= 27 || file[pos] == 31) {
+ key = file[pos++];
+ if (key == 0x0c) {
+ if (pos >= idxPos + idxLen) {
+ goto err1;
+ }
+ key = (key << 8) | file[pos++];
+ }
+ if (key == 0x0012) {
+ readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
+ }
+ j = 0;
} else {
- error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps);
+ x = getNum(&pos, &isFP);
+ if (j < 48) {
+ op[j] = x;
+ fp[j++] = isFP;
+ }
}
- break;
- case 21: // rmoveto
- if (first) {
- cvtGlyphWidth(nOps == 3);
- first = gFalse;
+ }
+ 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
+ if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) {
+ goto err1;
+ }
+
+ // read the FDSelect table
+ fdSelect = (Guchar *)gmalloc(nGlyphs);
+ if (dict.fdSelectOffset == 0) {
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ } else {
+ pos = dict.fdSelectOffset;
+ if (pos < 0 || pos >= len) {
+ goto err2;
+ }
+ fdSelectFmt = file[pos++];
+ if (fdSelectFmt == 0) {
+ if (pos + nGlyphs > len) {
+ goto err2;
+ }
+ memcpy(fdSelect, file + pos, nGlyphs);
+ } else if (fdSelectFmt == 3) {
+ if (pos + 4 > len) {
+ goto err2;
+ }
+ nRanges = getWord(pos, 2);
+ pos += 2;
+ gid0 = getWord(pos, 2);
+ pos += 2;
+ if (pos + nRanges * 3 > len) {
+ goto err2;
+ }
+ for (i = 1; i <= nRanges; ++i) {
+ fd = file[pos++];
+ gid1 = getWord(pos, 2);
+ pos += 2;
+ for (j = gid0; j < gid1; ++j) {
+ fdSelect[j] = fd;
}
- 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);
+ 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;
+ }
+
+ // set up global subroutines
+ i = getIndexLen(gsubrIdxPos);
+ gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
+
+ // 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;
- case 22: // hmoveto
- if (first) {
- cvtGlyphWidth(nOps == 2);
- first = gFalse;
+ }
+ }
+
+ // font dictionary (unencrypted section)
+ (*outputFunc)(outputStream, "16 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ sprintf(buf, "_%02x def\n", i >> 8);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
+ sprintf(buf, "/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]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, "/FontBBox [%g %g %g %g] def\n",
+ dict.fontBBox[0], dict.fontBBox[1],
+ dict.fontBBox[2], dict.fontBBox[3]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, "/PaintType %d def\n", dict.paintType);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ if (dict.paintType != 0) {
+ sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
+ for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+ sprintf(buf, "dup %d /c%02x put\n", j, j);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ (*outputFunc)(outputStream, "readonly def\n", 13);
+ (*outputFunc)(outputStream, "currentdict end\n", 16);
+
+ // start the binary section
+ (*outputFunc)(outputStream, "currentfile eexec\n", 18);
+ 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;
+
+ // set up the subroutines
+ subrIdxPos = dict.privateOffset + privateDicts[fd].subrsOffset;
+ j = getIndexLen(subrIdxPos);
+ subrBias = (j < 1240) ? 107 : (j < 33900) ? 1131 : 32768;
+
+ // start the CharStrings
+ sprintf(eBuf, "2 index /CharStrings 256 dict dup begin\n");
+ eexecWrite(eBuf);
+
+ // write the .notdef CharString
+ if ((idxPos = getIndexValPos(dict.charStrings, 0, &idxLen)) >= 0) {
+ eexecCvtGlyph(".notdef", idxPos, idxLen);
+ }
+
+ // write the CharStrings
+ for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+ if (cidMap[i+j] >= 0) {
+ if ((idxPos = getIndexValPos(dict.charStrings,
+ cidMap[i+j], &idxLen)) >= 0) {
+ sprintf(buf, "c%02x", j);
+ eexecCvtGlyph(buf, idxPos, idxLen);
}
- 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)
- 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]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(op[k+4], fp[k+4]);
- eexecDumpNum(op[k+5], fp[k+5]);
- eexecDumpOp1(8);
+ }
+ }
+ 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) {
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+ for (j = 0; j < 8; ++j) {
+ (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65);
+ }
+ (*outputFunc)(outputStream, "cleartomark\n", 12);
+ }
+
+ // write the Type 0 parent font
+ (*outputFunc)(outputStream, "16 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ (*outputFunc)(outputStream, " def\n", 5);
+ (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
+ (*outputFunc)(outputStream, "/Encoding [\n", 12);
+ for (i = 0; i < nCIDs; i += 256) {
+ sprintf(buf, "%d\n", i >> 8);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "/FDepVector [\n", 14);
+ for (i = 0; i < nCIDs; i += 256) {
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ sprintf(buf, "_%02x findfont\n", i >> 8);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
+
+ // clean up
+ gfree(cidMap);
+ gfree(charset);
+ err2:
+ gfree(fdSelect);
+ err1:
+ for (i = 0; i < nFDs; ++i) {
+ if (privateDicts[i].dictData) {
+ delete privateDicts[i].dictData;
+ }
+ }
+ gfree(privateDicts);
+ err0:;
+}
+
+void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
+ int idxPos, idxLen, pos;
+ double x;
+ GBool isFP;
+ int key;
+ int i;
+
+ 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;
+ if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) {
+ return;
+ }
+ i = 0;
+ pos = idxPos;
+ while (pos < idxPos + idxLen) {
+ if (file[pos] <= 27 || file[pos] == 31) {
+ key = file[pos++];
+ if (key == 0x0c) {
+ if (pos >= idxPos + idxLen) {
+ break;
}
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k]);
- eexecDumpOp1(5);
- break;
- case 25: // rlinecurve
- 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]);
- eexecDumpOp1(5);
+ key = (key << 8) | file[pos++];
+ }
+ 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(&pos, &isFP);
+ if (i < 48) {
+ op[i] = x;
+ fp[i++] = isFP;
+ }
+ }
+ }
+}
+
+void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
+ int offset, int size) {
+ int pos;
+ 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;
+ if (offset < 0 || offset + size > len) {
+ return;
+ }
+ pos = offset;
+ i = 0;
+ while (pos < offset + size) {
+ if (file[pos] <= 27 || file[pos] == 31) {
+ key = file[pos++];
+ if (key == 0x0c) {
+ if (pos >= offset + size) {
+ break;
}
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(op[k+4], fp[k+4]);
- eexecDumpNum(op[k+5], fp[k+5]);
- eexecDumpOp1(8);
+ key = (key << 8) | file[pos++];
+ }
+ switch (key) {
+ case 0x0006:
+ getDeltaInt(eBuf, "BlueValues", op, i);
+ privateDict->dictData->append(eBuf);
break;
- case 26: // vvcurveto
- 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]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpOp1(8);
- k = 5;
- } else {
- k = 0;
- }
- for (; k < nOps; k += 4) {
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpOp1(8);
- }
+ case 0x0007:
+ getDeltaInt(eBuf, "OtherBlues", op, i);
+ privateDict->dictData->append(eBuf);
break;
- case 27: // hhcurveto
- 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]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpNum(0, gFalse);
- eexecDumpOp1(8);
- k = 5;
- } else {
- k = 0;
- }
- for (; k < nOps; k += 4) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(0, gFalse);
- eexecDumpOp1(8);
- }
+ case 0x0008:
+ getDeltaInt(eBuf, "FamilyBlues", op, i);
+ privateDict->dictData->append(eBuf);
break;
- case 30: // vhcurveto
- 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]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpOp1(30);
- } else {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpOp1(31);
- }
+ case 0x0009:
+ getDeltaInt(eBuf, "FamilyOtherBlues", op, i);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c09:
+ sprintf(eBuf, "/BlueScale %g def\n", op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c0a:
+ sprintf(eBuf, "/BlueShift %d def\n", (int)op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c0b:
+ sprintf(eBuf, "/BlueFuzz %d def\n", (int)op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x000a:
+ sprintf(eBuf, "/StdHW [%g] def\n", op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x000b:
+ sprintf(eBuf, "/StdVW [%g] def\n", op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c0c:
+ getDeltaReal(eBuf, "StemSnapH", op, i);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c0d:
+ getDeltaReal(eBuf, "StemSnapV", op, i);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c0e:
+ sprintf(eBuf, "/ForceBold %s def\n", op[0] ? "true" : "false");
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c0f:
+ sprintf(eBuf, "/ForceBoldThreshold %g def\n", op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c11:
+ sprintf(eBuf, "/LanguageGroup %d def\n", (int)op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c12:
+ sprintf(eBuf, "/ExpansionFactor %g def\n", op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c13:
+ error(-1, "Got Type 1C InitialRandomSeed");
+ break;
+ case 0x0013:
+ privateDict->subrsOffset = (int)op[0];
+ break;
+ case 0x0014:
+ privateDict->defaultWidthX = op[0];
+ privateDict->defaultWidthXFP = fp[0];
+ break;
+ case 0x0015:
+ privateDict->nominalWidthX = op[0];
+ privateDict->nominalWidthXFP = fp[0];
+ break;
+ default:
+ error(-1, "Unknown Type 1C private dict entry %04x", key);
+ break;
+ }
+ i = 0;
+ } else {
+ x = getNum(&pos, &isFP);
+ if (i < 48) {
+ op[i] = x;
+ fp[i++] = isFP;
+ }
+ }
+ }
+}
+
+Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
+ Gushort *glyphNames;
+ int pos;
+ int charsetFormat, c;
+ int nLeft, i, j;
+
+ if (charset == 0) {
+ glyphNames = type1CISOAdobeCharset;
+ } else if (charset == 1) {
+ glyphNames = type1CExpertCharset;
+ } else if (charset == 2) {
+ glyphNames = type1CExpertSubsetCharset;
+ } else {
+ glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
+ for (i = 0; i < nGlyphs; ++i) {
+ glyphNames[i] = 0;
+ }
+ pos = charset;
+ if (pos < 0 || pos >= len) {
+ goto err0;
+ }
+ charsetFormat = file[pos++];
+ if (charsetFormat == 0) {
+ if (pos + (nGlyphs - 1) * 2 >= len) {
+ goto err0;
+ }
+ for (i = 1; i < nGlyphs; ++i) {
+ glyphNames[i] = getWord(pos, 2);
+ pos += 2;
+ }
+ } else if (charsetFormat == 1) {
+ i = 1;
+ while (i < nGlyphs) {
+ if (pos + 3 > len) {
+ goto err0;
}
- if (k == nOps-5) {
- if (k % 8 == 0) {
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(op[k+4], fp[k+4]);
- } else {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+4], fp[k+4]);
- eexecDumpNum(op[k+3], fp[k+3]);
- }
- eexecDumpOp1(8);
+ c = getWord(pos, 2);
+ pos += 2;
+ nLeft = file[pos++];
+ for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
+ glyphNames[i++] = c++;
}
- break;
- case 31: // hvcurveto
- 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]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpOp1(31);
- } else {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpOp1(30);
- }
+ }
+ } else if (charsetFormat == 2) {
+ i = 1;
+ while (i < nGlyphs) {
+ if (pos + 4 > len) {
+ goto err0;
}
- if (k == nOps-5) {
- if (k % 8 == 0) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+4], fp[k+4]);
- eexecDumpNum(op[k+3], fp[k+3]);
- } else {
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(op[k+4], fp[k+4]);
- }
- eexecDumpOp1(8);
+ c = getWord(pos, 2);
+ pos += 2;
+ nLeft = getWord(pos, 2);
+ pos += 2;
+ for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
+ glyphNames[i++] = c++;
}
+ }
+ }
+ }
+ err0:
+ return glyphNames;
+}
+
+void Type1CFontFile::eexecWrite(char *s) {
+ Guchar *p;
+ Guchar x;
+
+ for (p = (Guchar *)s; *p; ++p) {
+ x = *p ^ (r1 >> 8);
+ r1 = (x + r1) * 52845 + 22719;
+ (*outputFunc)(outputStream, &hexChars[x >> 4], 1);
+ (*outputFunc)(outputStream, &hexChars[x & 0x0f], 1);
+ line += 2;
+ if (line == 64) {
+ (*outputFunc)(outputStream, "\n", 1);
+ line = 0;
+ }
+ }
+}
+
+void Type1CFontFile::eexecCvtGlyph(char *glyphName, int pos, int n) {
+ char eBuf[256];
+
+ cvtGlyph(pos, n, gTrue);
+ sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength());
+ eexecWrite(eBuf);
+ eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
+ eexecWrite(" ND\n");
+ delete charBuf;
+}
+
+void Type1CFontFile::cvtGlyph(int pos, int n, GBool top) {
+ int x;
+ int subrPos, subrLen;
+ double d, dx, dy;
+ GBool dFP;
+ Gushort r2;
+ Guchar byte;
+ int i, k;
+
+ if (pos < 0 || pos + n > len) {
+ return;
+ }
+
+ if (top) {
+ charBuf = new GString();
+ charBuf->append((char)73);
+ charBuf->append((char)58);
+ charBuf->append((char)147);
+ charBuf->append((char)134);
+ nOps = 0;
+ nHints = 0;
+ firstOp = gTrue;
+ }
+
+ i = pos;
+ while (i < pos + n) {
+ if (file[i] == 12) {
+ if (i + 2 > pos + n) {
break;
- case 1: // hstem
- if (first) {
- cvtGlyphWidth(nOps & 1);
- first = gFalse;
- }
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps);
+ }
+ switch (file[i+1]) {
+ case 0: // dotsection (should be Type 1 only?)
+ // ignored
+ break;
+ case 34: // hflex
+ if (nOps != 7) {
+ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps);
}
- d = 0;
- dFP = gFalse;
- for (k = 0; k < nOps; k += 2) {
- if (op[k+1] < 0) {
- d += op[k] + op[k+1];
- dFP |= fp[k] | fp[k+1];
- eexecDumpNum(d, dFP);
- eexecDumpNum(-op[k+1], fp[k+1]);
- } else {
- d += op[k];
- dFP |= fp[k];
- eexecDumpNum(d, dFP);
- eexecDumpNum(op[k+1], fp[k+1]);
- d += op[k+1];
- dFP |= fp[k+1];
- }
- eexecDumpOp1(1);
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpNum(-op[2], fp[2]);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ break;
+ case 35: // flex
+ if (nOps != 13) {
+ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps);
}
- nHints += nOps / 2;
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(op[7], fp[7]);
+ eexecDumpNum(op[8], fp[8]);
+ eexecDumpNum(op[9], fp[9]);
+ eexecDumpNum(op[10], fp[10]);
+ eexecDumpNum(op[11], fp[11]);
+ eexecDumpOp1(8);
break;
- case 3: // vstem
- if (first) {
- cvtGlyphWidth(nOps & 1);
- first = gFalse;
+ case 36: // hflex1
+ if (nOps != 9) {
+ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps);
}
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps);
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(op[7], fp[7]);
+ eexecDumpNum(op[8], fp[8]);
+ eexecDumpNum(-(op[1] + op[3] + op[7]), fp[1] | fp[3] | fp[7]);
+ eexecDumpOp1(8);
+ break;
+ case 37: // flex1
+ if (nOps != 11) {
+ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(op[7], fp[7]);
+ eexecDumpNum(op[8], fp[8]);
+ eexecDumpNum(op[9], fp[9]);
+ dx = op[0] + op[2] + op[4] + op[6] + op[8];
+ dy = op[1] + op[3] + op[5] + op[7] + op[9];
+ if (fabs(dx) > fabs(dy)) {
+ eexecDumpNum(op[10], fp[10]);
+ eexecDumpNum(-dy, fp[1] | fp[3] | fp[5] | fp[7] | fp[9]);
+ } else {
+ eexecDumpNum(-dx, fp[0] | fp[2] | fp[4] | fp[6] | fp[8]);
+ eexecDumpNum(op[10], fp[10]);
+ }
+ eexecDumpOp1(8);
+ break;
+ case 3: // and
+ case 4: // or
+ case 5: // not
+ case 8: // store
+ case 9: // abs
+ case 10: // add
+ case 11: // sub
+ case 12: // div
+ case 13: // load
+ case 14: // neg
+ case 15: // eq
+ case 18: // drop
+ case 20: // put
+ case 21: // get
+ case 22: // ifelse
+ case 23: // random
+ case 24: // mul
+ case 26: // sqrt
+ case 27: // dup
+ case 28: // exch
+ case 29: // index
+ case 30: // roll
+ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]);
+ break;
+ default:
+ error(-1, "Illegal Type 2 charstring op: 12.%d", file[i+1]);
+ break;
+ }
+ i += 2;
+ nOps = 0;
+ } else if (file[i] == 19) { // hintmask
+ // ignored
+ if (firstOp) {
+ cvtGlyphWidth(nOps == 1);
+ firstOp = gFalse;
+ }
+ if (nOps > 0) {
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm",
+ nOps);
+ }
+ nHints += nOps / 2;
+ }
+ i += 1 + ((nHints + 7) >> 3);
+ nOps = 0;
+ } else if (file[i] == 20) { // cntrmask
+ // ignored
+ if (firstOp) {
+ cvtGlyphWidth(nOps == 1);
+ firstOp = gFalse;
+ }
+ if (nOps > 0) {
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm",
+ nOps);
+ }
+ nHints += nOps / 2;
+ }
+ i += 1 + ((nHints + 7) >> 3);
+ nOps = 0;
+ } else if (file[i] == 28) {
+ if (i + 3 > len) {
+ break;
+ }
+ x = (file[i+1] << 8) + file[i+2];
+ if (x & 0x8000) {
+ x |= -1 << 15;
+ }
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = x;
+ }
+ i += 3;
+ } else if (file[i] == 10) { // callsubr
+ if (nOps >= 1) {
+ k = subrBias + (int)op[nOps - 1];
+ --nOps;
+ if ((subrPos = getIndexValPos(subrIdxPos, k, &subrLen)) >= 0) {
+ cvtGlyph(subrPos, subrLen, gFalse);
+ }
+ } else {
+ error(-1, "Too few args to Type 2 callsubr");
+ }
+ // don't clear the stack
+ ++i;
+ } else if (file[i] == 29) { // callgsubr
+ if (nOps >= 1) {
+ k = gsubrBias + (int)op[nOps - 1];
+ --nOps;
+ if ((subrPos = getIndexValPos(gsubrIdxPos, k, &subrLen)) >= 0) {
+ cvtGlyph(subrPos, subrLen, gFalse);
+ }
+ } else {
+ error(-1, "Too few args to Type 2 callgsubr");
+ }
+ // don't clear the stack
+ ++i;
+ } else if (file[i] == 11) { // return
+ // don't clear the stack
+ ++i;
+ } else if (file[i] <= 31) {
+ switch (file[i]) {
+ case 4: // vmoveto
+ if (firstOp) {
+ cvtGlyphWidth(nOps == 2);
+ firstOp = gFalse;
+ }
+ 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) {
+ 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]);
+ eexecDumpOp1(5);
+ }
+ break;
+ case 6: // hlineto
+ 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) {
+ 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) {
+ 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]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+5], fp[k+5]);
+ eexecDumpOp1(8);
+ }
+ break;
+ case 14: // endchar / seac
+ if (firstOp) {
+ cvtGlyphWidth(nOps == 1 || nOps == 5);
+ firstOp = gFalse;
+ }
+ if (nOps == 4) {
+ eexecDumpNum(0, 0);
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpOp2(6);
+ } else if (nOps == 0) {
+ eexecDumpOp1(14);
+ } else {
+ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps);
+ }
+ break;
+ case 21: // rmoveto
+ if (firstOp) {
+ cvtGlyphWidth(nOps == 3);
+ firstOp = gFalse;
+ }
+ 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);
+ break;
+ case 22: // hmoveto
+ if (firstOp) {
+ cvtGlyphWidth(nOps == 2);
+ firstOp = gFalse;
+ }
+ 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) {
+ 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]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+5], fp[k+5]);
+ eexecDumpOp1(8);
+ }
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k]);
+ eexecDumpOp1(5);
+ break;
+ case 25: // rlinecurve
+ 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]);
+ eexecDumpOp1(5);
+ }
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+5], fp[k+5]);
+ eexecDumpOp1(8);
+ break;
+ case 26: // vvcurveto
+ 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]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpOp1(8);
+ k = 5;
+ } else {
+ k = 0;
+ }
+ for (; k < nOps; k += 4) {
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(8);
+ }
+ break;
+ case 27: // hhcurveto
+ 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]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ k = 5;
+ } else {
+ k = 0;
+ }
+ for (; k < nOps; k += 4) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ }
+ break;
+ case 30: // vhcurveto
+ 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]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(30);
+ } else {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(31);
+ }
+ }
+ if (k == nOps-5) {
+ if (k % 8 == 0) {
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ } else {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ }
+ eexecDumpOp1(8);
+ }
+ break;
+ case 31: // hvcurveto
+ 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]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(31);
+ } else {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(30);
+ }
+ }
+ if (k == nOps-5) {
+ if (k % 8 == 0) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ } else {
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ }
+ eexecDumpOp1(8);
+ }
+ break;
+ case 1: // hstem
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1);
+ firstOp = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps);
+ }
+ d = 0;
+ dFP = gFalse;
+ for (k = 0; k < nOps; k += 2) {
+ if (op[k+1] < 0) {
+ d += op[k] + op[k+1];
+ dFP |= fp[k] | fp[k+1];
+ eexecDumpNum(d, dFP);
+ eexecDumpNum(-op[k+1], fp[k+1]);
+ } else {
+ d += op[k];
+ dFP |= fp[k];
+ eexecDumpNum(d, dFP);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ d += op[k+1];
+ dFP |= fp[k+1];
+ }
+ eexecDumpOp1(1);
+ }
+ nHints += nOps / 2;
+ break;
+ case 3: // vstem
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1);
+ firstOp = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps);
}
d = 0;
dFP = gFalse;
eexecDumpNum(d, dFP);
eexecDumpNum(-op[k+1], fp[k+1]);
} else {
- d += op[k];
- dFP |= fp[k];
- eexecDumpNum(d, dFP);
- eexecDumpNum(op[k+1], fp[k+1]);
- d += op[k+1];
- dFP |= fp[k+1];
+ d += op[k];
+ dFP |= fp[k];
+ eexecDumpNum(d, dFP);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ d += op[k+1];
+ dFP |= fp[k+1];
+ }
+ eexecDumpOp1(3);
+ }
+ nHints += nOps / 2;
+ break;
+ case 18: // hstemhm
+ // ignored
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1);
+ firstOp = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps);
+ }
+ nHints += nOps / 2;
+ break;
+ case 23: // vstemhm
+ // ignored
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1);
+ firstOp = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps);
+ }
+ nHints += nOps / 2;
+ break;
+ case 16: // blend
+ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]);
+ break;
+ default:
+ error(-1, "Illegal Type 2 charstring op: %d", file[i]);
+ break;
+ }
+ ++i;
+ nOps = 0;
+ } else if (file[i] <= 246) {
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = (int)file[i] - 139;
+ }
+ ++i;
+ } else if (file[i] <= 250) {
+ if (i + 2 > len) {
+ break;
+ }
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = (((int)file[i] - 247) << 8) + (int)file[i+1] + 108;
+ }
+ i += 2;
+ } else if (file[i] <= 254) {
+ if (i + 2 > len) {
+ break;
+ }
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = -(((int)file[i] - 251) << 8) - (int)file[i+1] - 108;
+ }
+ i += 2;
+ } else {
+ if (i + 5 > len) {
+ break;
+ }
+ x = (file[i+1] << 24) | (file[i+2] << 16) | (file[i+3] << 8) | file[i+4];
+ if (x & 0x80000000) {
+ x |= -1 << 31;
+ }
+ if (nOps < 48) {
+ fp[nOps] = gTrue;
+ op[nOps++] = (double)x / 65536.0;
+ }
+ i += 5;
+ }
+ }
+
+ // charstring encryption
+ if (top) {
+ 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 Type1CFontFile::cvtGlyphWidth(GBool useOp) {
+ double w;
+ GBool wFP;
+ int i;
+
+ if (useOp) {
+ w = nominalWidthX + op[0];
+ wFP = nominalWidthXFP | fp[0];
+ for (i = 1; i < nOps; ++i) {
+ op[i-1] = op[i];
+ fp[i-1] = fp[i];
+ }
+ --nOps;
+ } else {
+ w = defaultWidthX;
+ wFP = defaultWidthXFP;
+ }
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(w, wFP);
+ eexecDumpOp1(13);
+}
+
+void Type1CFontFile::eexecDumpNum(double x, GBool fpA) {
+ Guchar buf[12];
+ int y, n;
+
+ n = 0;
+ if (fpA) {
+ if (x >= -32768 && x < 32768) {
+ y = (int)(x * 256.0);
+ buf[0] = 255;
+ buf[1] = (Guchar)(y >> 24);
+ buf[2] = (Guchar)(y >> 16);
+ buf[3] = (Guchar)(y >> 8);
+ buf[4] = (Guchar)y;
+ buf[5] = 255;
+ buf[6] = 0;
+ buf[7] = 0;
+ buf[8] = 1;
+ buf[9] = 0;
+ buf[10] = 12;
+ buf[11] = 12;
+ n = 12;
+ } else {
+ error(-1, "Type 2 fixed point constant out of range");
+ }
+ } else {
+ y = (int)x;
+ if (y >= -107 && y <= 107) {
+ buf[0] = (Guchar)(y + 139);
+ n = 1;
+ } else if (y > 107 && y <= 1131) {
+ y -= 108;
+ buf[0] = (Guchar)((y >> 8) + 247);
+ buf[1] = (Guchar)(y & 0xff);
+ n = 2;
+ } else if (y < -107 && y >= -1131) {
+ y = -y - 108;
+ buf[0] = (Guchar)((y >> 8) + 251);
+ buf[1] = (Guchar)(y & 0xff);
+ n = 2;
+ } else {
+ buf[0] = 255;
+ buf[1] = (Guchar)(y >> 24);
+ buf[2] = (Guchar)(y >> 16);
+ buf[3] = (Guchar)(y >> 8);
+ buf[4] = (Guchar)y;
+ n = 5;
+ }
+ }
+ charBuf->append((char *)buf, n);
+}
+
+void Type1CFontFile::eexecDumpOp1(int opA) {
+ charBuf->append((char)opA);
+}
+
+void Type1CFontFile::eexecDumpOp2(int opA) {
+ charBuf->append((char)12);
+ charBuf->append((char)opA);
+}
+
+void Type1CFontFile::eexecWriteCharstring(Guchar *s, int n) {
+ Guchar x;
+ int i;
+
+ // eexec encryption
+ for (i = 0; i < n; ++i) {
+ x = s[i] ^ (r1 >> 8);
+ r1 = (x + r1) * 52845 + 22719;
+ (*outputFunc)(outputStream, &hexChars[x >> 4], 1);
+ (*outputFunc)(outputStream, &hexChars[x & 0x0f], 1);
+ line += 2;
+ if (line == 64) {
+ (*outputFunc)(outputStream, "\n", 1);
+ line = 0;
+ }
+ }
+}
+
+void Type1CFontFile::getDeltaInt(char *buf, char *key, double *opA,
+ int n) {
+ int x, i;
+
+ sprintf(buf, "/%s [", key);
+ buf += strlen(buf);
+ x = 0;
+ for (i = 0; i < n; ++i) {
+ x += (int)opA[i];
+ sprintf(buf, "%s%d", i > 0 ? " " : "", x);
+ buf += strlen(buf);
+ }
+ sprintf(buf, "] def\n");
+}
+
+void Type1CFontFile::getDeltaReal(char *buf, char *key, double *opA,
+ int n) {
+ double x;
+ int i;
+
+ sprintf(buf, "/%s [", key);
+ buf += strlen(buf);
+ x = 0;
+ for (i = 0; i < n; ++i) {
+ x += opA[i];
+ sprintf(buf, "%s%g", i > 0 ? " " : "", x);
+ buf += strlen(buf);
+ }
+ sprintf(buf, "] def\n");
+}
+
+int Type1CFontFile::getIndexLen(int indexPos) {
+ if (indexPos + 2 > len) {
+ return -1;
+ }
+ return (int)getWord(indexPos, 2);
+}
+
+int Type1CFontFile::getIndexValPos(int indexPos, int i, int *valLen) {
+ int n, offSize, idxStartPos;
+ int pos0, pos1;
+
+ if (indexPos < 0 || indexPos + 3 > len) {
+ return -1;
+ }
+ n = (int)getWord(indexPos, 2);
+ if (i >= n) {
+ return -1;
+ }
+ offSize = file[indexPos + 2];
+ if (offSize < 1 || offSize > 4) {
+ return -1;
+ }
+ idxStartPos = indexPos + 3 + (n + 1) * offSize - 1;
+ if (idxStartPos >= len) {
+ return -1;
+ }
+ pos0 = idxStartPos + getWord(indexPos + 3 + i * offSize, offSize);
+ pos1 = idxStartPos + getWord(indexPos + 3 + (i + 1) * offSize, offSize);
+ if (pos0 < 0 || pos0 >= len || pos1 < pos0 || pos1 > len) {
+ return -1;
+ }
+ *valLen = pos1 - pos0;
+ return pos0;
+}
+
+int Type1CFontFile::getIndexEnd(int indexPos) {
+ int n, offSize, idxStartPos;
+
+ if (indexPos + 3 > len) {
+ return -1;
+ }
+ n = (int)getWord(indexPos, 2);
+ offSize = file[indexPos + 2];
+ idxStartPos = indexPos + 3 + (n + 1) * offSize - 1;
+ if (idxStartPos >= len) {
+ return -1;
+ }
+ return idxStartPos + getWord(indexPos + 3 + n * offSize, offSize);
+}
+
+Guint Type1CFontFile::getWord(int pos, int size) {
+ Guint x;
+ int i;
+
+ if (pos < 0 || pos + size > len) {
+ return 0;
+ }
+ x = 0;
+ for (i = 0; i < size; ++i) {
+ x = (x << 8) + file[pos + i];
+ }
+ return x;
+}
+
+double Type1CFontFile::getNum(int *pos, GBool *isFP) {
+ static char nybChars[16] = "0123456789.ee -";
+ int b0, b, nyb0, nyb1;
+ double x;
+ char buf[65];
+ int i;
+
+ x = 0;
+ *isFP = gFalse;
+ if (*pos >= len) {
+ return 0;
+ }
+ b0 = file[*pos];
+ if (b0 < 28) {
+ x = 0;
+ } else if (b0 == 28) {
+ if (*pos + 3 <= len) {
+ x = (file[*pos + 1] << 8) + file[*pos + 2];
+ *pos += 3;
+ }
+ } else if (b0 == 29) {
+ if (*pos + 5 <= len) {
+ x = (file[*pos + 1] << 24) + (file[*pos + 2] << 16) +
+ (file[*pos + 3] << 8) + file[*pos + 4];
+ *pos += 5;
+ }
+ } else if (b0 == 30) {
+ *pos += 1;
+ i = 0;
+ do {
+ if (*pos >= len) {
+ break;
+ }
+ b = file[(*pos)++];
+ 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';
+ {
+ char *theLocale = setlocale(LC_NUMERIC, "C");
+ x = atof(buf);
+ setlocale(LC_NUMERIC, theLocale);
+ }
+ *isFP = gTrue;
+ } else if (b0 == 31) {
+ x = 0;
+ } else if (b0 < 247) {
+ x = b0 - 139;
+ *pos += 1;
+ } else if (b0 < 251) {
+ if (*pos + 2 <= len) {
+ x = ((b0 - 247) << 8) + file[*pos + 1] + 108;
+ *pos += 2;
+ }
+ } else {
+ if (*pos + 2 <= len) {
+ x = -((b0 - 251) << 8) - file[*pos + 1] - 108;
+ *pos += 2;
+ }
+ }
+ return x;
+}
+
+char *Type1CFontFile::getString(int sid, char *buf) {
+ int idxPos, n;
+
+ if (sid < 391) {
+ strcpy(buf, type1CStdStrings[sid]);
+ } else {
+ sid -= 391;
+ idxPos = getIndexValPos(stringIdxPos, sid, &n);
+ if (idxPos < 0 || n < 0 || n > 255 || idxPos + n > len) {
+ buf[0] = '\0';
+ } else {
+ strncpy(buf, (char *)&file[idxPos], 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
+};
+
+struct TrueTypeLoca {
+ int idx;
+ int pos;
+ int length;
+};
+
+TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
+ int pos, i, idx, n, length;
+ Guint size, startPos, endPos;
+
+ 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);
+ if (tableHdrs[i].offset + tableHdrs[i].length < tableHdrs[i].offset ||
+ tableHdrs[i].offset + tableHdrs[i].length > (Guint)len) {
+ tableHdrs[i].offset = (Guint)-1;
+ }
+ 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;
+ }
+
+ // some embedded TrueType fonts have an incorrect (too small) cmap
+ // table size
+ idx = seekTableIdx("cmap");
+ if (idx >= 0) {
+ pos = tableHdrs[idx].offset;
+ n = getUShort(pos + 2);
+ size = (Guint)(4 + 8 * n);
+ for (i = 0; i < n; ++i) {
+ startPos = getULong(pos + 4 + 8*i + 4);
+ length = getUShort(pos + startPos + 2);
+ endPos = startPos + length;
+ if (endPos > size) {
+ size = endPos;
+ }
+ }
+ if ((mungedCmapSize = size > tableHdrs[idx].length)) {
+#if 0 // don't bother printing this error message - it's too common
+ error(-1, "Bad cmap table size in TrueType font");
+#endif
+ tableHdrs[idx].length = size;
+ }
+ } else {
+ mungedCmapSize = gFalse;
+ }
+
+ // 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 pos, i, j;
+ 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
+ cmapPlatform = 0; // make gcc happy
+ cmapEncoding = 0; // make gcc happy
+ 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);
+ for (i = 0; i < 256; ++i) {
+ cmap[i] = getCmapEntry(cmapFmt, pos, i);
+ }
+ // Windows-symbol sometimes uses char codes 0xf000 - 0xf0ff, so
+ // we use these to override 0x0000 - 0x00ff
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ for (i = 0; i < 256; ++i) {
+ if ((j = getCmapEntry(cmapFmt, pos, 0xf000 + i)) != 0) {
+ cmap[i] = j;
+ }
+ }
+ }
+ }
+
+ //----- 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);
+ if (stringPos >= 0 && stringPos + 1 + n <= len) {
+ s = new GString(file + stringPos + 1, n);
+ encoding[i] = copyString(s->getCString());
+ delete s;
+ } else {
+ encoding[i] = copyString(macGlyphNames[0]);
+ }
+ ++stringIdx;
+ stringPos += 1 + n;
}
- eexecDumpOp1(3);
+ } else {
+ encoding[i] = copyString(macGlyphNames[0]);
}
- nHints += nOps / 2;
+ }
+
+ // 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,
+ GBool pdfFontIsSymbolic,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
+ char buf[512];
+
+ // write the header
+ sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+ (*outputFunc)(outputStream, buf, strlen(buf));
+
+ // begin the font dictionary
+ (*outputFunc)(outputStream, "10 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, name, strlen(name));
+ (*outputFunc)(outputStream, " def\n", 5);
+ (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
+
+ // write the guts of the dictionary
+ cvtEncoding(encodingA, pdfFontHasEncoding, outputFunc, outputStream);
+ cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, pdfFontIsSymbolic,
+ outputFunc, outputStream);
+ cvtSfnts(outputFunc, outputStream, NULL);
+
+ // end the dictionary and define the font
+ (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
+}
+
+void TrueTypeFontFile::convertToCIDType2(char *name, Gushort *cidMap,
+ int nCIDs,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
+ char buf[512];
+ Gushort cid;
+ int i, j, k;
+
+ // write the header
+ sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+ (*outputFunc)(outputStream, buf, strlen(buf));
+
+ // begin the font dictionary
+ (*outputFunc)(outputStream, "20 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/CIDFontName /", 14);
+ (*outputFunc)(outputStream, name, strlen(name));
+ (*outputFunc)(outputStream, " def\n", 5);
+ (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
+ (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
+ (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
+ (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24);
+ (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27);
+ (*outputFunc)(outputStream, " /Supplement 0 def\n", 20);
+ (*outputFunc)(outputStream, " end def\n", 10);
+ (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
+ if (cidMap) {
+ sprintf(buf, "/CIDCount %d def\n", nCIDs);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ if (nCIDs > 32767) {
+ (*outputFunc)(outputStream, "/CIDMap [", 9);
+ for (i = 0; i < nCIDs; i += 32768 - 16) {
+ (*outputFunc)(outputStream, "<\n", 2);
+ for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
+ (*outputFunc)(outputStream, " ", 2);
+ for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
+ cid = cidMap[i+j+k];
+ sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+ (*outputFunc)(outputStream, " >", 3);
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ (*outputFunc)(outputStream, "] def\n", 6);
+ } else {
+ (*outputFunc)(outputStream, "/CIDMap <\n", 10);
+ for (i = 0; i < nCIDs; i += 16) {
+ (*outputFunc)(outputStream, " ", 2);
+ for (j = 0; j < 16 && i+j < nCIDs; ++j) {
+ cid = cidMap[i+j];
+ sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+ (*outputFunc)(outputStream, "> def\n", 6);
+ }
+ } else {
+ // direct mapping - just fill the string(s) with s[i]=i
+ sprintf(buf, "/CIDCount %d def\n", nGlyphs);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ if (nGlyphs > 32767) {
+ (*outputFunc)(outputStream, "/CIDMap [\n", 10);
+ for (i = 0; i < nGlyphs; i += 32767) {
+ j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
+ sprintf(buf, " %d string 0 1 %d {\n", 2 * j, j - 1);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, " 1 index exch dup 2 mul 1 add exch %d add"
+ " 255 and put\n", i);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, " } for\n", 8);
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ } else {
+ sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, " 0 1 %d {\n", nGlyphs - 1);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream,
+ " 2 copy dup 2 mul exch -8 bitshift put\n", 42);
+ (*outputFunc)(outputStream,
+ " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
+ (*outputFunc)(outputStream, " } for\n", 8);
+ (*outputFunc)(outputStream, "def\n", 4);
+ }
+ }
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
+ (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
+ (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
+ (*outputFunc)(outputStream, " /.notdef 0 def\n", 17);
+ (*outputFunc)(outputStream, " end readonly def\n", 19);
+
+ // write the guts of the dictionary
+ cvtSfnts(outputFunc, outputStream, NULL);
+
+ // end the dictionary and define the font
+ (*outputFunc)(outputStream,
+ "CIDFontName currentdict end /CIDFont defineresource pop\n",
+ 56);
+}
+
+void TrueTypeFontFile::convertToType0(char *name, Gushort *cidMap,
+ int nCIDs,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
+ char buf[512];
+ GString *sfntsName;
+ int n, i, j;
+
+ // write the Type 42 sfnts array
+ sfntsName = (new GString(name))->append("_sfnts");
+ cvtSfnts(outputFunc, outputStream, sfntsName);
+ delete sfntsName;
+
+ // write the descendant Type 42 fonts
+ n = cidMap ? nCIDs : nGlyphs;
+ for (i = 0; i < n; i += 256) {
+ (*outputFunc)(outputStream, "10 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, name, strlen(name));
+ sprintf(buf, "_%02x def\n", i >> 8);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
+ (*outputFunc)(outputStream, "/sfnts ", 7);
+ (*outputFunc)(outputStream, name, strlen(name));
+ (*outputFunc)(outputStream, "_sfnts def\n", 11);
+ (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
+ for (j = 0; j < 256 && i+j < n; ++j) {
+ sprintf(buf, "dup %d /c%02x put\n", j, j);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ (*outputFunc)(outputStream, "readonly def\n", 13);
+ (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
+ (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
+ for (j = 0; j < 256 && i+j < n; ++j) {
+ sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ (*outputFunc)(outputStream, "end readonly def\n", 17);
+ (*outputFunc)(outputStream,
+ "FontName currentdict end definefont pop\n", 40);
+ }
+
+ // write the Type 0 parent font
+ (*outputFunc)(outputStream, "16 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, name, strlen(name));
+ (*outputFunc)(outputStream, " def\n", 5);
+ (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
+ (*outputFunc)(outputStream, "/Encoding [\n", 12);
+ for (i = 0; i < n; i += 256) {
+ sprintf(buf, "%d\n", i >> 8);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "/FDepVector [\n", 14);
+ for (i = 0; i < n; i += 256) {
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, name, strlen(name));
+ sprintf(buf, "_%02x findfont\n", i >> 8);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
+}
+
+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 (int)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)) {
+ if (tableHdrs[i].offset == (Guint)-1) {
+ return -1;
+ }
+ return i;
+ }
+ }
+ return -1;
+}
+
+void TrueTypeFontFile::cvtEncoding(char **encodingA, GBool pdfFontHasEncoding,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
+ char *name;
+ char buf[64];
+ int i;
+
+ (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
+ if (pdfFontHasEncoding) {
+ for (i = 0; i < 256; ++i) {
+ if (!(name = encodingA[i])) {
+ name = ".notdef";
+ }
+ sprintf(buf, "dup %d /", i);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, name, strlen(name));
+ (*outputFunc)(outputStream, " put\n", 5);
+ }
+ } else {
+ for (i = 0; i < 256; ++i) {
+ sprintf(buf, "dup %d /c%02x put\n", i, i);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ }
+ (*outputFunc)(outputStream, "readonly def\n", 13);
+}
+
+void TrueTypeFontFile::cvtCharStrings(char **encodingA,
+ CharCodeToUnicode *toUnicode,
+ GBool pdfFontHasEncoding,
+ GBool pdfFontIsSymbolic,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
+ int unicodeCmap, macRomanCmap, msSymbolCmap;
+ int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapOffset;
+ T42FontIndexMode mode;
+ char *name;
+ char buf[64], buf2[16];
+ Unicode u;
+ int pos, i, j, k;
+
+ // always define '.notdef'
+ (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
+ (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
+
+ // 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 PDF font is symbolic and the TrueType font has a
+ // Microsoft Symbol cmap, use it, and use (0xf000 + char code).
+ // 1c. 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) || cmapPlatform == 0) {
+ 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 (pdfFontIsSymbolic && msSymbolCmap >= 0) {
+ i = msSymbolCmap;
+ mode = t42FontModeCharCodeOffset;
+ cmapOffset = 0xf000;
+ } 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
+ // N.B. We do this in reverse order because font subsets can have
+ // weird encodings that use the same character name twice, and
+ // the first definition is probably the one we want.
+ k = 0; // make gcc happy
+ for (i = 255; i >= 0; --i) {
+ if (pdfFontHasEncoding) {
+ name = encodingA[i];
+ } else {
+ sprintf(buf2, "c%02x", i);
+ name = buf2;
+ }
+ if (name && strcmp(name, ".notdef")) {
+ switch (mode) {
+ case t42FontModeUnicode:
+ toUnicode->mapToUnicode((CharCode)i, &u, 1);
+ k = getCmapEntry(cmapFmt, pos, (int)u);
break;
- case 18: // hstemhm
- //~ ignored
- if (first) {
- cvtGlyphWidth(nOps & 1);
- first = gFalse;
- }
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps);
- }
- nHints += nOps / 2;
+ case t42FontModeCharCode:
+ k = getCmapEntry(cmapFmt, pos, i);
break;
- case 23: // vstemhm
- //~ ignored
- if (first) {
- cvtGlyphWidth(nOps & 1);
- first = gFalse;
- }
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps);
+ case t42FontModeCharCodeOffset:
+ if ((k = getCmapEntry(cmapFmt, pos, cmapOffset + i)) == 0) {
+ k = getCmapEntry(cmapFmt, pos, i);
}
- nHints += nOps / 2;
- break;
- case 10: // callsubr
- case 11: // return
- case 16: // blend
- case 29: // callgsubr
- error(-1, "Unimplemented Type 2 charstring op: %d", s[i]);
break;
- default:
- error(-1, "Illegal Type 2 charstring op: %d", s[i]);
+ case t42FontModeMacRoman:
+ j = globalParams->getMacRomanCharCode(name);
+ k = getCmapEntry(cmapFmt, pos, j);
break;
}
- ++i;
- nOps = 0;
- } else if (s[i] <= 246) {
- if (nOps < 48) {
- fp[nOps] = gFalse;
- op[nOps++] = (int)s[i] - 139;
- }
- ++i;
- } else if (s[i] <= 250) {
- if (nOps < 48) {
- fp[nOps] = gFalse;
- op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108;
+ // 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 > 0 && k < nGlyphs) {
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, name, strlen(name));
+ sprintf(buf, " %d def\n", k);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- i += 2;
- } else if (s[i] <= 254) {
- if (nOps < 48) {
- fp[nOps] = gFalse;
- op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108;
+ }
+ }
+
+ err:
+ (*outputFunc)(outputStream, "end readonly def\n", 17);
+}
+
+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;
}
- i += 2;
+ }
+ 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 (code < segStart) {
+ return 0;
+ }
+ if (segOffset == 0) {
+ i = (code + segDelta) & 0xffff;
} else {
- x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4];
- if (x & 0x80000000)
- x |= -1 << 31;
- if (nOps < 48) {
- fp[nOps] = gTrue;
- op[nOps++] = (double)x / 65536.0;
+ i = getUShort(pos + 16 + 6*segCnt + 2*b +
+ segOffset + 2 * (code - segStart));
+ if (i != 0) {
+ i = (i + segDelta) & 0xffff;
}
- i += 5;
}
- }
+ return i;
- sprintf(eBuf, "/%s %d RD ", name, charBuf->getLength());
- eexecWrite(eBuf);
- eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
- eexecWrite(" ND\n");
- delete charBuf;
+ 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 Type1CFontConverter::cvtGlyphWidth(GBool useOp) {
- double w;
- GBool wFP;
- int i;
+static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
+ return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx;
+}
- if (useOp) {
- w = nominalWidthX + op[0];
- wFP = nominalWidthXFP | fp[0];
- for (i = 1; i < nOps; ++i) {
- op[i-1] = op[i];
- fp[i-1] = fp[i];
- }
- --nOps;
+static int cmpTrueTypeLocaPos(const void *p1, const void *p2) {
+ if (((TrueTypeLoca *)p1)->pos == ((TrueTypeLoca *)p2)->pos) {
+ return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx;
} else {
- w = defaultWidthX;
- wFP = defaultWidthXFP;
+ return ((TrueTypeLoca *)p1)->pos - ((TrueTypeLoca *)p2)->pos;
}
- eexecDumpNum(0, gFalse);
- eexecDumpNum(w, wFP);
- eexecDumpOp1(13);
}
-void Type1CFontConverter::eexecDumpNum(double x, GBool fp) {
- Guchar buf[12];
- int y, n;
+void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc,
+ void *outputStream, GString *name) {
+ TTFontTableHdr newTableHdrs[nT42Tables];
+ char tableDir[12 + nT42Tables*16];
+ char headTable[54];
+ TrueTypeLoca *origLocaTable;
+ char *locaTable;
+ int nNewTables;
+ Guint checksum;
+ int pos, glyfPos, length, glyphLength, pad;
+ int i, j, k;
- n = 0;
- if (fp) {
- if (x >= -32768 && x < 32768) {
- y = (int)(x * 256.0);
- buf[0] = 255;
- buf[1] = (Guchar)(y >> 24);
- buf[2] = (Guchar)(y >> 16);
- buf[3] = (Guchar)(y >> 8);
- buf[4] = (Guchar)y;
- buf[5] = 255;
- buf[6] = 0;
- buf[7] = 0;
- buf[8] = 1;
- buf[9] = 0;
- buf[10] = 12;
- buf[11] = 12;
- n = 12;
+ // 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 sort it into proper order --
+ // some (non-compliant) fonts have out-of-order loca tables; in
+ // order to correctly handle the case where (compliant) fonts have
+ // empty entries in the middle of the table, cmpTrueTypeLocaPos uses
+ // pos as its primary sort key, and idx as its secondary key
+ // (ensuring that adjacent entries with the same pos value remain in
+ // the same order)
+ origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) *
+ sizeof(TrueTypeLoca));
+ pos = seekTable("loca");
+ for (i = 0; i <= nGlyphs; ++i) {
+ origLocaTable[i].idx = i;
+ if (locaFmt) {
+ origLocaTable[i].pos = getULong(pos + 4*i);
} else {
- error(-1, "Type 2 fixed point constant out of range");
+ origLocaTable[i].pos = 2 * getUShort(pos + 2*i);
+ }
+ }
+ qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaPos);
+ for (i = 0; i < nGlyphs; ++i) {
+ origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos;
+ }
+ origLocaTable[nGlyphs].length = 0;
+ qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaIdx);
+
+ // construct the new 'loca' table, padding each glyph out to a
+ // multiple of 4 bytes
+ locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
+ pos = 0;
+ for (i = 0; i <= nGlyphs; ++i) {
+ 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);
+ }
+ length = origLocaTable[i].length;
+ if (length & 3) {
+ length += 4 - (length & 3);
+ }
+ pos += length;
+ }
+
+ // 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].length;
+ pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0;
+ length += glyphLength + pad;
+ if (glyphLength >= 0 &&
+ glyfPos + origLocaTable[j].pos + glyphLength <= len) {
+ checksum +=
+ computeTableChecksum(file + glyfPos + origLocaTable[j].pos,
+ 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) {
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, name->getCString(), name->getLength());
+ (*outputFunc)(outputStream, " [\n", 3);
} else {
- y = (int)x;
- if (y >= -107 && y <= 107) {
- buf[0] = (Guchar)(y + 139);
- n = 1;
- } else if (y > 107 && y <= 1131) {
- y -= 108;
- buf[0] = (Guchar)((y >> 8) + 247);
- buf[1] = (Guchar)(y & 0xff);
- n = 2;
- } else if (y < -107 && y >= -1131) {
- y = -y - 108;
- buf[0] = (Guchar)((y >> 8) + 251);
- buf[1] = (Guchar)(y & 0xff);
- n = 2;
+ (*outputFunc)(outputStream, "/sfnts [\n", 9);
+ }
+
+ // write the table directory
+ dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
+
+ // write the tables
+ for (i = 0; i < nNewTables; ++i) {
+ if (i == t42HeadTable) {
+ dumpString(headTable, 54, outputFunc, outputStream);
+ } else if (i == t42LocaTable) {
+ length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+ dumpString(locaTable, length, outputFunc, outputStream);
+ } else if (i == t42GlyfTable) {
+ glyfPos = seekTable("glyf");
+ for (j = 0; j < nGlyphs; ++j) {
+ length = origLocaTable[j].length;
+ if (length > 0 &&
+ glyfPos + origLocaTable[j].pos + length <= len) {
+ dumpString(file + glyfPos + origLocaTable[j].pos, length,
+ outputFunc, outputStream);
+ }
+ }
} else {
- buf[0] = 255;
- buf[1] = (Guchar)(y >> 24);
- buf[2] = (Guchar)(y >> 16);
- buf[3] = (Guchar)(y >> 8);
- buf[4] = (Guchar)y;
- n = 5;
+ // 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) {
+ j = seekTable(t42Tables[i].tag);
+ if (j >= 0) {
+ dumpString(file + seekTable(t42Tables[i].tag), length,
+ outputFunc, outputStream);
+ }
+ }
}
}
- charBuf->append((char *)buf, n);
-}
-void Type1CFontConverter::eexecDumpOp1(int op) {
- charBuf->append((char)op);
+ // end the sfnts array
+ (*outputFunc)(outputStream, "] def\n", 6);
+
+ gfree(origLocaTable);
+ gfree(locaTable);
}
-void Type1CFontConverter::eexecDumpOp2(int op) {
- charBuf->append((char)12);
- charBuf->append((char)op);
+void TrueTypeFontFile::dumpString(char *s, int length,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
+ char buf[64];
+ int pad, i, j;
+
+ (*outputFunc)(outputStream, "<", 1);
+ for (i = 0; i < length; i += 32) {
+ for (j = 0; j < 32 && i+j < length; ++j) {
+ sprintf(buf, "%02X", s[i+j] & 0xff);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ if (i % (65536 - 32) == 65536 - 64) {
+ (*outputFunc)(outputStream, ">\n<", 3);
+ } else if (i+32 < length) {
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+ }
+ if (length & 3) {
+ pad = 4 - (length & 3);
+ for (i = 0; i < pad; ++i) {
+ (*outputFunc)(outputStream, "00", 2);
+ }
+ }
+ // add an extra zero byte because the Adobe Type 42 spec says so
+ (*outputFunc)(outputStream, "00>\n", 4);
}
-void Type1CFontConverter::eexecWriteCharstring(Guchar *s, int n) {
- Gushort r2;
- Guchar x;
+Guint TrueTypeFontFile::computeTableChecksum(char *data, int length) {
+ Guint checksum, word;
int i;
- r2 = 4330;
+ 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;
+}
- for (i = 0; i < n; ++i) {
- // charstring encryption
- x = s[i];
- x ^= (r2 >> 8);
- r2 = (x + r2) * 52845 + 22719;
+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;
+ GBool unsortedLoca;
+ int nNewTables, nZeroLengthTables, nAllTables;
+ TTFontTableHdr *newTableHdrs;
+ char *tableDir;
+ TrueTypeLoca *origLocaTable;
+ char *locaTable;
+ int length, glyfLength;
+ Guint t, pos, pos2;
+ int i, j, k;
- // eexec encryption
- x ^= (r1 >> 8);
- r1 = (x + r1) * 52845 + 22719;
- fputc(hexChars[x >> 4], out);
- fputc(hexChars[x & 0x0f], out);
- line += 2;
- if (line == 64) {
- fputc('\n', out);
- line = 0;
+ // check for missing/broken tables
+ haveCmap = seekTable("cmap") >= 0;
+ haveName = seekTable("name") >= 0;
+ havePost = seekTable("post") >= 0;
+ unsortedLoca = gFalse;
+ pos = 0;
+ for (i = 0; i <= nGlyphs; ++i) {
+ if (locaFmt) {
+ pos2 = getULong(pos + 4*i);
+ } else {
+ pos2 = 2 * getUShort(pos + 2*i);
}
+ if (pos2 < pos) {
+ unsortedLoca = gTrue;
+ break;
+ }
+ pos = pos2;
+ }
+ nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1);
+ nZeroLengthTables = 0;
+ for (i = 0; i < nTables; ++i) {
+ if (tableHdrs[i].length == 0) {
+ ++nZeroLengthTables;
+ }
+ }
+ if (!nNewTables && !nZeroLengthTables && !mungedCmapSize && !unsortedLoca) {
+ // nothing is broken - write the TTF file as is
+ fwrite(file, 1, len, out);
+ return;
}
-}
-void Type1CFontConverter::getDeltaInt(char *buf, char *name, double *op,
- int n) {
- int x, i;
+ // if the glyph data isn't sorted (as listed in the 'loca' table),
+ // construct a new 'loca' table
+ if (unsortedLoca) {
+ origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) *
+ sizeof(TrueTypeLoca));
+ pos = seekTable("loca");
+ for (i = 0; i <= nGlyphs; ++i) {
+ origLocaTable[i].idx = i;
+ if (locaFmt) {
+ origLocaTable[i].pos = getULong(pos + 4*i);
+ } else {
+ origLocaTable[i].pos = 2 * getUShort(pos + 2*i);
+ }
+ }
+ qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
+ &cmpTrueTypeLocaPos);
+ for (i = 0; i < nGlyphs; ++i) {
+ origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos;
+ }
+ origLocaTable[nGlyphs].length = 0;
+ qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
+ &cmpTrueTypeLocaIdx);
+ locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
+ pos = 0;
+ for (i = 0; i <= nGlyphs; ++i) {
+ 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);
+ }
+ length = origLocaTable[i].length;
+ if (length & 3) {
+ length += 4 - (length & 3);
+ }
+ pos += length;
+ }
+ glyfLength = pos;
+ } else {
+ origLocaTable = NULL; // make gcc happy
+ locaTable = NULL; // make gcc happy
+ glyfLength = 0; // make gcc happy
+ }
- sprintf(buf, "/%s [", name);
- buf += strlen(buf);
- x = 0;
- for (i = 0; i < n; ++i) {
- x += (int)op[i];
- sprintf(buf, "%s%d", i > 0 ? " " : "", x);
- buf += strlen(buf);
+ // construct the new table directory
+ nAllTables = nTables - nZeroLengthTables + nNewTables;
+ newTableHdrs = (TTFontTableHdr *)gmalloc(nAllTables *
+ sizeof(TTFontTableHdr));
+ dirCmap = haveCmap;
+ dirName = haveName;
+ dirPost = havePost;
+ pos = 12 + nAllTables * 16;
+ j = 0;
+ for (i = 0; i < nTables; ++i) {
+ if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) {
+ memcpy(newTableHdrs[j].tag, "cmap", 4);
+ newTableHdrs[j].checksum = 0; //~ should compute the checksum
+ newTableHdrs[j].offset = pos;
+ pos += newTableHdrs[j].length = sizeof(cmapTab);
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
+ ++j;
+ dirCmap = gTrue;
+ }
+ if (!dirName && strncmp(tableHdrs[i].tag, "name", 4) > 0) {
+ memcpy(newTableHdrs[j].tag, "name", 4);
+ newTableHdrs[j].checksum = 0; //~ should compute the checksum
+ newTableHdrs[j].offset = pos;
+ pos += newTableHdrs[j].length = sizeof(nameTab);
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
+ ++j;
+ dirName = gTrue;
+ }
+ if (!dirPost && strncmp(tableHdrs[i].tag, "post", 4) > 0) {
+ memcpy(newTableHdrs[j].tag, "post", 4);
+ newTableHdrs[j].checksum = 0; //~ should compute the checksum
+ newTableHdrs[j].offset = pos;
+ pos += newTableHdrs[j].length = sizeof(postTab);
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
+ ++j;
+ dirPost = gTrue;
+ }
+ // throw away zero-length tables - they confuse FreeType
+ if (tableHdrs[i].length > 0) {
+ memcpy(newTableHdrs[j].tag, tableHdrs[i].tag, 4);
+ newTableHdrs[j].checksum = tableHdrs[i].checksum;
+ newTableHdrs[j].offset = pos;
+ if (unsortedLoca && !strncmp(tableHdrs[i].tag, "loca", 4)) {
+ newTableHdrs[j].length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+ } else if (unsortedLoca && !strncmp(tableHdrs[i].tag, "glyf", 4)) {
+ newTableHdrs[j].length = glyfLength;
+ } else {
+ newTableHdrs[j].length = tableHdrs[i].length;
+ }
+ pos += newTableHdrs[j].length;
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
+ ++j;
+ }
+ }
+ if (!dirCmap) {
+ memcpy(newTableHdrs[j].tag, "cmap", 4);
+ newTableHdrs[j].checksum = 0; //~ should compute the checksum
+ newTableHdrs[j].offset = pos;
+ pos += newTableHdrs[j].length = sizeof(cmapTab);
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
+ ++j;
+ }
+ if (!dirName) {
+ memcpy(newTableHdrs[j].tag, "name", 4);
+ newTableHdrs[j].checksum = 0; //~ should compute the checksum
+ newTableHdrs[j].offset = pos;
+ pos += newTableHdrs[j].length = sizeof(nameTab);
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
+ ++j;
+ }
+ if (!dirPost) {
+ memcpy(newTableHdrs[j].tag, "post", 4);
+ newTableHdrs[j].checksum = 0; //~ should compute the checksum
+ newTableHdrs[j].offset = pos;
+ pos += newTableHdrs[j].length = sizeof(postTab);
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
+ ++j;
+ }
+ tableDir = (char *)gmalloc(12 + nAllTables * 16);
+ tableDir[0] = 0x00; // sfnt version
+ tableDir[1] = 0x01;
+ tableDir[2] = 0x00;
+ tableDir[3] = 0x00;
+ tableDir[4] = (char)((nAllTables >> 8) & 0xff); // numTables
+ 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); // searchRange
+ tableDir[7] = (char)(t & 0xff);
+ tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector
+ tableDir[9] = (char)(i & 0xff);
+ t = nAllTables * 16 - t;
+ tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift
+ tableDir[11] = (char)(t & 0xff);
+ pos = 12;
+ for (i = 0; i < nAllTables; ++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;
}
- sprintf(buf, "] def\n");
-}
-void Type1CFontConverter::getDeltaReal(char *buf, char *name, double *op,
- int n) {
- double x;
- int i;
+ // write the table directory
+ fwrite(tableDir, 1, 12 + 16 * nAllTables, out);
- sprintf(buf, "/%s [", name);
- buf += strlen(buf);
- x = 0;
- for (i = 0; i < n; ++i) {
- x += op[i];
- sprintf(buf, "%s%g", i > 0 ? " " : "", x);
- buf += strlen(buf);
+ // write the tables
+ for (i = 0; i < nAllTables; ++i) {
+ if (!haveCmap && !strncmp(newTableHdrs[i].tag, "cmap", 4)) {
+ fwrite(cmapTab, 1, newTableHdrs[i].length, out);
+ } else if (!haveName && !strncmp(newTableHdrs[i].tag, "name", 4)) {
+ fwrite(nameTab, 1, newTableHdrs[i].length, out);
+ } else if (!havePost && !strncmp(newTableHdrs[i].tag, "post", 4)) {
+ fwrite(postTab, 1, newTableHdrs[i].length, out);
+ } else if (unsortedLoca && !strncmp(newTableHdrs[i].tag, "loca", 4)) {
+ fwrite(locaTable, 1, newTableHdrs[i].length, out);
+ } else if (unsortedLoca && !strncmp(newTableHdrs[i].tag, "glyf", 4)) {
+ pos = seekTable("glyf");
+ for (j = 0; j < nGlyphs; ++j) {
+ length = origLocaTable[j].length;
+ if (length > 0 &&
+ pos + origLocaTable[j].pos + length <= (Guint)len) {
+ fwrite(file + pos + origLocaTable[j].pos, 1, length, out);
+ if ((k = length & 3)) {
+ for (; k < 4; ++k) {
+ fputc((char)0, out);
+ }
+ }
+ }
+ }
+ } else {
+ fwrite(file + seekTable(newTableHdrs[i].tag),
+ 1, newTableHdrs[i].length, out);
+ }
+ if ((j = (newTableHdrs[i].length & 3))) {
+ for (; j < 4; ++j) {
+ fputc((char)0, out);
+ }
+ }
+ }
+
+ gfree(tableDir);
+ gfree(newTableHdrs);
+ if (unsortedLoca) {
+ gfree(origLocaTable);
+ gfree(locaTable);
}
- sprintf(buf, "] def\n");
}