//
// FontFile.cc
//
-// Copyright 1999-2002 Glyph & Cog, LLC
+// Copyright 1999-2003 Glyph & Cog, LLC
//
//========================================================================
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
-#include <aconf.h>
#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 "GHash.h"
#include "Error.h"
#include "GlobalParams.h"
#include "CharCodeToUnicode.h"
static inline char *nextLine(char *line, char *end) {
while (line < end && *line != '\n' && *line != '\r')
++line;
- while (line < end && *line == '\n' || *line == '\r')
+ while (line < end && (*line == '\n' || *line == '\r'))
++line;
return line;
}
};
Type1CFontFile::Type1CFontFile(char *fileA, int lenA) {
- Guchar *nameIdxPtr, *idxPtr0, *idxPtr1;
+ int nameIdxPos, namePos, nameLen;
- file = fileA;
+ 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 (file[0] != '\x01') {
+ if (len > 0 && file[0] != '\x01') {
++file;
+ --len;
}
- // read header
- topOffSize = file[3] & 0xff;
+ // make sure the header exists
+ if (len < 4) {
+ return;
+ }
// read name index (first font only)
- nameIdxPtr = (Guchar *)file + (file[2] & 0xff);
- idxPtr0 = getIndexValPtr(nameIdxPtr, 0);
- idxPtr1 = getIndexValPtr(nameIdxPtr, 1);
- name = new GString((char *)idxPtr0, idxPtr1 - idxPtr0);
-
- topDictIdxPtr = getIndexEnd(nameIdxPtr);
- stringIdxPtr = getIndexEnd(topDictIdxPtr);
- gsubrIdxPtr = getIndexEnd(stringIdxPtr);
+ 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() {
char **Type1CFontFile::getEncoding() {
if (!encoding) {
- readNameAndEncoding();
+ readEncoding();
}
return encoding;
}
-void Type1CFontFile::readNameAndEncoding() {
+void Type1CFontFile::readEncoding() {
char buf[256];
- Guchar *idxPtr0, *idxPtr1, *ptr;
+ int idxPos, idxLen, pos;
int nGlyphs;
int nCodes, nRanges, nLeft, nSups;
Gushort *glyphNames;
}
// read top dict (first font only)
- idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
- idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
+ if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) {
+ return;
+ }
charset = enc = charstrings = 0;
i = 0;
- ptr = idxPtr0;
- while (ptr < idxPtr1) {
- if (*ptr <= 27 || *ptr == 31) {
- key = *ptr++;
+ pos = idxPos;
+ while (pos < idxPos + idxLen) {
+ if (file[pos] <= 27 || file[pos] == 31) {
+ key = file[pos++];
if (key == 0x0c) {
- key = (key << 8) | *ptr++;
+ if (pos >= idxPos + idxLen) {
+ return;
+ }
+ key = (key << 8) | file[pos++];
}
if (key == 0x0f) { // charset
charset = (int)op[0];
}
i = 0;
} else {
- x = getNum(&ptr, &isFP);
+ x = getNum(&pos, &isFP);
if (i < 48) {
op[i++] = x;
}
}
// get number of glyphs from charstrings index
- nGlyphs = getIndexLen((Guchar *)file + charstrings);
+ nGlyphs = getIndexLen(charstrings);
// read charset (GID -> name mapping)
glyphNames = readCharset(charset, nGlyphs);
}
}
} else {
- ptr = (Guchar *)file + enc;
- encFormat = *ptr++;
+ pos = enc;
+ if (pos < 0 || pos >= len) {
+ goto err0;
+ }
+ encFormat = file[pos++];
if ((encFormat & 0x7f) == 0) {
- nCodes = 1 + *ptr++;
+ 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 = *ptr++;
+ c = file[pos++];
+ if (encoding[c]) {
+ gfree(encoding[c]);
+ }
encoding[c] = copyString(getString(glyphNames[i], buf));
}
} else if ((encFormat & 0x7f) == 1) {
- nRanges = *ptr++;
+ if (pos >= len) {
+ goto err0;
+ }
+ nRanges = file[pos++];
+ if (pos + 2 * nRanges > len) {
+ goto err0;
+ }
nCodes = 1;
for (i = 0; i < nRanges; ++i) {
- c = *ptr++;
- nLeft = *ptr++;
+ c = file[pos++];
+ nLeft = file[pos++];
for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
- encoding[c] = copyString(getString(glyphNames[nCodes], buf));
+ if (c < 256) {
+ if (encoding[c]) {
+ gfree(encoding[c]);
+ }
+ encoding[c] = copyString(getString(glyphNames[nCodes], buf));
+ }
++nCodes;
++c;
}
}
}
if (encFormat & 0x80) {
- nSups = *ptr++;
+ if (pos >= len) {
+ goto err0;
+ }
+ nSups = file[pos++];
+ if (pos + nSups * 3 > len) {
+ goto err0;
+ }
for (i = 0; i < nSups; ++i) {
- c = *ptr++;
- sid = getWord(ptr, 2);
- ptr += 2;
+ 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);
}
}
-void Type1CFontFile::convertToType1(FILE *outA) {
+void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
+ void *outputStreamA) {
Type1CTopDict dict;
Type1CPrivateDict privateDict;
- char buf[256], eBuf[256];
- Guchar *idxPtr0, *idxPtr1, *subrsIdxPtr, *charStringsIdxPtr, *ptr;
+ char buf[512], eBuf[256];
+ int idxPos, idxLen, pos;
int nGlyphs, nCodes, nRanges, nLeft, nSups;
Gushort *glyphNames;
- int encFormat, nSubrs, nCharStrings;
+ int encFormat, nCharStrings;
int c, sid;
- int i, j, n;
+ int i, j;
- out = outA;
+ outputFunc = outputFuncA;
+ outputStream = outputStreamA;
// read top dict (first font only)
readTopDict(&dict);
- // get global subrs
- //~ ... global subrs are unimplemented
-
// write header and font dictionary, up to encoding
- fprintf(out, "%%!FontType1-1.0: %s", name->getCString());
+ (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17);
+ (*outputFunc)(outputStream, name->getCString(), name->getLength());
if (dict.version != 0) {
- fprintf(out, "%s", getString(dict.version, 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);
+ // the dictionary needs room for 12 entries: the following 9, plus
+ // Private and CharStrings (in the eexec section) and FID (which is
+ // added by definefont)
+ (*outputFunc)(outputStream, "12 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, 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, 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, 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, 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, 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, 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", name->getCString());
- fprintf(out, "/PaintType %d def\n", dict.paintType);
- fprintf(out, "/FontType 1 def\n");
- fprintf(out, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
+ 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]);
- fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
+ (*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
- nGlyphs = getIndexLen((Guchar *)file + dict.charStrings);
+ nGlyphs = getIndexLen(dict.charStrings);
// read charset
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 (expertEncoding[i]) {
- fprintf(out, "dup %d /%s put\n", i, expertEncoding[i]);
+ sprintf(buf, "dup %d /%s put\n", i, expertEncoding[i]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
}
} else {
- ptr = (Guchar *)file + dict.encoding;
- encFormat = *ptr++;
+ pos = dict.encoding;
+ if (pos < 0 || pos >= len) {
+ goto err0;
+ }
+ encFormat = file[pos++];
if ((encFormat & 0x7f) == 0) {
- nCodes = 1 + *ptr++;
+ 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 = *ptr++;
- fprintf(out, "dup %d /%s put\n",
- c, getString(glyphNames[i], 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 = *ptr++;
+ if (pos >= len) {
+ goto err0;
+ }
+ nRanges = file[pos++];
+ if (pos + 2 * nRanges > len) {
+ goto err0;
+ }
nCodes = 1;
for (i = 0; i < nRanges; ++i) {
- c = *ptr++;
- nLeft = *ptr++;
+ 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], 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 = *ptr++;
+ if (pos >= len) {
+ goto err0;
+ }
+ nSups = file[pos++];
+ if (pos + nSups * 3 > len) {
+ goto err0;
+ }
for (i = 0; i < nSups; ++i) {
- c = *ptr++;
- sid = getWord(ptr, 2);
- ptr += 2;
- fprintf(out, "dup %d /%s put\n", c, getString(sid, 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");
+ (*outputFunc)(outputStream, "currentdict end\n", 16);
// start the binary section
- fprintf(out, "currentfile eexec\n");
+ (*outputFunc)(outputStream, "currentfile eexec\n", 18);
r1 = 55665;
line = 0;
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("/MinFeature {16 16} def\n");
+ eexecWrite("/password 5839 def\n");
readPrivateDict(&privateDict, dict.privateOffset, dict.privateSize);
eexecWrite(privateDict.dictData->getCString());
defaultWidthX = privateDict.defaultWidthX;
nominalWidthX = privateDict.nominalWidthX;
nominalWidthXFP = privateDict.nominalWidthXFP;
- // get subrs
- if (privateDict.subrsOffset != 0) {
- subrsIdxPtr = (Guchar *)file + dict.privateOffset +
- privateDict.subrsOffset;
- nSubrs = getIndexLen(subrsIdxPtr);
- sprintf(eBuf, "/Subrs %d array\n", nSubrs);
- eexecWrite(eBuf);
- idxPtr1 = getIndexValPtr(subrsIdxPtr, 0);
- for (i = 0; i < nSubrs; ++i) {
- idxPtr0 = idxPtr1;
- idxPtr1 = getIndexValPtr(subrsIdxPtr, i+1);
- n = idxPtr1 - idxPtr0;
-#if 1 //~ Type 2 subrs are unimplemented
- error(-1, "Unimplemented Type 2 subrs");
-#else
- sprintf(eBuf, "dup %d %d RD ", i, n);
- eexecWrite(eBuf);
- eexecCvtGlyph(idxPtr0, n);
- eexecWrite(" NP\n");
-#endif
- }
- eexecWrite("ND\n");
- }
+ // set up subroutines
+ subrIdxPos = 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
- charStringsIdxPtr = (Guchar *)file + dict.charStrings;
- nCharStrings = getIndexLen(charStringsIdxPtr);
+ nCharStrings = getIndexLen(dict.charStrings);
sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings);
eexecWrite(eBuf);
- idxPtr1 = getIndexValPtr(charStringsIdxPtr, 0);
for (i = 0; i < nCharStrings; ++i) {
- idxPtr0 = idxPtr1;
- idxPtr1 = getIndexValPtr(charStringsIdxPtr, i+1);
- n = idxPtr1 - idxPtr0;
- eexecCvtGlyph(getString(glyphNames[i], buf), idxPtr0, n);
+ if ((idxPos = getIndexValPos(dict.charStrings, i, &idxLen)) >= 0) {
+ eexecCvtGlyph(getString(glyphNames[i], buf), idxPos, idxLen);
+ }
}
eexecWrite("end\n");
eexecWrite("end\n");
// trailer
if (line > 0) {
- fputc('\n', out);
+ (*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
delete privateDict.dictData;
}
}
-void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
+void Type1CFontFile::convertToCIDType0(char *psName,
+ FontFileOutputFunc outputFuncA,
+ void *outputStreamA) {
Type1CTopDict dict;
Type1CPrivateDict *privateDicts;
GString *charStrings;
Gushort *charset;
int *cidMap;
Guchar *fdSelect;
- Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
- char buf[256];
+ int idxPos, idxLen, pos;
+ char buf[512], buf2[16];
int nGlyphs, nCIDs, gdBytes, nFDs;
int fdSelectFmt, nRanges, gid0, gid1, fd, offset;
int key;
GBool isFP;
int i, j, k, n;
- out = outA;
+ outputFunc = outputFuncA;
+ outputStream = outputStreamA;
- fprintf(out, "/CIDInit /ProcSet findresource begin\n");
+ (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37);
// read top dict (first font only)
readTopDict(&dict);
privateDicts[0].nominalWidthX = 0;
privateDicts[0].nominalWidthXFP = gFalse;
} else {
- fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
- nFDs = getIndexLen(fdArrayIdx);
+ if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) {
+ goto err0;
+ }
privateDicts = (Type1CPrivateDict *)
gmalloc(nFDs * sizeof(Type1CPrivateDict));
- idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
for (i = 0; i < nFDs; ++i) {
privateDicts[i].dictData = NULL;
- idxPtr0 = idxPtr1;
- idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
- ptr = idxPtr0;
+ }
+ 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 (ptr < idxPtr1) {
- if (*ptr <= 27 || *ptr == 31) {
- key = *ptr++;
+ while (pos < idxPos + idxLen) {
+ if (file[pos] <= 27 || file[pos] == 31) {
+ key = file[pos++];
if (key == 0x0c) {
- key = (key << 8) | *ptr++;
+ 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 {
- x = getNum(&ptr, &isFP);
+ x = getNum(&pos, &isFP);
if (j < 48) {
op[j] = x;
fp[j++] = isFP;
}
// get the glyph count
- charStringsIdxPtr = (Guchar *)file + dict.charStrings;
- nGlyphs = getIndexLen(charStringsIdxPtr);
+ if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) {
+ goto err1;
+ }
// read the FDSelect table
fdSelect = (Guchar *)gmalloc(nGlyphs);
fdSelect[i] = 0;
}
} else {
- ptr = (Guchar *)file + dict.fdSelectOffset;
- fdSelectFmt = *ptr++;
+ pos = dict.fdSelectOffset;
+ if (pos < 0 || pos >= len) {
+ goto err2;
+ }
+ fdSelectFmt = file[pos++];
if (fdSelectFmt == 0) {
- memcpy(fdSelect, ptr, nGlyphs);
+ if (pos + nGlyphs > len) {
+ goto err2;
+ }
+ memcpy(fdSelect, file + pos, nGlyphs);
} else if (fdSelectFmt == 3) {
- nRanges = getWord(ptr, 2);
- ptr += 2;
- gid0 = getWord(ptr, 2);
- ptr += 2;
+ 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 = *ptr++;
- gid1 = getWord(ptr, 2);
- ptr += 2;
+ fd = file[pos++];
+ gid1 = getWord(pos, 2);
+ pos += 2;
for (j = gid0; j < gid1; ++j) {
fdSelect[j] = fd;
}
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) {
- idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i]);
- idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i]+1);
- n = idxPtr1 - idxPtr0;
- j = fdSelect[cidMap[i]];
- defaultWidthX = privateDicts[j].defaultWidthX;
- defaultWidthXFP = privateDicts[j].defaultWidthXFP;
- nominalWidthX = privateDicts[j].nominalWidthX;
- nominalWidthXFP = privateDicts[j].nominalWidthXFP;
- cvtGlyph(idxPtr0, n);
- charStrings->append(charBuf);
- delete charBuf;
+ 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 = 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();
}
// begin the font dictionary
- fprintf(out, "20 dict begin\n");
- fprintf(out, "/CIDFontName /%s def\n", psName);
- fprintf(out, "/CIDFontType 0 def\n");
- fprintf(out, "/CIDSystemInfo 3 dict dup begin\n");
+ (*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) {
- fprintf(out, " /Registry (%s) def\n", getString(dict.registry, buf));
- fprintf(out, " /Ordering (%s) def\n", getString(dict.ordering, buf));
+ 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 {
- fprintf(out, " /Registry (Adobe) def\n");
- fprintf(out, " /Ordering (Identity) def\n");
+ (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24);
+ (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27);
}
- fprintf(out, " /Supplement %d def\n", dict.supplement);
- fprintf(out, "end def\n");
- fprintf(out, "/FontMatrix [%g %g %g %g %g %g] def\n",
+ 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]);
- fprintf(out, "/FontBBox [%g %g %g %g] def\n",
+ (*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]);
- fprintf(out, "/FontInfo 1 dict dup begin\n");
- fprintf(out, " /FSType 8 def\n");
- fprintf(out, "end def\n");
+ (*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
- fprintf(out, "/CIDCount %d def\n", nCIDs);
- fprintf(out, "/FDBytes 1 def\n");
- fprintf(out, "/GDBytes %d def\n", gdBytes);
- fprintf(out, "/CIDMapOffset 0 def\n");
+ 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) {
- fprintf(out, "/PaintType %d def\n", dict.paintType);
- fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
+ 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
- fprintf(out, "/FDArray %d array\n", nFDs);
+ sprintf(buf, "/FDArray %d array\n", nFDs);
+ (*outputFunc)(outputStream, buf, strlen(buf));
for (i = 0; i < nFDs; ++i) {
- fprintf(out, "dup %d 10 dict begin\n", i);
- fprintf(out, "/FontType 1 def\n");
- fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
- fprintf(out, "/PaintType %d def\n", dict.paintType);
- fprintf(out, "/Private 32 dict begin\n");
- fwrite(privateDicts[i].dictData->getCString(), 1,
- privateDicts[i].dictData->getLength(), out);
- fprintf(out, "currentdict end def\n");
- fprintf(out, "currentdict end put\n");
- }
- fprintf(out, "def\n");
-
- //~ need to deal with subrs
-
+ 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);
- fprintf(out, "(Hex) %d StartData\n",
+ 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 (cidMap[i+j] >= 0) {
+ if (i+j < nCIDs && cidMap[i+j] >= 0) {
buf[0] = (char)fdSelect[cidMap[i+j]];
} else {
buf[0] = (char)0;
n >>= 8;
}
for (k = 0; k <= gdBytes; ++k) {
- fprintf(out, "%02x", buf[k] & 0xff);
+ sprintf(buf2, "%02x", buf[k] & 0xff);
+ (*outputFunc)(outputStream, buf2, 2);
}
}
- fputc('\n', out);
+ (*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) {
- fprintf(out, "%02x", charStrings->getChar(i+j) & 0xff);
+ sprintf(buf, "%02x", charStrings->getChar(i+j) & 0xff);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
if (i + 32 >= n) {
- fputc('>', out);
+ (*outputFunc)(outputStream, ">", 1);
}
- fputc('\n', out);
+ (*outputFunc)(outputStream, "\n", 1);
}
- for (i = 0; i < nFDs; ++i) {
- delete privateDicts[i].dictData;
- }
- gfree(privateDicts);
- gfree(cidMap);
- gfree(charset);
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, FILE *outA) {
+void Type1CFontFile::convertToType0(char *psName,
+ FontFileOutputFunc outputFuncA,
+ void *outputStreamA) {
Type1CTopDict dict;
Type1CPrivateDict *privateDicts;
Gushort *charset;
int *cidMap;
Guchar *fdSelect;
- Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
- char buf[256];
+ 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, n;
+ int i, j;
- out = outA;
+ outputFunc = outputFuncA;
+ outputStream = outputStreamA;
// read top dict (first font only)
readTopDict(&dict);
privateDicts[0].nominalWidthX = 0;
privateDicts[0].nominalWidthXFP = gFalse;
} else {
- fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
- nFDs = getIndexLen(fdArrayIdx);
+ if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) {
+ goto err0;
+ }
privateDicts = (Type1CPrivateDict *)
gmalloc(nFDs * sizeof(Type1CPrivateDict));
- idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
for (i = 0; i < nFDs; ++i) {
privateDicts[i].dictData = NULL;
- idxPtr0 = idxPtr1;
- idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
- ptr = idxPtr0;
+ }
+ 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 (ptr < idxPtr1) {
- if (*ptr <= 27 || *ptr == 31) {
- key = *ptr++;
+ while (pos < idxPos + idxLen) {
+ if (file[pos] <= 27 || file[pos] == 31) {
+ key = file[pos++];
if (key == 0x0c) {
- key = (key << 8) | *ptr++;
+ 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 {
- x = getNum(&ptr, &isFP);
+ x = getNum(&pos, &isFP);
if (j < 48) {
op[j] = x;
fp[j++] = isFP;
}
// get the glyph count
- charStringsIdxPtr = (Guchar *)file + dict.charStrings;
- nGlyphs = getIndexLen(charStringsIdxPtr);
+ if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) {
+ goto err1;
+ }
// read the FDSelect table
fdSelect = (Guchar *)gmalloc(nGlyphs);
fdSelect[i] = 0;
}
} else {
- ptr = (Guchar *)file + dict.fdSelectOffset;
- fdSelectFmt = *ptr++;
+ pos = dict.fdSelectOffset;
+ if (pos < 0 || pos >= len) {
+ goto err2;
+ }
+ fdSelectFmt = file[pos++];
if (fdSelectFmt == 0) {
- memcpy(fdSelect, ptr, nGlyphs);
+ if (pos + nGlyphs > len) {
+ goto err2;
+ }
+ memcpy(fdSelect, file + pos, nGlyphs);
} else if (fdSelectFmt == 3) {
- nRanges = getWord(ptr, 2);
- ptr += 2;
- gid0 = getWord(ptr, 2);
- ptr += 2;
+ 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 = *ptr++;
- gid1 = getWord(ptr, 2);
- ptr += 2;
+ fd = file[pos++];
+ gid1 = getWord(pos, 2);
+ pos += 2;
for (j = gid0; j < gid1; ++j) {
fdSelect[j] = fd;
}
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) {
}
// font dictionary (unencrypted section)
- fprintf(out, "16 dict begin\n");
- fprintf(out, "/FontName /%s_%02x def\n", psName, i >> 8);
- fprintf(out, "/FontType 1 def\n");
- fprintf(out, "/FontMatrix [%g %g %g %g %g %g] def\n",
+ (*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]);
- fprintf(out, "/FontBBox [%g %g %g %g] def\n",
+ (*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]);
- fprintf(out, "/PaintType %d def\n", dict.paintType);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ sprintf(buf, "/PaintType %d def\n", dict.paintType);
+ (*outputFunc)(outputStream, buf, strlen(buf));
if (dict.paintType != 0) {
- fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
+ sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "/Encoding 256 array\n");
+ (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
for (j = 0; j < 256 && i+j < nCIDs; ++j) {
- fprintf(out, "dup %d /c%02x put\n", j, j);
+ sprintf(buf, "dup %d /c%02x put\n", j, j);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ if (j < 256) {
+ sprintf(buf, "%d 1 255 { 1 index exch /.notdef put } for\n", j);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "readonly def\n");
- fprintf(out, "currentdict end\n");
+ (*outputFunc)(outputStream, "readonly def\n", 13);
+ (*outputFunc)(outputStream, "currentdict end\n", 16);
// start the binary section
- fprintf(out, "currentfile eexec\n");
+ (*outputFunc)(outputStream, "currentfile eexec\n", 18);
r1 = 55665;
line = 0;
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("/MinFeature {16 16} def\n");
+ eexecWrite("/password 5839 def\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 = 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
- idxPtr0 = getIndexValPtr(charStringsIdxPtr, 0);
- idxPtr1 = getIndexValPtr(charStringsIdxPtr, 1);
- n = idxPtr1 - idxPtr0;
- eexecCvtGlyph(".notdef", idxPtr0, n);
+ 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) {
- idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]);
- idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]+1);
- n = idxPtr1 - idxPtr0;
- sprintf(buf, "c%02x", j);
- eexecCvtGlyph(buf, idxPtr0, n);
+ if ((idxPos = getIndexValPos(dict.charStrings,
+ cidMap[i+j], &idxLen)) >= 0) {
+ sprintf(buf, "c%02x", j);
+ eexecCvtGlyph(buf, idxPos, idxLen);
+ }
}
}
eexecWrite("end\n");
// trailer
if (line > 0) {
- fputc('\n', out);
+ (*outputFunc)(outputStream, "\n", 1);
}
for (j = 0; j < 8; ++j) {
- fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
+ (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65);
}
- fprintf(out, "cleartomark\n");
+ (*outputFunc)(outputStream, "cleartomark\n", 12);
}
// write the Type 0 parent font
- fprintf(out, "16 dict begin\n");
- fprintf(out, "/FontName /%s def\n", psName);
- fprintf(out, "/FontType 0 def\n");
- fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
- fprintf(out, "/FMapType 2 def\n");
- fprintf(out, "/Encoding [\n");
+ (*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) {
- fprintf(out, "%d\n", i >> 8);
+ sprintf(buf, "%d\n", i >> 8);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "] def\n");
- fprintf(out, "/FDepVector [\n");
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "/FDepVector [\n", 14);
for (i = 0; i < nCIDs; i += 256) {
- fprintf(out, "/%s_%02x findfont\n", psName, i >> 8);
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ sprintf(buf, "_%02x findfont\n", i >> 8);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "] def\n");
- fprintf(out, "FontName currentdict end definefont pop\n");
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
// clean up
- for (i = 0; i < nFDs; ++i) {
- delete privateDicts[i].dictData;
- }
- gfree(privateDicts);
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) {
- Guchar *idxPtr0, *idxPtr1, *ptr;
+ int idxPos, idxLen, pos;
double x;
GBool isFP;
int key;
int i;
- idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
- idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
dict->version = 0;
dict->notice = 0;
dict->copyright = 0;
dict->supplement = 0;
dict->fdArrayOffset = 0;
dict->fdSelectOffset = 0;
+ if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) {
+ return;
+ }
i = 0;
- ptr = idxPtr0;
- while (ptr < idxPtr1) {
- if (*ptr <= 27 || *ptr == 31) {
- key = *ptr++;
+ pos = idxPos;
+ while (pos < idxPos + idxLen) {
+ if (file[pos] <= 27 || file[pos] == 31) {
+ key = file[pos++];
if (key == 0x0c) {
- key = (key << 8) | *ptr++;
+ if (pos >= idxPos + idxLen) {
+ break;
+ }
+ key = (key << 8) | file[pos++];
}
switch (key) {
case 0x0000: dict->version = (int)op[0]; break;
}
i = 0;
} else {
- x = getNum(&ptr, &isFP);
+ x = getNum(&pos, &isFP);
if (i < 48) {
op[i] = x;
fp[i++] = isFP;
void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
int offset, int size) {
- Guchar *idxPtr0, *idxPtr1, *ptr;
+ int pos;
char eBuf[256];
int key;
double x;
privateDict->defaultWidthXFP = gFalse;
privateDict->nominalWidthX = 0;
privateDict->nominalWidthXFP = gFalse;
- idxPtr0 = (Guchar *)file + offset;
- idxPtr1 = idxPtr0 + size;
- ptr = idxPtr0;
+ if (offset < 0 || offset + size > len) {
+ return;
+ }
+ pos = offset;
i = 0;
- while (ptr < idxPtr1) {
- if (*ptr <= 27 || *ptr == 31) {
- key = *ptr++;
+ while (pos < offset + size) {
+ if (file[pos] <= 27 || file[pos] == 31) {
+ key = file[pos++];
if (key == 0x0c) {
- key = (key << 8) | *ptr++;
+ if (pos >= offset + size) {
+ break;
+ }
+ key = (key << 8) | file[pos++];
}
switch (key) {
case 0x0006:
error(-1, "Got Type 1C InitialRandomSeed");
break;
case 0x0013:
- privateDict->subrsOffset = (int)op[0];
+ privateDict->subrsOffset = offset + (int)op[0];
break;
case 0x0014:
privateDict->defaultWidthX = op[0];
}
i = 0;
} else {
- x = getNum(&ptr, &isFP);
+ x = getNum(&pos, &isFP);
if (i < 48) {
op[i] = x;
fp[i++] = isFP;
Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
Gushort *glyphNames;
- Guchar *ptr;
+ int pos;
int charsetFormat, c;
int nLeft, i, j;
glyphNames = type1CExpertSubsetCharset;
} else {
glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
- glyphNames[0] = 0;
- ptr = (Guchar *)file + charset;
- charsetFormat = *ptr++;
+ 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(ptr, 2);
- ptr += 2;
+ glyphNames[i] = getWord(pos, 2);
+ pos += 2;
}
} else if (charsetFormat == 1) {
i = 1;
while (i < nGlyphs) {
- c = getWord(ptr, 2);
- ptr += 2;
- nLeft = *ptr++;
+ if (pos + 3 > len) {
+ goto err0;
+ }
+ c = getWord(pos, 2);
+ pos += 2;
+ nLeft = file[pos++];
for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
glyphNames[i++] = c++;
}
} else if (charsetFormat == 2) {
i = 1;
while (i < nGlyphs) {
- c = getWord(ptr, 2);
- ptr += 2;
- nLeft = getWord(ptr, 2);
- ptr += 2;
+ if (pos + 4 > len) {
+ goto err0;
+ }
+ 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;
}
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);
+ (*outputFunc)(outputStream, &hexChars[x >> 4], 1);
+ (*outputFunc)(outputStream, &hexChars[x & 0x0f], 1);
line += 2;
if (line == 64) {
- fputc('\n', out);
+ (*outputFunc)(outputStream, "\n", 1);
line = 0;
}
}
}
-void Type1CFontFile::eexecCvtGlyph(char *glyphName, Guchar *s, int n) {
+void Type1CFontFile::eexecCvtGlyph(char *glyphName, int pos, int n) {
char eBuf[256];
- cvtGlyph(s, n);
+ cvtGlyph(pos, n, gTrue);
sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength());
eexecWrite(eBuf);
eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
delete charBuf;
}
-void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
- int nHints;
+void Type1CFontFile::cvtGlyph(int pos, int n, GBool top) {
int x;
- GBool first = gTrue;
+ int subrPos, subrLen;
double d, dx, dy;
GBool dFP;
Gushort r2;
Guchar byte;
int i, k;
- charBuf = new GString();
- charBuf->append((char)73);
- charBuf->append((char)58);
- charBuf->append((char)147);
- charBuf->append((char)134);
+ if (pos < 0 || pos + n > len) {
+ return;
+ }
- i = 0;
- nOps = 0;
- nHints = 0;
- while (i < n) {
- if (s[i] == 12) {
- switch (s[i+1]) {
+ 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;
+ }
+ switch (file[i+1]) {
case 0: // dotsection (should be Type 1 only?)
// ignored
break;
case 28: // exch
case 29: // index
case 30: // roll
- error(-1, "Unimplemented Type 2 charstring op: 12.%d", s[i+1]);
+ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]);
break;
default:
- error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]);
+ error(-1, "Illegal Type 2 charstring op: 12.%d", file[i+1]);
break;
}
i += 2;
nOps = 0;
- } else if (s[i] == 19) { // hintmask
+ } else if (file[i] == 19) { // hintmask
// ignored
- if (first) {
- cvtGlyphWidth(nOps == 1);
- first = gFalse;
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1);
+ firstOp = gFalse;
}
if (nOps > 0) {
if (nOps & 1) {
}
i += 1 + ((nHints + 7) >> 3);
nOps = 0;
- } else if (s[i] == 20) { // cntrmask
+ } else if (file[i] == 20) { // cntrmask
// ignored
- if (first) {
- cvtGlyphWidth(nOps == 1);
- first = gFalse;
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1);
+ firstOp = gFalse;
}
if (nOps > 0) {
if (nOps & 1) {
}
i += 1 + ((nHints + 7) >> 3);
nOps = 0;
- } else if (s[i] == 28) {
- x = (s[i+1] << 8) + s[i+2];
+ } else if (file[i] == 28) {
+ if (i + 3 > len) {
+ break;
+ }
+ x = (file[i+1] << 8) + file[i+2];
if (x & 0x8000) {
x |= -1 << 15;
}
op[nOps++] = x;
}
i += 3;
- } else if (s[i] <= 31) {
- switch (s[i]) {
+ } 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 (first) {
+ if (firstOp) {
cvtGlyphWidth(nOps == 2);
- first = gFalse;
+ firstOp = gFalse;
}
if (nOps != 1) {
error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps);
}
break;
case 14: // endchar / seac
- if (first) {
+ if (firstOp) {
cvtGlyphWidth(nOps == 1 || nOps == 5);
- first = gFalse;
+ firstOp = gFalse;
}
if (nOps == 4) {
eexecDumpNum(0, 0);
}
break;
case 21: // rmoveto
- if (first) {
+ if (firstOp) {
cvtGlyphWidth(nOps == 3);
- first = gFalse;
+ firstOp = gFalse;
}
if (nOps != 2) {
error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps);
eexecDumpOp1(21);
break;
case 22: // hmoveto
- if (first) {
+ if (firstOp) {
cvtGlyphWidth(nOps == 2);
- first = gFalse;
+ firstOp = gFalse;
}
if (nOps != 1) {
error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps);
}
break;
case 1: // hstem
- if (first) {
+ if (firstOp) {
cvtGlyphWidth(nOps & 1);
- first = gFalse;
+ firstOp = gFalse;
}
if (nOps & 1) {
error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps);
nHints += nOps / 2;
break;
case 3: // vstem
- if (first) {
+ if (firstOp) {
cvtGlyphWidth(nOps & 1);
- first = gFalse;
+ firstOp = gFalse;
}
if (nOps & 1) {
error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps);
}
nHints += nOps / 2;
break;
+ case 15: // (obsolete)
+ // this op is ignored, but we need the glyph width
+ if (firstOp) {
+ cvtGlyphWidth(nOps > 0);
+ firstOp = gFalse;
+ }
+ break;
case 18: // hstemhm
// ignored
- if (first) {
+ if (firstOp) {
cvtGlyphWidth(nOps & 1);
- first = gFalse;
+ firstOp = gFalse;
}
if (nOps & 1) {
error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps);
break;
case 23: // vstemhm
// ignored
- if (first) {
+ if (firstOp) {
cvtGlyphWidth(nOps & 1);
- first = gFalse;
+ firstOp = gFalse;
}
if (nOps & 1) {
error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps);
}
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]);
+ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]);
break;
default:
- error(-1, "Illegal Type 2 charstring op: %d", s[i]);
+ error(-1, "Illegal Type 2 charstring op: %d", file[i]);
break;
}
++i;
nOps = 0;
- } else if (s[i] <= 246) {
+ } else if (file[i] <= 246) {
if (nOps < 48) {
fp[nOps] = gFalse;
- op[nOps++] = (int)s[i] - 139;
+ op[nOps++] = (int)file[i] - 139;
}
++i;
- } else if (s[i] <= 250) {
+ } else if (file[i] <= 250) {
+ if (i + 2 > len) {
+ break;
+ }
if (nOps < 48) {
fp[nOps] = gFalse;
- op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108;
+ op[nOps++] = (((int)file[i] - 247) << 8) + (int)file[i+1] + 108;
}
i += 2;
- } else if (s[i] <= 254) {
+ } else if (file[i] <= 254) {
+ if (i + 2 > len) {
+ break;
+ }
if (nOps < 48) {
fp[nOps] = gFalse;
- op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108;
+ op[nOps++] = -(((int)file[i] - 251) << 8) - (int)file[i+1] - 108;
}
i += 2;
} else {
- x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4];
- if (x & 0x80000000)
+ 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;
}
// charstring encryption
- r2 = 4330;
- for (i = 0; i < charBuf->getLength(); ++i) {
- byte = charBuf->getChar(i) ^ (r2 >> 8);
- charBuf->setChar(i, byte);
- r2 = (byte + r2) * 52845 + 22719;
+ 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;
+ }
}
}
for (i = 0; i < n; ++i) {
x = s[i] ^ (r1 >> 8);
r1 = (x + r1) * 52845 + 22719;
- fputc(hexChars[x >> 4], out);
- fputc(hexChars[x & 0x0f], out);
+ (*outputFunc)(outputStream, &hexChars[x >> 4], 1);
+ (*outputFunc)(outputStream, &hexChars[x & 0x0f], 1);
line += 2;
if (line == 64) {
- fputc('\n', out);
+ (*outputFunc)(outputStream, "\n", 1);
line = 0;
}
}
sprintf(buf, "] def\n");
}
-int Type1CFontFile::getIndexLen(Guchar *indexPtr) {
- return (int)getWord(indexPtr, 2);
+int Type1CFontFile::getIndexLen(int indexPos) {
+ if (indexPos + 2 > len) {
+ return -1;
+ }
+ return (int)getWord(indexPos, 2);
}
-Guchar *Type1CFontFile::getIndexValPtr(Guchar *indexPtr, int i) {
- int n, offSize;
- Guchar *idxStartPtr;
+int Type1CFontFile::getIndexValPos(int indexPos, int i, int *valLen) {
+ int n, offSize, idxStartPos;
+ int pos0, pos1;
- n = (int)getWord(indexPtr, 2);
- offSize = indexPtr[2];
- idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
- return idxStartPtr + getWord(indexPtr + 3 + i * offSize, offSize);
+ 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;
}
-Guchar *Type1CFontFile::getIndexEnd(Guchar *indexPtr) {
- int n, offSize;
- Guchar *idxStartPtr;
+int Type1CFontFile::getIndexEnd(int indexPos) {
+ int n, offSize, idxStartPos;
- n = (int)getWord(indexPtr, 2);
- offSize = indexPtr[2];
- idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
- return idxStartPtr + getWord(indexPtr + 3 + n * offSize, offSize);
+ if (indexPos < 0 || 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(Guchar *ptr, int size) {
+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) + *ptr++;
+ x = (x << 8) + file[pos + i];
}
return x;
}
-double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) {
+double Type1CFontFile::getNum(int *pos, GBool *isFP) {
static char nybChars[16] = "0123456789.ee -";
int b0, b, nyb0, nyb1;
double x;
x = 0;
*isFP = gFalse;
- b0 = (*ptr)[0];
+ if (*pos >= len) {
+ return 0;
+ }
+ b0 = file[*pos];
if (b0 < 28) {
x = 0;
} else if (b0 == 28) {
- x = ((*ptr)[1] << 8) + (*ptr)[2];
- *ptr += 3;
+ if (*pos + 3 <= len) {
+ x = (file[*pos + 1] << 8) + file[*pos + 2];
+ *pos += 3;
+ }
} else if (b0 == 29) {
- x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4];
- *ptr += 5;
+ 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) {
- *ptr += 1;
+ *pos += 1;
i = 0;
do {
- b = *(*ptr)++;
+ if (*pos >= len) {
+ break;
+ }
+ b = file[(*pos)++];
nyb0 = b >> 4;
nyb1 = b & 0x0f;
if (nyb0 == 0xf) {
x = 0;
} else if (b0 < 247) {
x = b0 - 139;
- *ptr += 1;
+ *pos += 1;
} else if (b0 < 251) {
- x = ((b0 - 247) << 8) + (*ptr)[1] + 108;
- *ptr += 2;
+ if (*pos + 2 <= len) {
+ x = ((b0 - 247) << 8) + file[*pos + 1] + 108;
+ *pos += 2;
+ }
} else {
- x = -((b0 - 251) << 8) - (*ptr)[1] - 108;
- *ptr += 2;
+ if (*pos + 2 <= len) {
+ x = -((b0 - 251) << 8) - file[*pos + 1] - 108;
+ *pos += 2;
+ }
}
return x;
}
char *Type1CFontFile::getString(int sid, char *buf) {
- Guchar *idxPtr0, *idxPtr1;
- int n;
+ int idxPos, n;
if (sid < 391) {
strcpy(buf, type1CStdStrings[sid]);
} else {
sid -= 391;
- idxPtr0 = getIndexValPtr(stringIdxPtr, sid);
- idxPtr1 = getIndexValPtr(stringIdxPtr, sid + 1);
- if ((n = idxPtr1 - idxPtr0) > 255) {
- n = 255;
+ 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';
}
- strncpy(buf, (char *)idxPtr0, n);
- buf[n] = '\0';
}
return buf;
}
GBool required; // required by the TrueType spec?
};
+struct TTFontCmap {
+ int platform;
+ int encoding;
+ int offset;
+ int len;
+ int fmt;
+};
+
// TrueType tables to be embedded in Type 42 fonts.
// NB: the table names must be in alphabetical order here.
#define nT42Tables 11
"dmacron"
};
-enum T42FontIndexMode {
- t42FontModeUnicode,
- t42FontModeCharCode,
- t42FontModeCharCodeOffset,
- t42FontModeMacRoman
+struct TrueTypeLoca {
+ int idx;
+ int pos;
+ int length;
};
TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
- int pos, i;
+ int pos, pos2, i, idx, n, length;
+ Guint size, startPos, endPos;
file = fileA;
len = lenA;
encoding = NULL;
+ cmaps = NULL;
+ nCmaps = 0;
// read table directory
nTables = getUShort(4);
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;
}
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);
// read the 'maxp' table
pos = seekTable("maxp");
nGlyphs = getUShort(pos + 4);
+
+ // read the 'cmap' table
+ if ((pos = seekTable("cmap")) >= 0) {
+ pos2 = pos + 2;
+ if ((nCmaps = getUShort(pos2)) > 0) {
+ pos2 += 2;
+ cmaps = (TTFontCmap *)gmalloc(nCmaps * sizeof(TTFontCmap));
+ for (i = 0; i < nCmaps; ++i) {
+ cmaps[i].platform = getUShort(pos2);
+ cmaps[i].encoding = getUShort(pos2 + 2);
+ cmaps[i].offset = pos + getULong(pos2 + 4);
+ pos2 += 8;
+ cmaps[i].fmt = getUShort(cmaps[i].offset);
+ cmaps[i].len = getUShort(cmaps[i].offset + 2);
+ }
+ }
+ }
}
TrueTypeFontFile::~TrueTypeFontFile() {
}
gfree(encoding);
}
+ if (cmaps) {
+ gfree(cmaps);
+ }
gfree(tableHdrs);
}
}
char **TrueTypeFontFile::getEncoding() {
- int cmap[256];
- int nCmaps, cmapPlatform, cmapEncoding, cmapFmt;
- int cmapLen, cmapOffset, cmapFirst;
- int segCnt, segStart, segEnd, segDelta, segOffset;
- int pos, i, j, k;
- Guint fmt;
- GString *s;
- int stringIdx, stringPos, n;
+ int i;
- if (encoding) {
- return encoding;
+ if (!encoding) {
+ encoding = (char **)gmalloc(256 * sizeof(char *));
+ for (i = 0; i < 256; ++i) {
+ encoding[i] = NULL;
+ }
}
+ return encoding;
+}
- //----- construct the (char code) -> (glyph idx) mapping
+int TrueTypeFontFile::getNumCmaps() {
+ return nCmaps;
+}
- // map everything to the missing glyph
- for (i = 0; i < 256; ++i) {
- cmap[i] = 0;
- }
+int TrueTypeFontFile::getCmapPlatform(int i) {
+ return cmaps[i].platform;
+}
- // look for the 'cmap' table
- if ((pos = seekTable("cmap")) >= 0) {
- nCmaps = getUShort(pos+2);
-
- // if the font has a Windows-symbol cmap, use it;
- // otherwise, use the first cmap in the table
- for (i = 0; i < nCmaps; ++i) {
- cmapPlatform = getUShort(pos + 4 + 8*i);
- cmapEncoding = getUShort(pos + 4 + 8*i + 2);
- if (cmapPlatform == 3 && cmapEncoding == 0) {
- break;
- }
- }
- if (i >= nCmaps) {
- i = 0;
- cmapPlatform = getUShort(pos + 4);
- cmapEncoding = getUShort(pos + 4 + 2);
- }
- pos += getULong(pos + 4 + 8*i + 4);
+int TrueTypeFontFile::getCmapEncoding(int i) {
+ return cmaps[i].encoding;
+}
- // read the cmap
- cmapFmt = getUShort(pos);
- switch (cmapFmt) {
- case 0: // byte encoding table (Apple standard)
- cmapLen = getUShort(pos + 2);
- for (i = 0; i < cmapLen && i < 256; ++i) {
- cmap[i] = getByte(pos + 6 + i);
- }
- break;
- case 4: // segment mapping to delta values (Microsoft standard)
- if (cmapPlatform == 3 && cmapEncoding == 0) {
- // Windows-symbol uses char codes 0xf000 - 0xf0ff
- cmapOffset = 0xf000;
- } else {
- cmapOffset = 0;
- }
- segCnt = getUShort(pos + 6) / 2;
- for (i = 0; i < segCnt; ++i) {
- segEnd = getUShort(pos + 14 + 2*i);
- segStart = getUShort(pos + 16 + 2*segCnt + 2*i);
- segDelta = getUShort(pos + 16 + 4*segCnt + 2*i);
- segOffset = getUShort(pos + 16 + 6*segCnt + 2*i);
- if (segStart - cmapOffset <= 0xff &&
- segEnd - cmapOffset >= 0) {
- for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset;
- j <= segEnd && j - cmapOffset <= 0xff;
- ++j) {
- if (segOffset == 0) {
- k = (j + segDelta) & 0xffff;
- } else {
- k = getUShort(pos + 16 + 6*segCnt + 2*i +
- segOffset + 2 * (j - segStart));
- if (k != 0) {
- k = (k + segDelta) & 0xffff;
- }
- }
- cmap[j - cmapOffset] = k;
- }
- }
- }
- break;
- case 6: // trimmed table mapping
- cmapFirst = getUShort(pos + 6);
- cmapLen = getUShort(pos + 8);
- for (i = cmapFirst; i < 256 && i < cmapFirst + cmapLen; ++i) {
- cmap[i] = getUShort(pos + 10 + 2*i);
- }
- break;
- default:
- error(-1, "Unimplemented cmap format (%d) in TrueType font file",
- cmapFmt);
- break;
+int TrueTypeFontFile::findCmap(int platform, int enc) {
+ int i;
+
+ for (i = 0; i < nCmaps; ++i) {
+ if (cmaps[i].platform == platform && cmaps[i].encoding == enc) {
+ return i;
}
}
+ return -1;
+}
- //----- construct the (glyph idx) -> (glyph name) mapping
- //----- and compute the (char code) -> (glyph name) mapping
+Gushort TrueTypeFontFile::mapCodeToGID(int i, int c) {
+ if (i < 0 || i >= nCmaps) {
+ return 0;
+ }
+ return (Gushort)getCmapEntry(cmaps[i].fmt, cmaps[i].offset, c);
+}
- encoding = (char **)gmalloc(256 * sizeof(char *));
- for (i = 0; i < 256; ++i) {
- encoding[i] = NULL;
+GHash *TrueTypeFontFile::getNameToGID() {
+ GHash *nameToGID;
+ Guint fmt;
+ GString *s;
+ int stringIdx, stringPos, pos, i, j, n;
+
+ if ((pos = seekTable("post")) < 0) {
+ return NULL;
}
- if ((pos = seekTable("post")) >= 0) {
- fmt = getULong(pos);
+ fmt = getULong(pos);
+ nameToGID = NULL;
- // Apple font
- if (fmt == 0x00010000) {
- for (i = 0; i < 256; ++i) {
- j = (cmap[i] < 258) ? cmap[i] : 0;
- encoding[i] = copyString(macGlyphNames[j]);
- }
+ // Apple font
+ if (fmt == 0x00010000) {
+ nameToGID = new GHash(gTrue);
+ for (i = 0; i < 258; ++i) {
+ nameToGID->add(new GString(macGlyphNames[i]), (void *)i);
+ }
- // Microsoft font
- } else if (fmt == 0x00020000) {
- stringIdx = 0;
- stringPos = pos + 34 + 2*nGlyphs;
- for (i = 0; i < 256; ++i) {
- if (cmap[i] < nGlyphs) {
- j = getUShort(pos + 34 + 2 * cmap[i]);
- if (j < 258) {
- encoding[i] = copyString(macGlyphNames[j]);
- } else {
- j -= 258;
- if (j != stringIdx) {
- for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs;
- stringIdx < j;
- ++stringIdx, stringPos += 1 + getByte(stringPos)) ;
- }
- n = getByte(stringPos);
- s = new GString(file + stringPos + 1, n);
- encoding[i] = copyString(s->getCString());
- delete s;
- ++stringIdx;
- stringPos += 1 + n;
- }
- } else {
- encoding[i] = copyString(macGlyphNames[0]);
+ // Microsoft font
+ } else if (fmt == 0x00020000) {
+ nameToGID = new GHash(gTrue);
+ n = getUShort(pos + 32);
+ if (n > nGlyphs) {
+ n = nGlyphs;
+ }
+ stringIdx = 0;
+ stringPos = pos + 34 + 2*nGlyphs;
+ for (i = 0; i < nGlyphs; ++i) {
+ j = getUShort(pos + 34 + 2*i);
+ if (j < 258) {
+ nameToGID->remove(macGlyphNames[j]);
+ nameToGID->add(new GString(macGlyphNames[j]), (void *)i);
+ } else {
+ j -= 258;
+ if (j != stringIdx) {
+ for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs;
+ stringIdx < j;
+ ++stringIdx, stringPos += 1 + getByte(stringPos)) ;
}
- }
-
- // 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;
+ n = getByte(stringPos);
+ if (stringPos >= 0 && stringPos + 1 + n <= len) {
+ s = new GString(file + stringPos + 1, n);
+ nameToGID->remove(s);
+ nameToGID->add(s, (void *)i);
}
- 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]);
+ ++stringIdx;
+ stringPos += 1 + n;
}
}
- // 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]);
+ // Apple subset
+ } else if (fmt == 0x000280000) {
+ nameToGID = new GHash(gTrue);
+ for (i = 0; i < nGlyphs; ++i) {
+ j = getByte(pos + 32 + i);
+ if (j < 258) {
+ nameToGID->remove(macGlyphNames[j]);
+ nameToGID->add(new GString(macGlyphNames[j]), (void *)i);
+ }
}
}
- return encoding;
+ return nameToGID;
}
void TrueTypeFontFile::convertToType42(char *name, char **encodingA,
- CharCodeToUnicode *toUnicode,
- GBool pdfFontHasEncoding, FILE *out) {
+ GBool pdfFontHasEncoding,
+ Gushort *codeToGID,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
+ char buf[512];
+
// write the header
- fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+ sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+ (*outputFunc)(outputStream, buf, strlen(buf));
// begin the font dictionary
- fprintf(out, "10 dict begin\n");
- fprintf(out, "/FontName /%s def\n", name);
- fprintf(out, "/FontType 42 def\n");
- fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
- fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ (*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]);
- fprintf(out, "/PaintType 0 def\n");
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
// write the guts of the dictionary
- cvtEncoding(encodingA, out);
- cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, out);
- cvtSfnts(out, NULL);
+ cvtEncoding(encodingA, pdfFontHasEncoding, outputFunc, outputStream);
+ cvtCharStrings(encodingA, pdfFontHasEncoding, codeToGID,
+ outputFunc, outputStream);
+ cvtSfnts(outputFunc, outputStream, NULL);
// end the dictionary and define the font
- fprintf(out, "FontName currentdict end definefont pop\n");
+ (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
}
void TrueTypeFontFile::convertToCIDType2(char *name, Gushort *cidMap,
- int nCIDs, FILE *out) {
+ int nCIDs,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
+ char buf[512];
Gushort cid;
int i, j, k;
// write the header
- fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+ sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+ (*outputFunc)(outputStream, buf, strlen(buf));
// begin the font dictionary
- fprintf(out, "20 dict begin\n");
- fprintf(out, "/CIDFontName /%s def\n", name);
- fprintf(out, "/CIDFontType 2 def\n");
- fprintf(out, "/FontType 42 def\n");
- fprintf(out, "/CIDSystemInfo 3 dict dup begin\n");
- fprintf(out, " /Registry (Adobe) def\n");
- fprintf(out, " /Ordering (Identity) def\n");
- fprintf(out, " /Supplement 0 def\n");
- fprintf(out, " end def\n");
- fprintf(out, "/GDBytes 2 def\n");
+ (*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) {
- fprintf(out, "/CIDCount %d def\n", nCIDs);
+ sprintf(buf, "/CIDCount %d def\n", nCIDs);
+ (*outputFunc)(outputStream, buf, strlen(buf));
if (nCIDs > 32767) {
- fprintf(out, "/CIDMap [");
+ (*outputFunc)(outputStream, "/CIDMap [", 9);
for (i = 0; i < nCIDs; i += 32768 - 16) {
- fprintf(out, "<\n");
+ (*outputFunc)(outputStream, "<\n", 2);
for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
- fprintf(out, " ");
+ (*outputFunc)(outputStream, " ", 2);
for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
cid = cidMap[i+j+k];
- fprintf(out, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+ sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "\n");
+ (*outputFunc)(outputStream, "\n", 1);
}
- fprintf(out, " >");
+ (*outputFunc)(outputStream, " >", 3);
}
- fprintf(out, "\n");
- fprintf(out, "] def\n");
+ (*outputFunc)(outputStream, "\n", 1);
+ (*outputFunc)(outputStream, "] def\n", 6);
} else {
- fprintf(out, "/CIDMap <\n");
+ (*outputFunc)(outputStream, "/CIDMap <\n", 10);
for (i = 0; i < nCIDs; i += 16) {
- fprintf(out, " ");
+ (*outputFunc)(outputStream, " ", 2);
for (j = 0; j < 16 && i+j < nCIDs; ++j) {
cid = cidMap[i+j];
- fprintf(out, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+ sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "\n");
+ (*outputFunc)(outputStream, "\n", 1);
}
- fprintf(out, "> def\n");
+ (*outputFunc)(outputStream, "> def\n", 6);
}
} else {
// direct mapping - just fill the string(s) with s[i]=i
- fprintf(out, "/CIDCount %d def\n", nGlyphs);
+ sprintf(buf, "/CIDCount %d def\n", nGlyphs);
+ (*outputFunc)(outputStream, buf, strlen(buf));
if (nGlyphs > 32767) {
- fprintf(out, "/CIDMap [\n");
+ (*outputFunc)(outputStream, "/CIDMap [\n", 10);
for (i = 0; i < nGlyphs; i += 32767) {
j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
- fprintf(out, " %d string 0 1 %d {\n", 2 * j, j - 1);
- fprintf(out, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
- fprintf(out, " 1 index exch dup 2 mul 1 add exch %d add"
+ 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);
- fprintf(out, " } for\n");
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, " } for\n", 8);
}
- fprintf(out, "] def\n");
+ (*outputFunc)(outputStream, "] def\n", 6);
} else {
- fprintf(out, "/CIDMap %d string\n", 2 * nGlyphs);
- fprintf(out, " 0 1 %d {\n", nGlyphs - 1);
- fprintf(out, " 2 copy dup 2 mul exch -8 bitshift put\n");
- fprintf(out, " 1 index exch dup 2 mul 1 add exch 255 and put\n");
- fprintf(out, " } for\n");
- fprintf(out, "def\n");
+ 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);
}
}
- fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
- fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ (*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]);
- fprintf(out, "/PaintType 0 def\n");
- fprintf(out, "/Encoding [] readonly def\n");
- fprintf(out, "/CharStrings 1 dict dup begin\n");
- fprintf(out, " /.notdef 0 def\n");
- fprintf(out, " end readonly def\n");
+ (*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(out, NULL);
+ cvtSfnts(outputFunc, outputStream, NULL);
// end the dictionary and define the font
- fprintf(out, "CIDFontName currentdict end /CIDFont defineresource pop\n");
+ (*outputFunc)(outputStream,
+ "CIDFontName currentdict end /CIDFont defineresource pop\n",
+ 56);
}
void TrueTypeFontFile::convertToType0(char *name, Gushort *cidMap,
- int nCIDs, FILE *out) {
+ 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(out, sfntsName);
+ cvtSfnts(outputFunc, outputStream, sfntsName);
delete sfntsName;
// write the descendant Type 42 fonts
n = cidMap ? nCIDs : nGlyphs;
for (i = 0; i < n; i += 256) {
- fprintf(out, "10 dict begin\n");
- fprintf(out, "/FontName /%s_%02x def\n", name, i >> 8);
- fprintf(out, "/FontType 42 def\n");
- fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
- fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ (*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]);
- fprintf(out, "/PaintType 0 def\n");
- fprintf(out, "/sfnts %s_sfnts def\n", name);
- fprintf(out, "/Encoding 256 array\n");
+ (*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) {
- fprintf(out, "dup %d /c%02x put\n", j, j);
+ sprintf(buf, "dup %d /c%02x put\n", j, j);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "readonly def\n");
- fprintf(out, "/CharStrings 257 dict dup begin\n");
- fprintf(out, "/.notdef 0 def\n");
+ (*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) {
- fprintf(out, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
+ sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "end readonly def\n");
- fprintf(out, "FontName currentdict end definefont pop\n");
+ (*outputFunc)(outputStream, "end readonly def\n", 17);
+ (*outputFunc)(outputStream,
+ "FontName currentdict end definefont pop\n", 40);
}
// write the Type 0 parent font
- fprintf(out, "16 dict begin\n");
- fprintf(out, "/FontName /%s def\n", name);
- fprintf(out, "/FontType 0 def\n");
- fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
- fprintf(out, "/FMapType 2 def\n");
- fprintf(out, "/Encoding [\n");
+ (*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) {
- fprintf(out, "%d\n", i >> 8);
+ sprintf(buf, "%d\n", i >> 8);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "] def\n");
- fprintf(out, "/FDepVector [\n");
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "/FDepVector [\n", 14);
for (i = 0; i < n; i += 256) {
- fprintf(out, "/%s_%02x findfont\n", name, i >> 8);
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, name, strlen(name));
+ sprintf(buf, "_%02x findfont\n", i >> 8);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
- fprintf(out, "] def\n");
- fprintf(out, "FontName currentdict end definefont pop\n");
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
}
int TrueTypeFontFile::getByte(int pos) {
for (i = 0; i < nTables; ++i) {
if (!strncmp(tableHdrs[i].tag, tag, 4)) {
- return tableHdrs[i].offset;
+ return (int)tableHdrs[i].offset;
}
}
return -1;
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, FILE *out) {
+void TrueTypeFontFile::cvtEncoding(char **encodingA, GBool pdfFontHasEncoding,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
char *name;
+ char buf[64];
int i;
- fprintf(out, "/Encoding 256 array\n");
- for (i = 0; i < 256; ++i) {
- if (!(name = encodingA[i])) {
- name = ".notdef";
+ (*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));
}
- fprintf(out, "dup %d /%s put\n", i, name);
}
- fprintf(out, "readonly def\n");
+ (*outputFunc)(outputStream, "readonly def\n", 13);
}
void TrueTypeFontFile::cvtCharStrings(char **encodingA,
- CharCodeToUnicode *toUnicode,
- GBool pdfFontHasEncoding, FILE *out) {
- int unicodeCmap, macRomanCmap, msSymbolCmap;
- int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapOffset;
- T42FontIndexMode mode;
+ GBool pdfFontHasEncoding,
+ Gushort *codeToGID,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
char *name;
- Unicode u;
- int pos, i, j, k;
+ char buf[64], buf2[16];
+ int i, k;
// always define '.notdef'
- fprintf(out, "/CharStrings 256 dict dup begin\n");
- fprintf(out, "/.notdef 0 def\n");
+ (*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 TrueType font has a Macintosh Roman cmap, use it,
- // and reverse map the char names through MacRomanEncoding to
- // get char codes.
- // 2. If the PDF font does not have an encoding:
- // 2a. If the TrueType font has a Macintosh Roman cmap, use it,
- // and use char codes directly.
- // 2b. If the TrueType font has a Microsoft Symbol cmap, use it,
- // and use (0xf000 + char code).
- // 3. If none of these rules apply, use the first cmap and hope for
- // the best (this shouldn't happen).
- nCmaps = getUShort(pos+2);
- unicodeCmap = macRomanCmap = msSymbolCmap = -1;
- cmapOffset = 0;
- for (i = 0; i < nCmaps; ++i) {
- cmapPlatform = getUShort(pos + 4 + 8*i);
- cmapEncoding = getUShort(pos + 4 + 8*i + 2);
- if (cmapPlatform == 3 && cmapEncoding == 1) {
- unicodeCmap = i;
- } else if (cmapPlatform == 1 && cmapEncoding == 0) {
- macRomanCmap = i;
- } else if (cmapPlatform == 3 && cmapEncoding == 0) {
- msSymbolCmap = i;
- }
- }
- i = 0;
- mode = t42FontModeCharCode;
- if (pdfFontHasEncoding) {
- if (unicodeCmap >= 0) {
- i = unicodeCmap;
- mode = t42FontModeUnicode;
- } else if (macRomanCmap >= 0) {
- i = macRomanCmap;
- mode = t42FontModeMacRoman;
- }
- } else {
- if (macRomanCmap >= 0) {
- i = macRomanCmap;
- mode = t42FontModeCharCode;
- } else if (msSymbolCmap >= 0) {
- i = msSymbolCmap;
- mode = t42FontModeCharCodeOffset;
- cmapOffset = 0xf000;
- }
- }
- cmapPlatform = getUShort(pos + 4 + 8*i);
- cmapEncoding = getUShort(pos + 4 + 8*i + 2);
- pos += getULong(pos + 4 + 8*i + 4);
- cmapFmt = getUShort(pos);
- if (cmapFmt != 0 && cmapFmt != 4 && cmapFmt != 6) {
- error(-1, "Unimplemented cmap format (%d) in TrueType font file",
- cmapFmt);
+ if (nCmaps == 0) {
goto err;
}
// map char name to glyph index:
// 1. use encoding to map name to char code
- // 2. use cmap to map char code to glyph index
- j = 0; // make gcc happy
- for (i = 0; i < 256; ++i) {
- name = encodingA[i];
+ // 2. use codeToGID 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);
- j = (int)u;
- break;
- case t42FontModeCharCode:
- j = i;
- break;
- case t42FontModeCharCodeOffset:
- j = cmapOffset + i;
- break;
- case t42FontModeMacRoman:
- j = globalParams->getMacRomanCharCode(name);
- break;
- }
+ k = codeToGID[i];
// note: Distiller (maybe Adobe's PS interpreter in general)
// doesn't like TrueType fonts that have CharStrings entries
// which point to nonexistent glyphs, hence the (k < nGlyphs)
// test
- if ((k = getCmapEntry(cmapFmt, pos, j)) > 0 &&
- k < nGlyphs) {
- fprintf(out, "/%s %d def\n", name, k);
+ if (k > 0 && k < nGlyphs) {
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, name, strlen(name));
+ sprintf(buf, " %d def\n", k);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
}
}
err:
- fprintf(out, "end readonly def\n");
+ (*outputFunc)(outputStream, "end readonly def\n", 17);
}
int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) {
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 {
return 0;
}
-void TrueTypeFontFile::cvtSfnts(FILE *out, GString *name) {
+static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
+ return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx;
+}
+
+static int cmpTrueTypeLocaPos(const void *p1, const void *p2) {
+ if (((TrueTypeLoca *)p1)->pos == ((TrueTypeLoca *)p2)->pos) {
+ return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx;
+ } else {
+ return ((TrueTypeLoca *)p1)->pos - ((TrueTypeLoca *)p2)->pos;
+ }
+}
+
+void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc,
+ void *outputStream, GString *name) {
TTFontTableHdr newTableHdrs[nT42Tables];
char tableDir[12 + nT42Tables*16];
char headTable[54];
- int *origLocaTable;
+ TrueTypeLoca *origLocaTable;
char *locaTable;
int nNewTables;
Guint checksum;
memcpy(headTable, file + seekTable("head"), 54);
headTable[8] = headTable[9] = headTable[10] = headTable[11] = (char)0;
- // read the original 'loca' table and construct the new one
- // (pad each glyph out to a multiple of 4 bytes)
- origLocaTable = (int *)gmalloc((nGlyphs + 1) * sizeof(int));
+ // 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] = getULong(pos + 4*i);
+ origLocaTable[i].pos = getULong(pos + 4*i);
} else {
- origLocaTable[i] = 2 * getUShort(pos + 2*i);
+ origLocaTable[i].pos = 2 * getUShort(pos + 2*i);
}
}
- locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
- if (locaFmt) {
- locaTable[0] = locaTable[1] = locaTable[2] = locaTable[3] = 0;
- } else {
- locaTable[0] = locaTable[1] = 0;
+ 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 = 1; i <= nGlyphs; ++i) {
- length = origLocaTable[i] - origLocaTable[i-1];
- if (length & 3) {
- length += 4 - (length & 3);
- }
- pos += length;
+ for (i = 0; i <= nGlyphs; ++i) {
if (locaFmt) {
locaTable[4*i ] = (char)(pos >> 24);
locaTable[4*i+1] = (char)(pos >> 16);
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
checksum = 0;
glyfPos = seekTable("glyf");
for (j = 0; j < nGlyphs; ++j) {
- glyphLength = origLocaTable[j+1] - origLocaTable[j];
+ glyphLength = origLocaTable[j].length;
pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0;
length += glyphLength + pad;
- checksum += computeTableChecksum(file + glyfPos + origLocaTable[j],
- glyphLength);
+ 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) {
// start the sfnts array
if (name) {
- fprintf(out, "/%s [\n", name->getCString());
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, name->getCString(), name->getLength());
+ (*outputFunc)(outputStream, " [\n", 3);
} else {
- fprintf(out, "/sfnts [\n");
+ (*outputFunc)(outputStream, "/sfnts [\n", 9);
}
// write the table directory
- dumpString(tableDir, 12 + nNewTables*16, out);
+ dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
// write the tables
for (i = 0; i < nNewTables; ++i) {
if (i == t42HeadTable) {
- dumpString(headTable, 54, out);
+ dumpString(headTable, 54, outputFunc, outputStream);
} else if (i == t42LocaTable) {
length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
- dumpString(locaTable, length, out);
+ dumpString(locaTable, length, outputFunc, outputStream);
} else if (i == t42GlyfTable) {
glyfPos = seekTable("glyf");
for (j = 0; j < nGlyphs; ++j) {
- length = origLocaTable[j+1] - origLocaTable[j];
- if (length > 0) {
- dumpString(file + glyfPos + origLocaTable[j], length, out);
+ length = origLocaTable[j].length;
+ if (length > 0 &&
+ glyfPos + origLocaTable[j].pos + length <= len) {
+ dumpString(file + glyfPos + origLocaTable[j].pos, length,
+ outputFunc, outputStream);
}
}
} else {
// already reported during the construction of the table
// headers
if ((length = newTableHdrs[i].length) > 0) {
- dumpString(file + seekTable(t42Tables[i].tag), length, out);
+ j = seekTable(t42Tables[i].tag);
+ if (j >= 0) {
+ dumpString(file + seekTable(t42Tables[i].tag), length,
+ outputFunc, outputStream);
+ }
}
}
}
// end the sfnts array
- fprintf(out, "] def\n");
+ (*outputFunc)(outputStream, "] def\n", 6);
gfree(origLocaTable);
gfree(locaTable);
}
-void TrueTypeFontFile::dumpString(char *s, int length, FILE *out) {
+void TrueTypeFontFile::dumpString(char *s, int length,
+ FontFileOutputFunc outputFunc,
+ void *outputStream) {
+ char buf[64];
int pad, i, j;
- fprintf(out, "<");
+ (*outputFunc)(outputStream, "<", 1);
for (i = 0; i < length; i += 32) {
for (j = 0; j < 32 && i+j < length; ++j) {
- fprintf(out, "%02X", s[i+j] & 0xff);
+ sprintf(buf, "%02X", s[i+j] & 0xff);
+ (*outputFunc)(outputStream, buf, strlen(buf));
}
if (i % (65536 - 32) == 65536 - 64) {
- fprintf(out, ">\n<");
+ (*outputFunc)(outputStream, ">\n<", 3);
} else if (i+32 < length) {
- fprintf(out, "\n");
+ (*outputFunc)(outputStream, "\n", 1);
}
}
if (length & 3) {
pad = 4 - (length & 3);
for (i = 0; i < pad; ++i) {
- fprintf(out, "00");
+ (*outputFunc)(outputStream, "00", 2);
}
}
// add an extra zero byte because the Adobe Type 42 spec says so
- fprintf(out, "00>\n");
+ (*outputFunc)(outputStream, "00>\n", 4);
}
Guint TrueTypeFontFile::computeTableChecksum(char *data, int length) {
};
GBool haveCmap, haveName, havePost;
GBool dirCmap, dirName, dirPost;
- int nNewTables, nAllTables, pad;
+ GBool unsortedLoca;
+ int nNewTables, nZeroLengthTables, nAllTables;
+ TTFontTableHdr *newTableHdrs;
char *tableDir;
- Guint t, pos;
- int i, j;
+ TrueTypeLoca *origLocaTable;
+ char *locaTable;
+ int length, glyfLength;
+ Guint t, pos, pos2, pos3;
+ int i, j, k;
- // check for missing tables
+ // check for missing/broken tables
haveCmap = seekTable("cmap") >= 0;
haveName = seekTable("name") >= 0;
havePost = seekTable("post") >= 0;
+ unsortedLoca = gFalse;
+ pos = seekTable("loca");
+ pos2 = 0;
+ for (i = 0; i <= nGlyphs; ++i) {
+ if (locaFmt) {
+ pos3 = getULong(pos + 4*i);
+ } else {
+ pos3 = 2 * getUShort(pos + 2*i);
+ }
+ if (pos3 < pos2) {
+ unsortedLoca = gTrue;
+ break;
+ }
+ pos2 = pos3;
+ }
nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1);
- if (!nNewTables) {
- // none are missing - write the TTF file as is
+ 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;
}
+ // 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
+ }
+
// construct the new table directory
- nAllTables = nTables + nNewTables;
- tableDir = (char *)gmalloc(12 + nAllTables * 16);
- memcpy(tableDir, file, 12 + nTables * 16);
- tableDir[4] = (char)((nAllTables >> 8) & 0xff);
- tableDir[5] = (char)(nAllTables & 0xff);
- for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ;
- t = 1 << (4 + i);
- tableDir[6] = (char)((t >> 8) & 0xff);
- tableDir[7] = (char)(t & 0xff);
- tableDir[8] = (char)((i >> 8) & 0xff);
- tableDir[9] = (char)(i & 0xff);
- t = nAllTables * 16 - t;
- tableDir[10] = (char)((t >> 8) & 0xff);
- tableDir[11] = (char)(t & 0xff);
+ nAllTables = nTables - nZeroLengthTables + nNewTables;
+ newTableHdrs = (TTFontTableHdr *)gmalloc(nAllTables *
+ sizeof(TTFontTableHdr));
dirCmap = haveCmap;
dirName = haveName;
dirPost = havePost;
+ pos = 12 + nAllTables * 16;
j = 0;
- pad = (len & 3) ? 4 - (len & 3) : 0;
- pos = len + pad + 16 * nNewTables;
for (i = 0; i < nTables; ++i) {
if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) {
- tableDir[12 + 16*j ] = 'c';
- tableDir[12 + 16*j + 1] = 'm';
- tableDir[12 + 16*j + 2] = 'a';
- tableDir[12 + 16*j + 3] = 'p';
- tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
- tableDir[12 + 16*j + 5] = (char)0;
- tableDir[12 + 16*j + 6] = (char)0;
- tableDir[12 + 16*j + 7] = (char)0;
- tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
- tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
- tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
- tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
- tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
- tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
- tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff);
- tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff);
- pos += sizeof(cmapTab);
+ 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) {
- tableDir[12 + 16*j ] = 'n';
- tableDir[12 + 16*j + 1] = 'a';
- tableDir[12 + 16*j + 2] = 'm';
- tableDir[12 + 16*j + 3] = 'e';
- tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
- tableDir[12 + 16*j + 5] = (char)0;
- tableDir[12 + 16*j + 6] = (char)0;
- tableDir[12 + 16*j + 7] = (char)0;
- tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
- tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
- tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
- tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
- tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
- tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
- tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff);
- tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff);
- pos += sizeof(nameTab);
+ 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 (!dirName && strncmp(tableHdrs[i].tag, "post", 4) > 0) {
- tableDir[12 + 16*j ] = 'p';
- tableDir[12 + 16*j + 1] = 'o';
- tableDir[12 + 16*j + 2] = 's';
- tableDir[12 + 16*j + 3] = 't';
- tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
- tableDir[12 + 16*j + 5] = (char)0;
- tableDir[12 + 16*j + 6] = (char)0;
- tableDir[12 + 16*j + 7] = (char)0;
- tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
- tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
- tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
- tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
- tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
- tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
- tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff);
- tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff);
- pos += sizeof(postTab);
+ 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;
}
- memcpy(&tableDir[12 + 16*j], file + 12 + 16*i, 16);
- t = tableHdrs[i].offset + nNewTables * 16;
- tableDir[12 + 16*j + 8] = (char)((t >> 24) & 0xff);
- tableDir[12 + 16*j + 9] = (char)((t >> 16) & 0xff);
- tableDir[12 + 16*j + 10] = (char)((t >> 8) & 0xff);
- tableDir[12 + 16*j + 11] = (char)( t & 0xff);
- ++j;
+ // 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) {
- tableDir[12 + 16*j ] = 'c';
- tableDir[12 + 16*j + 1] = 'm';
- tableDir[12 + 16*j + 2] = 'a';
- tableDir[12 + 16*j + 3] = 'p';
- tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
- tableDir[12 + 16*j + 5] = (char)0;
- tableDir[12 + 16*j + 6] = (char)0;
- tableDir[12 + 16*j + 7] = (char)0;
- tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
- tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
- tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
- tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
- tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
- tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
- tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff);
- tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff);
- pos += sizeof(cmapTab);
+ 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) {
- tableDir[12 + 16*j ] = 'n';
- tableDir[12 + 16*j + 1] = 'a';
- tableDir[12 + 16*j + 2] = 'm';
- tableDir[12 + 16*j + 3] = 'e';
- tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
- tableDir[12 + 16*j + 5] = (char)0;
- tableDir[12 + 16*j + 6] = (char)0;
- tableDir[12 + 16*j + 7] = (char)0;
- tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
- tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
- tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
- tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
- tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
- tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
- tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff);
- tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff);
- pos += sizeof(nameTab);
+ 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) {
- tableDir[12 + 16*j ] = 'p';
- tableDir[12 + 16*j + 1] = 'o';
- tableDir[12 + 16*j + 2] = 's';
- tableDir[12 + 16*j + 3] = 't';
- tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
- tableDir[12 + 16*j + 5] = (char)0;
- tableDir[12 + 16*j + 6] = (char)0;
- tableDir[12 + 16*j + 7] = (char)0;
- tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
- tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
- tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
- tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
- tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
- tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
- tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff);
- tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff);
- pos += sizeof(postTab);
+ 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;
+ }
+ 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;
}
// write the table directory
fwrite(tableDir, 1, 12 + 16 * nAllTables, out);
- // write the original tables
- fwrite(file + 12 + 16*nTables, 1, len - (12 + 16*nTables), out);
-
- // write the new tables
- for (i = 0; i < pad; ++i) {
- fputc((char)0, out);
- }
- if (!haveCmap) {
- fwrite(cmapTab, 1, sizeof(cmapTab), out);
- }
- if (!haveName) {
- fwrite(nameTab, 1, sizeof(nameTab), out);
- }
- if (!havePost) {
- fwrite(postTab, 1, sizeof(postTab), out);
+ // 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);
+ }
}