diff options
Diffstat (limited to 'pdf/xpdf/FontFile.cc')
-rw-r--r-- | pdf/xpdf/FontFile.cc | 4113 |
1 files changed, 0 insertions, 4113 deletions
diff --git a/pdf/xpdf/FontFile.cc b/pdf/xpdf/FontFile.cc deleted file mode 100644 index 0c44422..0000000 --- a/pdf/xpdf/FontFile.cc +++ /dev/null @@ -1,4113 +0,0 @@ -//======================================================================== -// -// FontFile.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <locale.h> -#include <math.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdarg.h> -#include <string.h> -#include <ctype.h> -#include "gmem.h" -#include "GHash.h" -#include "Error.h" -#include "GlobalParams.h" -#include "CharCodeToUnicode.h" -#include "FontEncodingTables.h" -#include "FontFile.h" - -#include "CompactFontTables.h" - -//------------------------------------------------------------------------ - -static inline char *nextLine(char *line, char *end) { - while (line < end && *line != '\n' && *line != '\r') - ++line; - while (line < end && (*line == '\n' || *line == '\r')) - ++line; - return line; -} - -static char hexChars[17] = "0123456789ABCDEF"; - -//------------------------------------------------------------------------ -// FontFile -//------------------------------------------------------------------------ - -FontFile::FontFile() { -} - -FontFile::~FontFile() { -} - -//------------------------------------------------------------------------ -// Type1FontFile -//------------------------------------------------------------------------ - -Type1FontFile::Type1FontFile(char *file, int len) { - char *line, *line1, *p, *p2; - GBool haveEncoding; - char buf[256]; - char c; - int n, code, i, j; - - name = NULL; - encoding = (char **)gmalloc(256 * sizeof(char *)); - for (i = 0; i < 256; ++i) { - encoding[i] = NULL; - } - haveEncoding = gFalse; - - for (i = 1, line = file; - i <= 100 && line < file + len && !haveEncoding; - ++i) { - - // get font name - if (!strncmp(line, "/FontName", 9)) { - strncpy(buf, line, 255); - buf[255] = '\0'; - if ((p = strchr(buf+9, '/')) && - (p = strtok(p+1, " \t\n\r"))) { - name = copyString(p); - } - line = nextLine(line, file + len); - - // get encoding - } else if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { - for (j = 0; j < 256; ++j) { - if (standardEncoding[j]) { - encoding[j] = copyString(standardEncoding[j]); - } - } - haveEncoding = gTrue; - } else if (!strncmp(line, "/Encoding 256 array", 19)) { - for (j = 0; j < 300; ++j) { - line1 = nextLine(line, file + len); - if ((n = line1 - line) > 255) { - n = 255; - } - strncpy(buf, line, n); - buf[n] = '\0'; - for (p = buf; *p == ' ' || *p == '\t'; ++p) ; - if (!strncmp(p, "dup", 3)) { - for (p += 3; *p == ' ' || *p == '\t'; ++p) ; - for (p2 = p; *p2 >= '0' && *p2 <= '9'; ++p2) ; - if (*p2) { - c = *p2; - *p2 = '\0'; - if ((code = atoi(p)) < 256) { - *p2 = c; - for (p = p2; *p == ' ' || *p == '\t'; ++p) ; - if (*p == '/') { - ++p; - for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; - *p2 = '\0'; - encoding[code] = copyString(p); - } - } - } - } else { - if (strtok(buf, " \t") && - (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { - break; - } - } - line = line1; - } - //~ check for getinterval/putinterval junk - haveEncoding = gTrue; - - } else { - line = nextLine(line, file + len); - } - } -} - -Type1FontFile::~Type1FontFile() { - int i; - - if (name) { - gfree(name); - } - for (i = 0; i < 256; ++i) { - gfree(encoding[i]); - } - gfree(encoding); -} - -//------------------------------------------------------------------------ -// Type1CFontFile -//------------------------------------------------------------------------ - -struct Type1CTopDict { - int version; - int notice; - int copyright; - int fullName; - int familyName; - int weight; - int isFixedPitch; - double italicAngle; - double underlinePosition; - double underlineThickness; - int paintType; - int charstringType; - double fontMatrix[6]; - int uniqueID; - double fontBBox[4]; - double strokeWidth; - int charset; - int encoding; - int charStrings; - int privateSize; - int privateOffset; - - //----- CIDFont entries - int registry; - int ordering; - int supplement; - int fdArrayOffset; - int fdSelectOffset; -}; - -struct Type1CPrivateDict { - GString *dictData; - int subrsOffset; - double defaultWidthX; - GBool defaultWidthXFP; - double nominalWidthX; - GBool nominalWidthXFP; -}; - -Type1CFontFile::Type1CFontFile(char *fileA, int lenA) { - int nameIdxPos, namePos, nameLen; - - file = (Guchar *)fileA; - len = lenA; - name = NULL; - encoding = NULL; - ok = gFalse; - - // some tools embed Type 1C fonts with an extra whitespace char at - // the beginning - if (len > 0 && file[0] != '\x01') { - ++file; - --len; - } - - // make sure the header exists - if (len < 4) { - return; - } - - // read name index (first font only) - nameIdxPos = file[2] & 0xff; - if ((namePos = getIndexValPos(nameIdxPos, 0, &nameLen)) < 0) { - return; - } - name = new GString((char *)&file[namePos], nameLen); - - topDictIdxPos = getIndexEnd(nameIdxPos); - stringIdxPos = getIndexEnd(topDictIdxPos); - gsubrIdxPos = getIndexEnd(stringIdxPos); - - ok = gTrue; -} - -Type1CFontFile::~Type1CFontFile() { - int i; - - delete name; - if (encoding) { - for (i = 0; i < 256; ++i) { - gfree(encoding[i]); - } - gfree(encoding); - } -} - -char *Type1CFontFile::getName() { - return name->getCString(); -} - -char **Type1CFontFile::getEncoding() { - if (!encoding) { - readEncoding(); - } - return encoding; -} - -void Type1CFontFile::readEncoding() { - char buf[256]; - int idxPos, idxLen, pos; - int nGlyphs; - int nCodes, nRanges, nLeft, nSups; - Gushort *glyphNames; - int charset, enc, charstrings; - int encFormat; - int c, sid; - double x; - GBool isFP; - int key; - int i, j; - - encoding = (char **)gmalloc(256 * sizeof(char *)); - for (i = 0; i < 256; ++i) { - encoding[i] = NULL; - } - - // read top dict (first font only) - if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) { - return; - } - charset = enc = charstrings = 0; - i = 0; - pos = idxPos; - while (pos < idxPos + idxLen) { - if (file[pos] <= 27 || file[pos] == 31) { - key = file[pos++]; - if (key == 0x0c) { - if (pos >= idxPos + idxLen) { - return; - } - key = (key << 8) | file[pos++]; - } - if (key == 0x0f) { // charset - charset = (int)op[0]; - } else if (key == 0x10) { // encoding - enc = (int)op[0]; - } else if (key == 0x11) { // charstrings - charstrings = (int)op[0]; - } - i = 0; - } else { - x = getNum(&pos, &isFP); - if (i < 48) { - op[i++] = x; - } - } - } - - // get number of glyphs from charstrings index - nGlyphs = getIndexLen(charstrings); - - // read charset (GID -> name mapping) - glyphNames = readCharset(charset, nGlyphs); - - // read encoding (GID -> code mapping) - if (enc == 0) { - for (i = 0; i < 256; ++i) { - if (standardEncoding[i]) { - encoding[i] = copyString(standardEncoding[i]); - } - } - } else if (enc == 1) { - for (i = 0; i < 256; ++i) { - if (expertEncoding[i]) { - encoding[i] = copyString(expertEncoding[i]); - } - } - } else { - pos = enc; - if (pos < 0 || pos >= len) { - goto err0; - } - encFormat = file[pos++]; - if ((encFormat & 0x7f) == 0) { - 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 = file[pos++]; - if (encoding[c]) { - gfree(encoding[c]); - } - encoding[c] = copyString(getString(glyphNames[i], buf)); - } - } else if ((encFormat & 0x7f) == 1) { - if (pos >= len) { - goto err0; - } - nRanges = file[pos++]; - if (pos + 2 * nRanges > len) { - goto err0; - } - nCodes = 1; - for (i = 0; i < nRanges; ++i) { - c = file[pos++]; - nLeft = file[pos++]; - for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { - if (c < 256) { - if (encoding[c]) { - gfree(encoding[c]); - } - encoding[c] = copyString(getString(glyphNames[nCodes], buf)); - } - ++nCodes; - ++c; - } - } - } - if (encFormat & 0x80) { - if (pos >= len) { - goto err0; - } - nSups = file[pos++]; - if (pos + nSups * 3 > len) { - goto err0; - } - for (i = 0; i < nSups; ++i) { - c = file[pos++]; - sid = getWord(pos, 2); - pos += 2; - if (encoding[c]) { - gfree(encoding[c]); - } - encoding[c] = copyString(getString(sid, buf)); - } - } - } - - err0: - if (charset < 0 || charset > 2) { - gfree(glyphNames); - } -} - -void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, - void *outputStreamA) { - Type1CTopDict dict; - Type1CPrivateDict privateDict; - char buf[512], eBuf[256]; - int idxPos, idxLen, pos; - int nGlyphs, nCodes, nRanges, nLeft, nSups; - Gushort *glyphNames; - int encFormat, nCharStrings; - int c, sid; - int i, j; - - outputFunc = outputFuncA; - outputStream = outputStreamA; - - // read top dict (first font only) - readTopDict(&dict); - - // write header and font dictionary, up to encoding - (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); - (*outputFunc)(outputStream, name->getCString(), name->getLength()); - if (dict.version != 0) { - getString(dict.version, buf); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*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) { - (*outputFunc)(outputStream, "/version (", 10); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.notice != 0) { - getString(dict.notice, buf); - (*outputFunc)(outputStream, "/Notice (", 9); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.copyright != 0) { - getString(dict.copyright, buf); - (*outputFunc)(outputStream, "/Copyright (", 12); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.fullName != 0) { - getString(dict.fullName, buf); - (*outputFunc)(outputStream, "/FullName (", 11); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.familyName != 0) { - getString(dict.familyName, buf); - (*outputFunc)(outputStream, "/FamilyName (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.weight != 0) { - 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]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/FontBBox [%g %g %g %g] readonly def\n", - dict.fontBBox[0], dict.fontBBox[1], - dict.fontBBox[2], dict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (dict.uniqueID != 0) { - sprintf(buf, "/UniqueID %d def\n", dict.uniqueID); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - - // get number of glyphs from charstrings index - nGlyphs = getIndexLen(dict.charStrings); - - // read charset - glyphNames = readCharset(dict.charset, nGlyphs); - - // read encoding (glyph -> code mapping), write Type 1 encoding - (*outputFunc)(outputStream, "/Encoding ", 10); - if (dict.encoding == 0) { - (*outputFunc)(outputStream, "StandardEncoding def\n", 21); - } else { - (*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]) { - sprintf(buf, "dup %d /%s put\n", i, expertEncoding[i]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - } else { - pos = dict.encoding; - if (pos < 0 || pos >= len) { - goto err0; - } - encFormat = file[pos++]; - if ((encFormat & 0x7f) == 0) { - 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 = 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) { - if (pos >= len) { - goto err0; - } - nRanges = file[pos++]; - if (pos + 2 * nRanges > len) { - goto err0; - } - nCodes = 1; - for (i = 0; i < nRanges; ++i) { - c = file[pos++]; - nLeft = file[pos++]; - for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { - 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) { - if (pos >= len) { - goto err0; - } - nSups = file[pos++]; - if (pos + nSups * 3 > len) { - goto err0; - } - for (i = 0; i < nSups; ++i) { - 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:; - } - (*outputFunc)(outputStream, "readonly def\n", 13); - } - (*outputFunc)(outputStream, "currentdict end\n", 16); - - // start the binary section - (*outputFunc)(outputStream, "currentfile eexec\n", 18); - r1 = 55665; - line = 0; - - // get private dictionary - eexecWrite("\x83\xca\x73\xd5"); - eexecWrite("dup /Private 32 dict dup begin\n"); - eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n"); - eexecWrite("/ND {noaccess def} executeonly def\n"); - eexecWrite("/NP {noaccess put} executeonly def\n"); - eexecWrite("/MinFeature {16 16} def\n"); - eexecWrite("/password 5839 def\n"); - readPrivateDict(&privateDict, dict.privateOffset, dict.privateSize); - eexecWrite(privateDict.dictData->getCString()); - defaultWidthX = privateDict.defaultWidthX; - defaultWidthXFP = privateDict.defaultWidthXFP; - nominalWidthX = privateDict.nominalWidthX; - nominalWidthXFP = privateDict.nominalWidthXFP; - - // 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 - nCharStrings = getIndexLen(dict.charStrings); - sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings); - eexecWrite(eBuf); - for (i = 0; i < nCharStrings; ++i) { - if ((idxPos = getIndexValPos(dict.charStrings, i, &idxLen)) >= 0) { - eexecCvtGlyph(getString(glyphNames[i], buf), idxPos, idxLen); - } - } - eexecWrite("end\n"); - eexecWrite("end\n"); - eexecWrite("readonly put\n"); - eexecWrite("noaccess put\n"); - eexecWrite("dup /FontName get exch definefont pop\n"); - eexecWrite("mark currentfile closefile\n"); - - // trailer - if (line > 0) { - (*outputFunc)(outputStream, "\n", 1); - } - for (i = 0; i < 8; ++i) { - (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); - } - (*outputFunc)(outputStream, "cleartomark\n", 12); - - // clean up - delete privateDict.dictData; - if (dict.charset > 2) { - gfree(glyphNames); - } -} - -void Type1CFontFile::convertToCIDType0(char *psName, - FontFileOutputFunc outputFuncA, - void *outputStreamA) { - Type1CTopDict dict; - Type1CPrivateDict *privateDicts; - GString *charStrings; - int *charStringOffsets; - Gushort *charset; - int *cidMap; - Guchar *fdSelect; - int idxPos, idxLen, pos; - char buf[512], buf2[16]; - int nGlyphs, nCIDs, gdBytes, nFDs; - int fdSelectFmt, nRanges, gid0, gid1, fd, offset; - int key; - double x; - GBool isFP; - int i, j, k, n; - - outputFunc = outputFuncA; - outputStream = outputStreamA; - - (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37); - - // read top dict (first font only) - readTopDict(&dict); - - // read the FDArray dictionaries and Private dictionaries - if (dict.fdArrayOffset == 0) { - nFDs = 1; - privateDicts = (Type1CPrivateDict *) - gmalloc(nFDs * sizeof(Type1CPrivateDict)); - privateDicts[0].dictData = new GString(); - privateDicts[0].subrsOffset = 0; - privateDicts[0].defaultWidthX = 0; - privateDicts[0].defaultWidthXFP = gFalse; - privateDicts[0].nominalWidthX = 0; - privateDicts[0].nominalWidthXFP = gFalse; - } else { - if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) { - goto err0; - } - privateDicts = (Type1CPrivateDict *) - gmalloc(nFDs * sizeof(Type1CPrivateDict)); - for (i = 0; i < nFDs; ++i) { - privateDicts[i].dictData = NULL; - } - for (i = 0; i < nFDs; ++i) { - privateDicts[i].dictData = NULL; - if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) { - goto err1; - } - pos = idxPos; - j = 0; - while (pos < idxPos + idxLen) { - if (file[pos] <= 27 || file[pos] == 31) { - key = file[pos++]; - if (key == 0x0c) { - if (pos >= idxPos + idxLen) { - goto err1; - } - key = (key << 8) | file[pos++]; - } - if (key == 0x0012) { - readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]); - } - j = 0; - } else { - x = getNum(&pos, &isFP); - if (j < 48) { - op[j] = x; - fp[j++] = isFP; - } - } - } - if (!privateDicts[i].dictData) { - privateDicts[i].dictData = new GString(); - privateDicts[i].subrsOffset = 0; - privateDicts[i].defaultWidthX = 0; - privateDicts[i].defaultWidthXFP = gFalse; - privateDicts[i].nominalWidthX = 0; - privateDicts[i].nominalWidthXFP = gFalse; - } - } - } - - // get the glyph count - if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) { - goto err1; - } - - // read the FDSelect table - fdSelect = (Guchar *)gmalloc(nGlyphs); - if (dict.fdSelectOffset == 0) { - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } else { - pos = dict.fdSelectOffset; - if (pos < 0 || pos >= len) { - goto err2; - } - fdSelectFmt = file[pos++]; - if (fdSelectFmt == 0) { - if (pos + nGlyphs > len) { - goto err2; - } - memcpy(fdSelect, file + pos, nGlyphs); - } else if (fdSelectFmt == 3) { - if (pos + 4 > len) { - goto err2; - } - nRanges = getWord(pos, 2); - pos += 2; - gid0 = getWord(pos, 2); - pos += 2; - if (pos + nRanges * 3 > len) { - goto err2; - } - for (i = 1; i <= nRanges; ++i) { - fd = file[pos++]; - gid1 = getWord(pos, 2); - pos += 2; - for (j = gid0; j < gid1; ++j) { - fdSelect[j] = fd; - } - gid0 = gid1; - } - } else { - error(-1, "Unknown FDSelect table format in CID font"); - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } - } - - // read the charset, compute the CID-to-GID mapping - charset = readCharset(dict.charset, nGlyphs); - nCIDs = 0; - for (i = 0; i < nGlyphs; ++i) { - if (charset[i] >= nCIDs) { - nCIDs = charset[i] + 1; - } - } - cidMap = (int *)gmalloc(nCIDs * sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - cidMap[i] = -1; - } - for (i = 0; i < nGlyphs; ++i) { - cidMap[charset[i]] = i; - } - - // set up global subroutines - i = getIndexLen(gsubrIdxPos); - gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768; - - // build the charstrings - charStrings = new GString(); - charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - charStringOffsets[i] = charStrings->getLength(); - if (cidMap[i] >= 0) { - if ((idxPos = getIndexValPos(dict.charStrings, - cidMap[i], &idxLen)) >= 0) { - j = fdSelect[cidMap[i]]; - defaultWidthX = privateDicts[j].defaultWidthX; - defaultWidthXFP = privateDicts[j].defaultWidthXFP; - nominalWidthX = privateDicts[j].nominalWidthX; - nominalWidthXFP = privateDicts[j].nominalWidthXFP; - subrIdxPos = privateDicts[j].subrsOffset; - k = getIndexLen(subrIdxPos); - subrBias = (k < 1240) ? 107 : (k < 33900) ? 1131 : 32768; - cvtGlyph(idxPos, idxLen, gTrue); - charStrings->append(charBuf); - delete charBuf; - } - } - } - charStringOffsets[nCIDs] = charStrings->getLength(); - - // compute gdBytes = number of bytes needed for charstring offsets - // (offset size needs to account for the charstring offset table, - // with a worst case of five bytes per entry, plus the charstrings - // themselves) - i = (nCIDs + 1) * 5 + charStrings->getLength(); - if (i < 0x100) { - gdBytes = 1; - } else if (i < 0x10000) { - gdBytes = 2; - } else if (i < 0x1000000) { - gdBytes = 3; - } else { - gdBytes = 4; - } - - // begin the font dictionary - (*outputFunc)(outputStream, "20 dict begin\n", 14); - (*outputFunc)(outputStream, "/CIDFontName /", 14); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19); - (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); - if (dict.registry > 0 && dict.ordering > 0) { - getString(dict.registry, buf); - (*outputFunc)(outputStream, " /Registry (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") def\n", 6); - getString(dict.ordering, buf); - (*outputFunc)(outputStream, " /Ordering (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") def\n", 6); - } else { - (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); - (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); - } - sprintf(buf, " /Supplement %d def\n", dict.supplement); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "end def\n", 8); - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2], - dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/FontBBox [%g %g %g %g] def\n", - dict.fontBBox[0], dict.fontBBox[1], - dict.fontBBox[2], dict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27); - (*outputFunc)(outputStream, " /FSType 8 def\n", 16); - (*outputFunc)(outputStream, "end def\n", 8); - - // CIDFont-specific entries - sprintf(buf, "/CIDCount %d def\n", nCIDs); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); - sprintf(buf, "/GDBytes %d def\n", gdBytes); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20); - if (dict.paintType != 0) { - sprintf(buf, "/PaintType %d def\n", dict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - - // FDArray entry - sprintf(buf, "/FDArray %d array\n", nFDs); - (*outputFunc)(outputStream, buf, strlen(buf)); - for (i = 0; i < nFDs; ++i) { - sprintf(buf, "dup %d 10 dict begin\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/PaintType %d def\n", dict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); - (*outputFunc)(outputStream, privateDicts[i].dictData->getCString(), - privateDicts[i].dictData->getLength()); - (*outputFunc)(outputStream, "currentdict end def\n", 20); - (*outputFunc)(outputStream, "currentdict end put\n", 20); - } - (*outputFunc)(outputStream, "def\n", 4); - - // start the binary section - offset = (nCIDs + 1) * (1 + gdBytes); - sprintf(buf, "(Hex) %d StartData\n", - offset + charStrings->getLength()); - (*outputFunc)(outputStream, buf, strlen(buf)); - - // write the charstring offset (CIDMap) table - for (i = 0; i <= nCIDs; i += 6) { - for (j = 0; j < 6 && i+j <= nCIDs; ++j) { - if (i+j < nCIDs && cidMap[i+j] >= 0) { - buf[0] = (char)fdSelect[cidMap[i+j]]; - } else { - buf[0] = (char)0; - } - n = offset + charStringOffsets[i+j]; - for (k = gdBytes; k >= 1; --k) { - buf[k] = (char)(n & 0xff); - n >>= 8; - } - for (k = 0; k <= gdBytes; ++k) { - sprintf(buf2, "%02x", buf[k] & 0xff); - (*outputFunc)(outputStream, buf2, 2); - } - } - (*outputFunc)(outputStream, "\n", 1); - } - - // write the charstring data - n = charStrings->getLength(); - for (i = 0; i < n; i += 32) { - for (j = 0; j < 32 && i+j < n; ++j) { - sprintf(buf, "%02x", charStrings->getChar(i+j) & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (i + 32 >= n) { - (*outputFunc)(outputStream, ">", 1); - } - (*outputFunc)(outputStream, "\n", 1); - } - - gfree(charStringOffsets); - delete charStrings; - gfree(cidMap); - gfree(charset); - err2: - gfree(fdSelect); - err1: - for (i = 0; i < nFDs; ++i) { - if (privateDicts[i].dictData) { - delete privateDicts[i].dictData; - } - } - gfree(privateDicts); - err0:; -} - -void Type1CFontFile::convertToType0(char *psName, - FontFileOutputFunc outputFuncA, - void *outputStreamA) { - Type1CTopDict dict; - Type1CPrivateDict *privateDicts; - Gushort *charset; - int *cidMap; - Guchar *fdSelect; - int idxPos, idxLen, pos; - char buf[512]; - char eBuf[256]; - int nGlyphs, nCIDs, nFDs; - int fdSelectFmt, nRanges, gid0, gid1, fd; - int key; - double x; - GBool isFP; - int i, j; - - outputFunc = outputFuncA; - outputStream = outputStreamA; - - // read top dict (first font only) - readTopDict(&dict); - - // read the FDArray dictionaries and Private dictionaries - if (dict.fdArrayOffset == 0) { - nFDs = 1; - privateDicts = (Type1CPrivateDict *) - gmalloc(nFDs * sizeof(Type1CPrivateDict)); - privateDicts[0].dictData = new GString(); - privateDicts[0].subrsOffset = 0; - privateDicts[0].defaultWidthX = 0; - privateDicts[0].defaultWidthXFP = gFalse; - privateDicts[0].nominalWidthX = 0; - privateDicts[0].nominalWidthXFP = gFalse; - } else { - if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) { - goto err0; - } - privateDicts = (Type1CPrivateDict *) - gmalloc(nFDs * sizeof(Type1CPrivateDict)); - for (i = 0; i < nFDs; ++i) { - privateDicts[i].dictData = NULL; - } - for (i = 0; i < nFDs; ++i) { - privateDicts[i].dictData = NULL; - if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) { - goto err1; - } - pos = idxPos; - j = 0; - while (pos < idxPos + idxLen) { - if (file[pos] <= 27 || file[pos] == 31) { - key = file[pos++]; - if (key == 0x0c) { - if (pos >= idxPos + idxLen) { - goto err1; - } - key = (key << 8) | file[pos++]; - } - if (key == 0x0012) { - readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]); - } - j = 0; - } else { - x = getNum(&pos, &isFP); - if (j < 48) { - op[j] = x; - fp[j++] = isFP; - } - } - } - if (!privateDicts[i].dictData) { - privateDicts[i].dictData = new GString(); - privateDicts[i].subrsOffset = 0; - privateDicts[i].defaultWidthX = 0; - privateDicts[i].defaultWidthXFP = gFalse; - privateDicts[i].nominalWidthX = 0; - privateDicts[i].nominalWidthXFP = gFalse; - } - } - } - - // get the glyph count - if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) { - goto err1; - } - - // read the FDSelect table - fdSelect = (Guchar *)gmalloc(nGlyphs); - if (dict.fdSelectOffset == 0) { - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } else { - pos = dict.fdSelectOffset; - if (pos < 0 || pos >= len) { - goto err2; - } - fdSelectFmt = file[pos++]; - if (fdSelectFmt == 0) { - if (pos + nGlyphs > len) { - goto err2; - } - memcpy(fdSelect, file + pos, nGlyphs); - } else if (fdSelectFmt == 3) { - if (pos + 4 > len) { - goto err2; - } - nRanges = getWord(pos, 2); - pos += 2; - gid0 = getWord(pos, 2); - pos += 2; - if (pos + nRanges * 3 > len) { - goto err2; - } - for (i = 1; i <= nRanges; ++i) { - fd = file[pos++]; - gid1 = getWord(pos, 2); - pos += 2; - for (j = gid0; j < gid1; ++j) { - fdSelect[j] = fd; - } - gid0 = gid1; - } - } else { - error(-1, "Unknown FDSelect table format in CID font"); - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } - } - - // read the charset, compute the CID-to-GID mapping - charset = readCharset(dict.charset, nGlyphs); - nCIDs = 0; - for (i = 0; i < nGlyphs; ++i) { - if (charset[i] >= nCIDs) { - nCIDs = charset[i] + 1; - } - } - cidMap = (int *)gmalloc(nCIDs * sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - cidMap[i] = -1; - } - for (i = 0; i < nGlyphs; ++i) { - cidMap[charset[i]] = i; - } - - // set up global subroutines - i = getIndexLen(gsubrIdxPos); - gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768; - - // write the descendant Type 1 fonts - for (i = 0; i < nCIDs; i += 256) { - - //~ this assumes that all CIDs in this block have the same FD -- - //~ to handle multiple FDs correctly, need to somehow divide the - //~ font up by FD - fd = 0; - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - if (cidMap[i+j] >= 0) { - fd = fdSelect[cidMap[i+j]]; - break; - } - } - - // font dictionary (unencrypted section) - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - sprintf(buf, "_%02x def\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2], - dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/FontBBox [%g %g %g %g] def\n", - dict.fontBBox[0], dict.fontBBox[1], - dict.fontBBox[2], dict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/PaintType %d def\n", dict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (dict.paintType != 0) { - sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - sprintf(buf, "dup %d /c%02x put\n", j, j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (j < 256) { - sprintf(buf, "%d 1 255 { 1 index exch /.notdef put } for\n", j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "readonly def\n", 13); - (*outputFunc)(outputStream, "currentdict end\n", 16); - - // start the binary section - (*outputFunc)(outputStream, "currentfile eexec\n", 18); - r1 = 55665; - line = 0; - - // start the private dictionary - eexecWrite("\x83\xca\x73\xd5"); - eexecWrite("dup /Private 32 dict dup begin\n"); - eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n"); - eexecWrite("/ND {noaccess def} executeonly def\n"); - eexecWrite("/NP {noaccess put} executeonly def\n"); - eexecWrite("/MinFeature {16 16} 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 - if ((idxPos = getIndexValPos(dict.charStrings, 0, &idxLen)) >= 0) { - eexecCvtGlyph(".notdef", idxPos, idxLen); - } - - // write the CharStrings - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - if (cidMap[i+j] >= 0) { - if ((idxPos = getIndexValPos(dict.charStrings, - cidMap[i+j], &idxLen)) >= 0) { - sprintf(buf, "c%02x", j); - eexecCvtGlyph(buf, idxPos, idxLen); - } - } - } - eexecWrite("end\n"); - eexecWrite("end\n"); - eexecWrite("readonly put\n"); - eexecWrite("noaccess put\n"); - eexecWrite("dup /FontName get exch definefont pop\n"); - eexecWrite("mark currentfile closefile\n"); - - // trailer - if (line > 0) { - (*outputFunc)(outputStream, "\n", 1); - } - for (j = 0; j < 8; ++j) { - (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); - } - (*outputFunc)(outputStream, "cleartomark\n", 12); - } - - // write the Type 0 parent font - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 0 def\n", 16); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); - (*outputFunc)(outputStream, "/Encoding [\n", 12); - for (i = 0; i < nCIDs; i += 256) { - sprintf(buf, "%d\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "/FDepVector [\n", 14); - for (i = 0; i < nCIDs; i += 256) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, psName, strlen(psName)); - sprintf(buf, "_%02x findfont\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); - - // clean up - gfree(cidMap); - gfree(charset); - err2: - gfree(fdSelect); - err1: - for (i = 0; i < nFDs; ++i) { - if (privateDicts[i].dictData) { - delete privateDicts[i].dictData; - } - } - gfree(privateDicts); - err0:; -} - -void Type1CFontFile::readTopDict(Type1CTopDict *dict) { - int idxPos, idxLen, pos; - double x; - GBool isFP; - int key; - int i; - - dict->version = 0; - dict->notice = 0; - dict->copyright = 0; - dict->fullName = 0; - dict->familyName = 0; - dict->weight = 0; - dict->isFixedPitch = 0; - dict->italicAngle = 0; - dict->underlinePosition = -100; - dict->underlineThickness = 50; - dict->paintType = 0; - dict->charstringType = 2; - dict->fontMatrix[0] = 0.001; - dict->fontMatrix[1] = 0; - dict->fontMatrix[2] = 0; - dict->fontMatrix[3] = 0.001; - dict->fontMatrix[4] = 0; - dict->fontMatrix[5] = 0; - dict->uniqueID = 0; - dict->fontBBox[0] = 0; - dict->fontBBox[1] = 0; - dict->fontBBox[2] = 0; - dict->fontBBox[3] = 0; - dict->strokeWidth = 0; - dict->charset = 0; - dict->encoding = 0; - dict->charStrings = 0; - dict->privateSize = 0; - dict->privateOffset = 0; - dict->registry = 0; - dict->ordering = 0; - dict->supplement = 0; - dict->fdArrayOffset = 0; - dict->fdSelectOffset = 0; - if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) { - return; - } - i = 0; - pos = idxPos; - while (pos < idxPos + idxLen) { - if (file[pos] <= 27 || file[pos] == 31) { - key = file[pos++]; - if (key == 0x0c) { - if (pos >= idxPos + idxLen) { - break; - } - key = (key << 8) | file[pos++]; - } - switch (key) { - case 0x0000: dict->version = (int)op[0]; break; - case 0x0001: dict->notice = (int)op[0]; break; - case 0x0c00: dict->copyright = (int)op[0]; break; - case 0x0002: dict->fullName = (int)op[0]; break; - case 0x0003: dict->familyName = (int)op[0]; break; - case 0x0004: dict->weight = (int)op[0]; break; - case 0x0c01: dict->isFixedPitch = (int)op[0]; break; - case 0x0c02: dict->italicAngle = op[0]; break; - case 0x0c03: dict->underlinePosition = op[0]; break; - case 0x0c04: dict->underlineThickness = op[0]; break; - case 0x0c05: dict->paintType = (int)op[0]; break; - case 0x0c06: dict->charstringType = (int)op[0]; break; - case 0x0c07: dict->fontMatrix[0] = op[0]; - dict->fontMatrix[1] = op[1]; - dict->fontMatrix[2] = op[2]; - dict->fontMatrix[3] = op[3]; - dict->fontMatrix[4] = op[4]; - dict->fontMatrix[5] = op[5]; break; - case 0x000d: dict->uniqueID = (int)op[0]; break; - case 0x0005: dict->fontBBox[0] = op[0]; - dict->fontBBox[1] = op[1]; - dict->fontBBox[2] = op[2]; - dict->fontBBox[3] = op[3]; break; - case 0x0c08: dict->strokeWidth = op[0]; break; - case 0x000f: dict->charset = (int)op[0]; break; - case 0x0010: dict->encoding = (int)op[0]; break; - case 0x0011: dict->charStrings = (int)op[0]; break; - case 0x0012: dict->privateSize = (int)op[0]; - dict->privateOffset = (int)op[1]; break; - case 0x0c1e: dict->registry = (int)op[0]; - dict->ordering = (int)op[1]; - dict->supplement = (int)op[2]; break; - case 0x0c24: dict->fdArrayOffset = (int)op[0]; break; - case 0x0c25: dict->fdSelectOffset = (int)op[0]; break; - } - i = 0; - } else { - x = getNum(&pos, &isFP); - if (i < 48) { - op[i] = x; - fp[i++] = isFP; - } - } - } -} - -void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict, - int offset, int size) { - int pos; - char eBuf[256]; - int key; - double x; - GBool isFP; - int i; - - privateDict->dictData = new GString(); - privateDict->subrsOffset = 0; - privateDict->defaultWidthX = 0; - privateDict->defaultWidthXFP = gFalse; - privateDict->nominalWidthX = 0; - privateDict->nominalWidthXFP = gFalse; - if (offset < 0 || offset + size > len) { - return; - } - pos = offset; - i = 0; - while (pos < offset + size) { - if (file[pos] <= 27 || file[pos] == 31) { - key = file[pos++]; - if (key == 0x0c) { - if (pos >= offset + size) { - break; - } - key = (key << 8) | file[pos++]; - } - switch (key) { - case 0x0006: - getDeltaInt(eBuf, "BlueValues", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0007: - getDeltaInt(eBuf, "OtherBlues", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0008: - getDeltaInt(eBuf, "FamilyBlues", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0009: - getDeltaInt(eBuf, "FamilyOtherBlues", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0c09: - sprintf(eBuf, "/BlueScale %g def\n", op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c0a: - sprintf(eBuf, "/BlueShift %d def\n", (int)op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c0b: - sprintf(eBuf, "/BlueFuzz %d def\n", (int)op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x000a: - sprintf(eBuf, "/StdHW [%g] def\n", op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x000b: - sprintf(eBuf, "/StdVW [%g] def\n", op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c0c: - getDeltaReal(eBuf, "StemSnapH", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0c0d: - getDeltaReal(eBuf, "StemSnapV", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0c0e: - sprintf(eBuf, "/ForceBold %s def\n", op[0] ? "true" : "false"); - privateDict->dictData->append(eBuf); - break; - case 0x0c0f: - sprintf(eBuf, "/ForceBoldThreshold %g def\n", op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c11: - sprintf(eBuf, "/LanguageGroup %d def\n", (int)op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c12: - sprintf(eBuf, "/ExpansionFactor %g def\n", op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c13: - error(-1, "Got Type 1C InitialRandomSeed"); - break; - case 0x0013: - privateDict->subrsOffset = offset + (int)op[0]; - break; - case 0x0014: - privateDict->defaultWidthX = op[0]; - privateDict->defaultWidthXFP = fp[0]; - break; - case 0x0015: - privateDict->nominalWidthX = op[0]; - privateDict->nominalWidthXFP = fp[0]; - break; - default: - error(-1, "Unknown Type 1C private dict entry %04x", key); - break; - } - i = 0; - } else { - x = getNum(&pos, &isFP); - if (i < 48) { - op[i] = x; - fp[i++] = isFP; - } - } - } -} - -Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) { - Gushort *glyphNames; - int pos; - int charsetFormat, c; - int nLeft, i, j; - - if (charset == 0) { - glyphNames = type1CISOAdobeCharset; - } else if (charset == 1) { - glyphNames = type1CExpertCharset; - } else if (charset == 2) { - glyphNames = type1CExpertSubsetCharset; - } else { - glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort)); - for (i = 0; i < nGlyphs; ++i) { - glyphNames[i] = 0; - } - pos = charset; - if (pos < 0 || pos >= len) { - goto err0; - } - charsetFormat = file[pos++]; - if (charsetFormat == 0) { - if (pos + (nGlyphs - 1) * 2 >= len) { - goto err0; - } - for (i = 1; i < nGlyphs; ++i) { - glyphNames[i] = getWord(pos, 2); - pos += 2; - } - } else if (charsetFormat == 1) { - i = 1; - while (i < nGlyphs) { - if (pos + 3 > len) { - goto err0; - } - 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) { - 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; -} - -void Type1CFontFile::eexecWrite(char *s) { - Guchar *p; - Guchar x; - - for (p = (Guchar *)s; *p; ++p) { - x = *p ^ (r1 >> 8); - r1 = (x + r1) * 52845 + 22719; - (*outputFunc)(outputStream, &hexChars[x >> 4], 1); - (*outputFunc)(outputStream, &hexChars[x & 0x0f], 1); - line += 2; - if (line == 64) { - (*outputFunc)(outputStream, "\n", 1); - line = 0; - } - } -} - -void Type1CFontFile::eexecCvtGlyph(char *glyphName, int pos, int n) { - char eBuf[256]; - - cvtGlyph(pos, n, gTrue); - sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength()); - eexecWrite(eBuf); - eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength()); - eexecWrite(" ND\n"); - delete charBuf; -} - -void Type1CFontFile::cvtGlyph(int pos, int n, GBool top) { - int x; - int subrPos, subrLen; - double d, dx, dy; - GBool dFP; - Gushort r2; - Guchar byte; - int i, k; - - if (pos < 0 || pos + n > len) { - return; - } - - if (top) { - charBuf = new GString(); - charBuf->append((char)73); - charBuf->append((char)58); - charBuf->append((char)147); - charBuf->append((char)134); - nOps = 0; - nHints = 0; - firstOp = gTrue; - } - - i = pos; - while (i < pos + n) { - if (file[i] == 12) { - if (i + 2 > pos + n) { - break; - } - switch (file[i+1]) { - case 0: // dotsection (should be Type 1 only?) - // ignored - break; - case 34: // hflex - if (nOps != 7) { - error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[5], fp[5]); - eexecDumpNum(-op[2], fp[2]); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - break; - case 35: // flex - if (nOps != 13) { - error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(op[5], fp[5]); - eexecDumpOp1(8); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(op[7], fp[7]); - eexecDumpNum(op[8], fp[8]); - eexecDumpNum(op[9], fp[9]); - eexecDumpNum(op[10], fp[10]); - eexecDumpNum(op[11], fp[11]); - eexecDumpOp1(8); - break; - case 36: // hflex1 - if (nOps != 9) { - error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - eexecDumpNum(op[5], fp[5]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(op[7], fp[7]); - eexecDumpNum(op[8], fp[8]); - eexecDumpNum(-(op[1] + op[3] + op[7]), fp[1] | fp[3] | fp[7]); - eexecDumpOp1(8); - break; - case 37: // flex1 - if (nOps != 11) { - error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(op[5], fp[5]); - eexecDumpOp1(8); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(op[7], fp[7]); - eexecDumpNum(op[8], fp[8]); - eexecDumpNum(op[9], fp[9]); - dx = op[0] + op[2] + op[4] + op[6] + op[8]; - dy = op[1] + op[3] + op[5] + op[7] + op[9]; - if (fabs(dx) > fabs(dy)) { - eexecDumpNum(op[10], fp[10]); - eexecDumpNum(-dy, fp[1] | fp[3] | fp[5] | fp[7] | fp[9]); - } else { - eexecDumpNum(-dx, fp[0] | fp[2] | fp[4] | fp[6] | fp[8]); - eexecDumpNum(op[10], fp[10]); - } - eexecDumpOp1(8); - break; - case 3: // and - case 4: // or - case 5: // not - case 8: // store - case 9: // abs - case 10: // add - case 11: // sub - case 12: // div - case 13: // load - case 14: // neg - case 15: // eq - case 18: // drop - case 20: // put - case 21: // get - case 22: // ifelse - case 23: // random - case 24: // mul - case 26: // sqrt - case 27: // dup - case 28: // exch - case 29: // index - case 30: // roll - error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); - break; - default: - error(-1, "Illegal Type 2 charstring op: 12.%d", file[i+1]); - break; - } - i += 2; - nOps = 0; - } else if (file[i] == 19) { // hintmask - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps > 0) { - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", - nOps); - } - nHints += nOps / 2; - } - i += 1 + ((nHints + 7) >> 3); - nOps = 0; - } else if (file[i] == 20) { // cntrmask - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps > 0) { - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", - nOps); - } - nHints += nOps / 2; - } - i += 1 + ((nHints + 7) >> 3); - nOps = 0; - } else if (file[i] == 28) { - if (i + 3 > len) { - break; - } - x = (file[i+1] << 8) + file[i+2]; - if (x & 0x8000) { - x |= -1 << 15; - } - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = x; - } - i += 3; - } else if (file[i] == 10) { // callsubr - if (nOps >= 1) { - k = subrBias + (int)op[nOps - 1]; - --nOps; - if ((subrPos = getIndexValPos(subrIdxPos, k, &subrLen)) >= 0) { - cvtGlyph(subrPos, subrLen, gFalse); - } - } else { - error(-1, "Too few args to Type 2 callsubr"); - } - // don't clear the stack - ++i; - } else if (file[i] == 29) { // callgsubr - if (nOps >= 1) { - k = gsubrBias + (int)op[nOps - 1]; - --nOps; - if ((subrPos = getIndexValPos(gsubrIdxPos, k, &subrLen)) >= 0) { - cvtGlyph(subrPos, subrLen, gFalse); - } - } else { - error(-1, "Too few args to Type 2 callgsubr"); - } - // don't clear the stack - ++i; - } else if (file[i] == 11) { // return - // don't clear the stack - ++i; - } else if (file[i] <= 31) { - switch (file[i]) { - case 4: // vmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 2); - firstOp = gFalse; - } - if (nOps != 1) { - error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpOp1(4); - break; - case 5: // rlineto - if (nOps < 2 || nOps % 2 != 0) { - error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); - } - for (k = 0; k < nOps; k += 2) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpOp1(5); - } - break; - case 6: // hlineto - if (nOps < 1) { - error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); - } - for (k = 0; k < nOps; ++k) { - eexecDumpNum(op[k], fp[k]); - eexecDumpOp1((k & 1) ? 7 : 6); - } - break; - case 7: // vlineto - if (nOps < 1) { - error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); - } - for (k = 0; k < nOps; ++k) { - eexecDumpNum(op[k], fp[k]); - eexecDumpOp1((k & 1) ? 6 : 7); - } - break; - case 8: // rrcurveto - if (nOps < 6 || nOps % 6 != 0) { - error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); - } - for (k = 0; k < nOps; k += 6) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+5], fp[k+5]); - eexecDumpOp1(8); - } - break; - case 14: // endchar / seac - if (firstOp) { - cvtGlyphWidth(nOps == 1 || nOps == 5); - firstOp = gFalse; - } - if (nOps == 4) { - eexecDumpNum(0, 0); - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpOp2(6); - } else if (nOps == 0) { - eexecDumpOp1(14); - } else { - error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); - } - break; - case 21: // rmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 3); - firstOp = gFalse; - } - if (nOps != 2) { - error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpOp1(21); - break; - case 22: // hmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 2); - firstOp = gFalse; - } - if (nOps != 1) { - error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpOp1(22); - break; - case 24: // rcurveline - if (nOps < 8 || (nOps - 2) % 6 != 0) { - error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps); - } - for (k = 0; k < nOps - 2; k += 6) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+5], fp[k+5]); - eexecDumpOp1(8); - } - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k]); - eexecDumpOp1(5); - break; - case 25: // rlinecurve - if (nOps < 8 || (nOps - 6) % 2 != 0) { - error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps); - } - for (k = 0; k < nOps - 6; k += 2) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k]); - eexecDumpOp1(5); - } - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+5], fp[k+5]); - eexecDumpOp1(8); - break; - case 26: // vvcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps); - } - if (nOps % 2 == 1) { - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[4], fp[4]); - eexecDumpOp1(8); - k = 5; - } else { - k = 0; - } - for (; k < nOps; k += 4) { - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(8); - } - break; - case 27: // hhcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps); - } - if (nOps % 2 == 1) { - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - k = 5; - } else { - k = 0; - } - for (; k < nOps; k += 4) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - } - break; - case 30: // vhcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps); - } - for (k = 0; k < nOps && k != nOps-5; k += 4) { - if (k % 8 == 0) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(30); - } else { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(31); - } - } - if (k == nOps-5) { - if (k % 8 == 0) { - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - } else { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+3], fp[k+3]); - } - eexecDumpOp1(8); - } - break; - case 31: // hvcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps); - } - for (k = 0; k < nOps && k != nOps-5; k += 4) { - if (k % 8 == 0) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(31); - } else { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(30); - } - } - if (k == nOps-5) { - if (k % 8 == 0) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+3], fp[k+3]); - } else { - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - } - eexecDumpOp1(8); - } - break; - case 1: // hstem - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); - } - d = 0; - dFP = gFalse; - for (k = 0; k < nOps; k += 2) { - if (op[k+1] < 0) { - d += op[k] + op[k+1]; - dFP |= fp[k] | fp[k+1]; - eexecDumpNum(d, dFP); - eexecDumpNum(-op[k+1], fp[k+1]); - } else { - d += op[k]; - dFP |= fp[k]; - eexecDumpNum(d, dFP); - eexecDumpNum(op[k+1], fp[k+1]); - d += op[k+1]; - dFP |= fp[k+1]; - } - eexecDumpOp1(1); - } - nHints += nOps / 2; - break; - case 3: // vstem - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); - } - d = 0; - dFP = gFalse; - for (k = 0; k < nOps; k += 2) { - if (op[k+1] < 0) { - d += op[k] + op[k+1]; - dFP |= fp[k] | fp[k+1]; - eexecDumpNum(d, dFP); - eexecDumpNum(-op[k+1], fp[k+1]); - } else { - d += op[k]; - dFP |= fp[k]; - eexecDumpNum(d, dFP); - eexecDumpNum(op[k+1], fp[k+1]); - d += op[k+1]; - dFP |= fp[k+1]; - } - eexecDumpOp1(3); - } - 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 (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); - } - nHints += nOps / 2; - break; - case 23: // vstemhm - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); - } - nHints += nOps / 2; - break; - case 16: // blend - error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); - break; - default: - error(-1, "Illegal Type 2 charstring op: %d", file[i]); - break; - } - ++i; - nOps = 0; - } else if (file[i] <= 246) { - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = (int)file[i] - 139; - } - ++i; - } else if (file[i] <= 250) { - if (i + 2 > len) { - break; - } - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = (((int)file[i] - 247) << 8) + (int)file[i+1] + 108; - } - i += 2; - } else if (file[i] <= 254) { - if (i + 2 > len) { - break; - } - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = -(((int)file[i] - 251) << 8) - (int)file[i+1] - 108; - } - i += 2; - } else { - if (i + 5 > len) { - break; - } - x = (file[i+1] << 24) | (file[i+2] << 16) | (file[i+3] << 8) | file[i+4]; - if (x & 0x80000000) { - x |= -1 << 31; - } - if (nOps < 48) { - fp[nOps] = gTrue; - op[nOps++] = (double)x / 65536.0; - } - i += 5; - } - } - - // charstring encryption - if (top) { - r2 = 4330; - for (i = 0; i < charBuf->getLength(); ++i) { - byte = charBuf->getChar(i) ^ (r2 >> 8); - charBuf->setChar(i, byte); - r2 = (byte + r2) * 52845 + 22719; - } - } -} - -void Type1CFontFile::cvtGlyphWidth(GBool useOp) { - double w; - GBool wFP; - int i; - - if (useOp) { - w = nominalWidthX + op[0]; - wFP = nominalWidthXFP | fp[0]; - for (i = 1; i < nOps; ++i) { - op[i-1] = op[i]; - fp[i-1] = fp[i]; - } - --nOps; - } else { - w = defaultWidthX; - wFP = defaultWidthXFP; - } - eexecDumpNum(0, gFalse); - eexecDumpNum(w, wFP); - eexecDumpOp1(13); -} - -void Type1CFontFile::eexecDumpNum(double x, GBool fpA) { - Guchar buf[12]; - int y, n; - - n = 0; - if (fpA) { - if (x >= -32768 && x < 32768) { - y = (int)(x * 256.0); - buf[0] = 255; - buf[1] = (Guchar)(y >> 24); - buf[2] = (Guchar)(y >> 16); - buf[3] = (Guchar)(y >> 8); - buf[4] = (Guchar)y; - buf[5] = 255; - buf[6] = 0; - buf[7] = 0; - buf[8] = 1; - buf[9] = 0; - buf[10] = 12; - buf[11] = 12; - n = 12; - } else { - error(-1, "Type 2 fixed point constant out of range"); - } - } else { - y = (int)x; - if (y >= -107 && y <= 107) { - buf[0] = (Guchar)(y + 139); - n = 1; - } else if (y > 107 && y <= 1131) { - y -= 108; - buf[0] = (Guchar)((y >> 8) + 247); - buf[1] = (Guchar)(y & 0xff); - n = 2; - } else if (y < -107 && y >= -1131) { - y = -y - 108; - buf[0] = (Guchar)((y >> 8) + 251); - buf[1] = (Guchar)(y & 0xff); - n = 2; - } else { - buf[0] = 255; - buf[1] = (Guchar)(y >> 24); - buf[2] = (Guchar)(y >> 16); - buf[3] = (Guchar)(y >> 8); - buf[4] = (Guchar)y; - n = 5; - } - } - charBuf->append((char *)buf, n); -} - -void Type1CFontFile::eexecDumpOp1(int opA) { - charBuf->append((char)opA); -} - -void Type1CFontFile::eexecDumpOp2(int opA) { - charBuf->append((char)12); - charBuf->append((char)opA); -} - -void Type1CFontFile::eexecWriteCharstring(Guchar *s, int n) { - Guchar x; - int i; - - // eexec encryption - for (i = 0; i < n; ++i) { - x = s[i] ^ (r1 >> 8); - r1 = (x + r1) * 52845 + 22719; - (*outputFunc)(outputStream, &hexChars[x >> 4], 1); - (*outputFunc)(outputStream, &hexChars[x & 0x0f], 1); - line += 2; - if (line == 64) { - (*outputFunc)(outputStream, "\n", 1); - line = 0; - } - } -} - -void Type1CFontFile::getDeltaInt(char *buf, char *key, double *opA, - int n) { - int x, i; - - sprintf(buf, "/%s [", key); - buf += strlen(buf); - x = 0; - for (i = 0; i < n; ++i) { - x += (int)opA[i]; - sprintf(buf, "%s%d", i > 0 ? " " : "", x); - buf += strlen(buf); - } - sprintf(buf, "] def\n"); -} - -void Type1CFontFile::getDeltaReal(char *buf, char *key, double *opA, - int n) { - double x; - int i; - - sprintf(buf, "/%s [", key); - buf += strlen(buf); - x = 0; - for (i = 0; i < n; ++i) { - x += opA[i]; - sprintf(buf, "%s%g", i > 0 ? " " : "", x); - buf += strlen(buf); - } - sprintf(buf, "] def\n"); -} - -int Type1CFontFile::getIndexLen(int indexPos) { - if (indexPos + 2 > len) { - return -1; - } - return (int)getWord(indexPos, 2); -} - -int Type1CFontFile::getIndexValPos(int indexPos, int i, int *valLen) { - int n, offSize, idxStartPos; - int pos0, pos1; - - if (indexPos < 0 || indexPos + 3 > len) { - return -1; - } - n = (int)getWord(indexPos, 2); - if (i >= n) { - return -1; - } - offSize = file[indexPos + 2]; - if (offSize < 1 || offSize > 4) { - return -1; - } - idxStartPos = indexPos + 3 + (n + 1) * offSize - 1; - if (idxStartPos >= len) { - return -1; - } - pos0 = idxStartPos + getWord(indexPos + 3 + i * offSize, offSize); - pos1 = idxStartPos + getWord(indexPos + 3 + (i + 1) * offSize, offSize); - if (pos0 < 0 || pos0 >= len || pos1 < pos0 || pos1 > len) { - return -1; - } - *valLen = pos1 - pos0; - return pos0; -} - -int Type1CFontFile::getIndexEnd(int indexPos) { - int n, offSize, idxStartPos; - - if (indexPos < 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(int pos, int size) { - Guint x; - int i; - - if (pos < 0 || pos + size > len) { - return 0; - } - x = 0; - for (i = 0; i < size; ++i) { - x = (x << 8) + file[pos + i]; - } - return x; -} - -double Type1CFontFile::getNum(int *pos, GBool *isFP) { - static char nybChars[16] = "0123456789.ee -"; - int b0, b, nyb0, nyb1; - double x; - char buf[65]; - int i; - - x = 0; - *isFP = gFalse; - if (*pos >= len) { - return 0; - } - b0 = file[*pos]; - if (b0 < 28) { - x = 0; - } else if (b0 == 28) { - if (*pos + 3 <= len) { - x = (file[*pos + 1] << 8) + file[*pos + 2]; - *pos += 3; - } - } else if (b0 == 29) { - if (*pos + 5 <= len) { - x = (file[*pos + 1] << 24) + (file[*pos + 2] << 16) + - (file[*pos + 3] << 8) + file[*pos + 4]; - *pos += 5; - } - } else if (b0 == 30) { - *pos += 1; - i = 0; - do { - if (*pos >= len) { - break; - } - b = file[(*pos)++]; - nyb0 = b >> 4; - nyb1 = b & 0x0f; - if (nyb0 == 0xf) { - break; - } - buf[i++] = nybChars[nyb0]; - if (i == 64) { - break; - } - if (nyb0 == 0xc) { - buf[i++] = '-'; - } - if (i == 64) { - break; - } - if (nyb1 == 0xf) { - break; - } - buf[i++] = nybChars[nyb1]; - if (i == 64) { - break; - } - if (nyb1 == 0xc) { - buf[i++] = '-'; - } - } while (i < 64); - buf[i] = '\0'; - { - char *theLocale = setlocale(LC_NUMERIC, "C"); - x = atof(buf); - setlocale(LC_NUMERIC, theLocale); - } - *isFP = gTrue; - } else if (b0 == 31) { - x = 0; - } else if (b0 < 247) { - x = b0 - 139; - *pos += 1; - } else if (b0 < 251) { - if (*pos + 2 <= len) { - x = ((b0 - 247) << 8) + file[*pos + 1] + 108; - *pos += 2; - } - } else { - if (*pos + 2 <= len) { - x = -((b0 - 251) << 8) - file[*pos + 1] - 108; - *pos += 2; - } - } - return x; -} - -char *Type1CFontFile::getString(int sid, char *buf) { - int idxPos, n; - - if (sid < 391) { - strcpy(buf, type1CStdStrings[sid]); - } else { - sid -= 391; - idxPos = getIndexValPos(stringIdxPos, sid, &n); - if (idxPos < 0 || n < 0 || n > 255 || idxPos + n > len) { - buf[0] = '\0'; - } else { - strncpy(buf, (char *)&file[idxPos], n); - buf[n] = '\0'; - } - } - return buf; -} - -//------------------------------------------------------------------------ -// TrueTypeFontFile -//------------------------------------------------------------------------ - -// -// Terminology -// ----------- -// -// character code = number used as an element of a text string -// -// character name = glyph name = name for a particular glyph within a -// font -// -// glyph index = position (within some internal table in the font) -// where the instructions to draw a particular glyph are -// stored -// -// Type 1 fonts -// ------------ -// -// Type 1 fonts contain: -// -// Encoding: array of glyph names, maps char codes to glyph names -// -// Encoding[charCode] = charName -// -// CharStrings: dictionary of instructions, keyed by character names, -// maps character name to glyph data -// -// CharStrings[charName] = glyphData -// -// TrueType fonts -// -------------- -// -// TrueType fonts contain: -// -// 'cmap' table: mapping from character code to glyph index; there may -// be multiple cmaps in a TrueType font -// -// cmap[charCode] = glyphIdx -// -// 'post' table: mapping from glyph index to glyph name -// -// post[glyphIdx] = glyphName -// -// Type 42 fonts -// ------------- -// -// Type 42 fonts contain: -// -// Encoding: array of glyph names, maps char codes to glyph names -// -// Encoding[charCode] = charName -// -// CharStrings: dictionary of glyph indexes, keyed by character names, -// maps character name to glyph index -// -// CharStrings[charName] = glyphIdx -// - -struct TTFontTableHdr { - char tag[4]; - Guint checksum; - Guint offset; - Guint length; -}; - -struct T42Table { - char *tag; // 4-byte tag - GBool required; // required by the TrueType spec? -}; - -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 -static T42Table t42Tables[nT42Tables] = { - { "cvt ", gTrue }, - { "fpgm", gTrue }, - { "glyf", gTrue }, - { "head", gTrue }, - { "hhea", gTrue }, - { "hmtx", gTrue }, - { "loca", gTrue }, - { "maxp", gTrue }, - { "prep", gTrue }, - { "vhea", gFalse }, - { "vmtx", gFalse } -}; -#define t42HeadTable 3 -#define t42LocaTable 6 -#define t42GlyfTable 2 - -// Glyph names in some arbitrary standard that Apple uses for their -// TrueType fonts. -static char *macGlyphNames[258] = { - ".notdef", - "null", - "CR", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quotesingle", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "grave", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "Adieresis", - "Aring", - "Ccedilla", - "Eacute", - "Ntilde", - "Odieresis", - "Udieresis", - "aacute", - "agrave", - "acircumflex", - "adieresis", - "atilde", - "aring", - "ccedilla", - "eacute", - "egrave", - "ecircumflex", - "edieresis", - "iacute", - "igrave", - "icircumflex", - "idieresis", - "ntilde", - "oacute", - "ograve", - "ocircumflex", - "odieresis", - "otilde", - "uacute", - "ugrave", - "ucircumflex", - "udieresis", - "dagger", - "degree", - "cent", - "sterling", - "section", - "bullet", - "paragraph", - "germandbls", - "registered", - "copyright", - "trademark", - "acute", - "dieresis", - "notequal", - "AE", - "Oslash", - "infinity", - "plusminus", - "lessequal", - "greaterequal", - "yen", - "mu1", - "partialdiff", - "summation", - "product", - "pi", - "integral", - "ordfeminine", - "ordmasculine", - "Ohm", - "ae", - "oslash", - "questiondown", - "exclamdown", - "logicalnot", - "radical", - "florin", - "approxequal", - "increment", - "guillemotleft", - "guillemotright", - "ellipsis", - "nbspace", - "Agrave", - "Atilde", - "Otilde", - "OE", - "oe", - "endash", - "emdash", - "quotedblleft", - "quotedblright", - "quoteleft", - "quoteright", - "divide", - "lozenge", - "ydieresis", - "Ydieresis", - "fraction", - "currency", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "daggerdbl", - "periodcentered", - "quotesinglbase", - "quotedblbase", - "perthousand", - "Acircumflex", - "Ecircumflex", - "Aacute", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Oacute", - "Ocircumflex", - "applelogo", - "Ograve", - "Uacute", - "Ucircumflex", - "Ugrave", - "dotlessi", - "circumflex", - "tilde", - "overscore", - "breve", - "dotaccent", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "Lslash", - "lslash", - "Scaron", - "scaron", - "Zcaron", - "zcaron", - "brokenbar", - "Eth", - "eth", - "Yacute", - "yacute", - "Thorn", - "thorn", - "minus", - "multiply", - "onesuperior", - "twosuperior", - "threesuperior", - "onehalf", - "onequarter", - "threequarters", - "franc", - "Gbreve", - "gbreve", - "Idot", - "Scedilla", - "scedilla", - "Cacute", - "cacute", - "Ccaron", - "ccaron", - "dmacron" -}; - -struct TrueTypeLoca { - int idx; - int pos; - int length; -}; - -TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) { - 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 = (TTFontTableHdr *)gmalloc(nTables * sizeof(TTFontTableHdr)); - pos = 12; - for (i = 0; i < nTables; ++i) { - tableHdrs[i].tag[0] = getByte(pos+0); - tableHdrs[i].tag[1] = getByte(pos+1); - tableHdrs[i].tag[2] = getByte(pos+2); - tableHdrs[i].tag[3] = getByte(pos+3); - tableHdrs[i].checksum = getULong(pos+4); - tableHdrs[i].offset = getULong(pos+8); - tableHdrs[i].length = getULong(pos+12); - if (tableHdrs[i].offset + tableHdrs[i].length < tableHdrs[i].offset || - tableHdrs[i].offset + tableHdrs[i].length > (Guint)len) { - tableHdrs[i].offset = (Guint)-1; - } - pos += 16; - } - - // check for tables that are required by both the TrueType spec - // and the Type 42 spec - if (seekTable("head") < 0 || - seekTable("hhea") < 0 || - seekTable("loca") < 0 || - seekTable("maxp") < 0 || - seekTable("glyf") < 0 || - seekTable("hmtx") < 0) { - error(-1, "TrueType font file is missing a required table"); - return; - } - - // some embedded TrueType fonts have an incorrect (too small) cmap - // table size - idx = seekTableIdx("cmap"); - if (idx >= 0) { - pos = tableHdrs[idx].offset; - n = getUShort(pos + 2); - size = (Guint)(4 + 8 * n); - for (i = 0; i < n; ++i) { - startPos = getULong(pos + 4 + 8*i + 4); - length = getUShort(pos + startPos + 2); - endPos = startPos + length; - if (endPos > size) { - size = endPos; - } - } - if ((mungedCmapSize = size > tableHdrs[idx].length)) { -#if 0 // don't bother printing this error message - it's too common - error(-1, "Bad cmap table size in TrueType font"); -#endif - tableHdrs[idx].length = size; - } - } else { - mungedCmapSize = gFalse; - } - - // read the 'head' table - pos = seekTable("head"); - bbox[0] = getShort(pos + 36); - bbox[1] = getShort(pos + 38); - bbox[2] = getShort(pos + 40); - bbox[3] = getShort(pos + 42); - locaFmt = getShort(pos + 50); - - // read the 'maxp' table - pos = seekTable("maxp"); - nGlyphs = getUShort(pos + 4); - - // 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() { - int i; - - if (encoding) { - for (i = 0; i < 256; ++i) { - gfree(encoding[i]); - } - gfree(encoding); - } - if (cmaps) { - gfree(cmaps); - } - gfree(tableHdrs); -} - -char *TrueTypeFontFile::getName() { - return NULL; -} - -char **TrueTypeFontFile::getEncoding() { - int i; - - if (!encoding) { - encoding = (char **)gmalloc(256 * sizeof(char *)); - for (i = 0; i < 256; ++i) { - encoding[i] = NULL; - } - } - return encoding; -} - -int TrueTypeFontFile::getNumCmaps() { - return nCmaps; -} - -int TrueTypeFontFile::getCmapPlatform(int i) { - return cmaps[i].platform; -} - -int TrueTypeFontFile::getCmapEncoding(int i) { - return cmaps[i].encoding; -} - -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; -} - -Gushort TrueTypeFontFile::mapCodeToGID(int i, int c) { - if (i < 0 || i >= nCmaps) { - return 0; - } - return (Gushort)getCmapEntry(cmaps[i].fmt, cmaps[i].offset, c); -} - -GHash *TrueTypeFontFile::getNameToGID() { - GHash *nameToGID; - Guint fmt; - GString *s; - int stringIdx, stringPos, pos, i, j, n; - - if ((pos = seekTable("post")) < 0) { - return NULL; - } - - fmt = getULong(pos); - nameToGID = NULL; - - // 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) { - 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)) ; - } - 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); - } - ++stringIdx; - stringPos += 1 + n; - } - } - - // 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 nameToGID; -} - -void TrueTypeFontFile::convertToType42(char *name, char **encodingA, - GBool pdfFontHasEncoding, - Gushort *codeToGID, - FontFileOutputFunc outputFunc, - void *outputStream) { - char buf[512]; - - // write the header - sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0)); - (*outputFunc)(outputStream, buf, strlen(buf)); - - // begin the font dictionary - (*outputFunc)(outputStream, "10 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - - // write the guts of the dictionary - cvtEncoding(encodingA, pdfFontHasEncoding, outputFunc, outputStream); - cvtCharStrings(encodingA, pdfFontHasEncoding, codeToGID, - outputFunc, outputStream); - cvtSfnts(outputFunc, outputStream, NULL); - - // end the dictionary and define the font - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); -} - -void TrueTypeFontFile::convertToCIDType2(char *name, Gushort *cidMap, - int nCIDs, - FontFileOutputFunc outputFunc, - void *outputStream) { - char buf[512]; - Gushort cid; - int i, j, k; - - // write the header - sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0)); - (*outputFunc)(outputStream, buf, strlen(buf)); - - // begin the font dictionary - (*outputFunc)(outputStream, "20 dict begin\n", 14); - (*outputFunc)(outputStream, "/CIDFontName /", 14); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); - (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); - (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); - (*outputFunc)(outputStream, " /Supplement 0 def\n", 20); - (*outputFunc)(outputStream, " end def\n", 10); - (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15); - if (cidMap) { - sprintf(buf, "/CIDCount %d def\n", nCIDs); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (nCIDs > 32767) { - (*outputFunc)(outputStream, "/CIDMap [", 9); - for (i = 0; i < nCIDs; i += 32768 - 16) { - (*outputFunc)(outputStream, "<\n", 2); - for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) { - (*outputFunc)(outputStream, " ", 2); - for (k = 0; k < 16 && i+j+k < nCIDs; ++k) { - cid = cidMap[i+j+k]; - sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "\n", 1); - } - (*outputFunc)(outputStream, " >", 3); - } - (*outputFunc)(outputStream, "\n", 1); - (*outputFunc)(outputStream, "] def\n", 6); - } else { - (*outputFunc)(outputStream, "/CIDMap <\n", 10); - for (i = 0; i < nCIDs; i += 16) { - (*outputFunc)(outputStream, " ", 2); - for (j = 0; j < 16 && i+j < nCIDs; ++j) { - cid = cidMap[i+j]; - sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "\n", 1); - } - (*outputFunc)(outputStream, "> def\n", 6); - } - } else { - // direct mapping - just fill the string(s) with s[i]=i - sprintf(buf, "/CIDCount %d def\n", nGlyphs); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (nGlyphs > 32767) { - (*outputFunc)(outputStream, "/CIDMap [\n", 10); - for (i = 0; i < nGlyphs; i += 32767) { - j = nGlyphs - i < 32767 ? nGlyphs - i : 32767; - sprintf(buf, " %d string 0 1 %d {\n", 2 * j, j - 1); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 1 index exch dup 2 mul 1 add exch %d add" - " 255 and put\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, " } for\n", 8); - } - (*outputFunc)(outputStream, "] def\n", 6); - } else { - sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 0 1 %d {\n", nGlyphs - 1); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, - " 2 copy dup 2 mul exch -8 bitshift put\n", 42); - (*outputFunc)(outputStream, - " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50); - (*outputFunc)(outputStream, " } for\n", 8); - (*outputFunc)(outputStream, "def\n", 4); - } - } - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26); - (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30); - (*outputFunc)(outputStream, " /.notdef 0 def\n", 17); - (*outputFunc)(outputStream, " end readonly def\n", 19); - - // write the guts of the dictionary - cvtSfnts(outputFunc, outputStream, NULL); - - // end the dictionary and define the font - (*outputFunc)(outputStream, - "CIDFontName currentdict end /CIDFont defineresource pop\n", - 56); -} - -void TrueTypeFontFile::convertToType0(char *name, Gushort *cidMap, - int nCIDs, - FontFileOutputFunc outputFunc, - void *outputStream) { - char buf[512]; - GString *sfntsName; - int n, i, j; - - // write the Type 42 sfnts array - sfntsName = (new GString(name))->append("_sfnts"); - cvtSfnts(outputFunc, outputStream, sfntsName); - delete sfntsName; - - // write the descendant Type 42 fonts - n = cidMap ? nCIDs : nGlyphs; - for (i = 0; i < n; i += 256) { - (*outputFunc)(outputStream, "10 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, name, strlen(name)); - sprintf(buf, "_%02x def\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - (*outputFunc)(outputStream, "/sfnts ", 7); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, "_sfnts def\n", 11); - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - for (j = 0; j < 256 && i+j < n; ++j) { - sprintf(buf, "dup %d /c%02x put\n", j, j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "readonly def\n", 13); - (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32); - (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); - for (j = 0; j < 256 && i+j < n; ++j) { - sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "end readonly def\n", 17); - (*outputFunc)(outputStream, - "FontName currentdict end definefont pop\n", 40); - } - - // write the Type 0 parent font - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 0 def\n", 16); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); - (*outputFunc)(outputStream, "/Encoding [\n", 12); - for (i = 0; i < n; i += 256) { - sprintf(buf, "%d\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "/FDepVector [\n", 14); - for (i = 0; i < n; i += 256) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, name, strlen(name)); - sprintf(buf, "_%02x findfont\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); -} - -int TrueTypeFontFile::getByte(int pos) { - if (pos < 0 || pos >= len) { - return 0; - } - return file[pos] & 0xff; -} - -int TrueTypeFontFile::getChar(int pos) { - int x; - - if (pos < 0 || pos >= len) { - return 0; - } - x = file[pos] & 0xff; - if (x & 0x80) - x |= 0xffffff00; - return x; -} - -int TrueTypeFontFile::getUShort(int pos) { - int x; - - if (pos < 0 || pos+1 >= len) { - return 0; - } - x = file[pos] & 0xff; - x = (x << 8) + (file[pos+1] & 0xff); - return x; -} - -int TrueTypeFontFile::getShort(int pos) { - int x; - - if (pos < 0 || pos+1 >= len) { - return 0; - } - x = file[pos] & 0xff; - x = (x << 8) + (file[pos+1] & 0xff); - if (x & 0x8000) - x |= 0xffff0000; - return x; -} - -Guint TrueTypeFontFile::getULong(int pos) { - int x; - - if (pos < 0 || pos+3 >= len) { - return 0; - } - x = file[pos] & 0xff; - x = (x << 8) + (file[pos+1] & 0xff); - x = (x << 8) + (file[pos+2] & 0xff); - x = (x << 8) + (file[pos+3] & 0xff); - return x; -} - -double TrueTypeFontFile::getFixed(int pos) { - int x, y; - - x = getShort(pos); - y = getUShort(pos+2); - return (double)x + (double)y / 65536; -} - -int TrueTypeFontFile::seekTable(char *tag) { - int i; - - for (i = 0; i < nTables; ++i) { - if (!strncmp(tableHdrs[i].tag, tag, 4)) { - return (int)tableHdrs[i].offset; - } - } - return -1; -} - -int TrueTypeFontFile::seekTableIdx(char *tag) { - int i; - - for (i = 0; i < nTables; ++i) { - if (!strncmp(tableHdrs[i].tag, tag, 4)) { - if (tableHdrs[i].offset == (Guint)-1) { - return -1; - } - return i; - } - } - return -1; -} - -void TrueTypeFontFile::cvtEncoding(char **encodingA, GBool pdfFontHasEncoding, - FontFileOutputFunc outputFunc, - void *outputStream) { - char *name; - char buf[64]; - int i; - - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - if (pdfFontHasEncoding) { - for (i = 0; i < 256; ++i) { - if (!(name = encodingA[i])) { - name = ".notdef"; - } - sprintf(buf, "dup %d /", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, " put\n", 5); - } - } else { - for (i = 0; i < 256; ++i) { - sprintf(buf, "dup %d /c%02x put\n", i, i); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - (*outputFunc)(outputStream, "readonly def\n", 13); -} - -void TrueTypeFontFile::cvtCharStrings(char **encodingA, - GBool pdfFontHasEncoding, - Gushort *codeToGID, - FontFileOutputFunc outputFunc, - void *outputStream) { - char *name; - char buf[64], buf2[16]; - int i, k; - - // always define '.notdef' - (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32); - (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); - - // if there's no 'cmap' table, punt - if (nCmaps == 0) { - goto err; - } - - // map char name to glyph index: - // 1. use encoding to map name to char code - // 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")) { - 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 > 0 && k < nGlyphs) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, name, strlen(name)); - sprintf(buf, " %d def\n", k); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - } - - err: - (*outputFunc)(outputStream, "end readonly def\n", 17); -} - -int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) { - int cmapLen, cmapFirst; - int segCnt, segEnd, segStart, segDelta, segOffset; - int a, b, m, i; - - switch (cmapFmt) { - case 0: // byte encoding table (Apple standard) - cmapLen = getUShort(pos + 2); - if (code >= cmapLen) { - return 0; - } - return getByte(pos + 6 + code); - - case 4: // segment mapping to delta values (Microsoft standard) - segCnt = getUShort(pos + 6) / 2; - a = -1; - b = segCnt - 1; - segEnd = getUShort(pos + 14 + 2*b); - if (code > segEnd) { - // malformed font -- the TrueType spec requires the last segEnd - // to be 0xffff - return 0; - } - // invariant: seg[a].end < code <= seg[b].end - while (b - a > 1) { - m = (a + b) / 2; - segEnd = getUShort(pos + 14 + 2*m); - if (segEnd < code) { - a = m; - } else { - b = m; - } - } - 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 { - i = getUShort(pos + 16 + 6*segCnt + 2*b + - segOffset + 2 * (code - segStart)); - if (i != 0) { - i = (i + segDelta) & 0xffff; - } - } - return i; - - case 6: // trimmed table mapping - cmapFirst = getUShort(pos + 6); - cmapLen = getUShort(pos + 8); - if (code < cmapFirst || code >= cmapFirst + cmapLen) { - return 0; - } - return getUShort(pos + 10 + 2*(code - cmapFirst)); - - default: - // shouldn't happen - this is checked earlier - break; - } - return 0; -} - -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]; - TrueTypeLoca *origLocaTable; - char *locaTable; - int nNewTables; - Guint checksum; - int pos, glyfPos, length, glyphLength, pad; - int i, j, k; - - // construct the 'head' table, zero out the font checksum - memcpy(headTable, file + seekTable("head"), 54); - headTable[8] = headTable[9] = headTable[10] = headTable[11] = (char)0; - - // read the original 'loca' table and sort it into proper order -- - // some (non-compliant) fonts have out-of-order loca tables; in - // order to correctly handle the case where (compliant) fonts have - // empty entries in the middle of the table, cmpTrueTypeLocaPos uses - // pos as its primary sort key, and idx as its secondary key - // (ensuring that adjacent entries with the same pos value remain in - // the same order) - origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * - sizeof(TrueTypeLoca)); - pos = seekTable("loca"); - for (i = 0; i <= nGlyphs; ++i) { - origLocaTable[i].idx = i; - if (locaFmt) { - origLocaTable[i].pos = getULong(pos + 4*i); - } else { - origLocaTable[i].pos = 2 * getUShort(pos + 2*i); - } - } - qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaPos); - for (i = 0; i < nGlyphs; ++i) { - origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos; - } - origLocaTable[nGlyphs].length = 0; - qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaIdx); - - // construct the new 'loca' table, padding each glyph out to a - // multiple of 4 bytes - locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2)); - pos = 0; - for (i = 0; i <= nGlyphs; ++i) { - if (locaFmt) { - locaTable[4*i ] = (char)(pos >> 24); - locaTable[4*i+1] = (char)(pos >> 16); - locaTable[4*i+2] = (char)(pos >> 8); - locaTable[4*i+3] = (char) pos; - } else { - locaTable[2*i ] = (char)(pos >> 9); - locaTable[2*i+1] = (char)(pos >> 1); - } - length = origLocaTable[i].length; - if (length & 3) { - length += 4 - (length & 3); - } - pos += length; - } - - // count the number of tables - nNewTables = 0; - for (i = 0; i < nT42Tables; ++i) { - if (t42Tables[i].required || - seekTable(t42Tables[i].tag) >= 0) { - ++nNewTables; - } - } - - // construct the new table headers, including table checksums - // (pad each table out to a multiple of 4 bytes) - pos = 12 + nNewTables*16; - k = 0; - for (i = 0; i < nT42Tables; ++i) { - length = -1; - checksum = 0; // make gcc happy - if (i == t42HeadTable) { - length = 54; - checksum = computeTableChecksum(headTable, 54); - } else if (i == t42LocaTable) { - length = (nGlyphs + 1) * (locaFmt ? 4 : 2); - checksum = computeTableChecksum(locaTable, length); - } else if (i == t42GlyfTable) { - length = 0; - checksum = 0; - glyfPos = seekTable("glyf"); - for (j = 0; j < nGlyphs; ++j) { - glyphLength = origLocaTable[j].length; - pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0; - length += glyphLength + pad; - if (glyphLength >= 0 && - glyfPos + origLocaTable[j].pos + glyphLength <= len) { - checksum += - computeTableChecksum(file + glyfPos + origLocaTable[j].pos, - glyphLength); - } - } - } else { - if ((j = seekTableIdx(t42Tables[i].tag)) >= 0) { - length = tableHdrs[j].length; - checksum = computeTableChecksum(file + tableHdrs[j].offset, length); - } else if (t42Tables[i].required) { - error(-1, "Embedded TrueType font is missing a required table ('%s')", - t42Tables[i].tag); - length = 0; - checksum = 0; - } - } - if (length >= 0) { - strncpy(newTableHdrs[k].tag, t42Tables[i].tag, 4); - newTableHdrs[k].checksum = checksum; - newTableHdrs[k].offset = pos; - newTableHdrs[k].length = length; - pad = (length & 3) ? 4 - (length & 3) : 0; - pos += length + pad; - ++k; - } - } - - // construct the table directory - tableDir[0] = 0x00; // sfnt version - tableDir[1] = 0x01; - tableDir[2] = 0x00; - tableDir[3] = 0x00; - tableDir[4] = 0; // numTables - tableDir[5] = nNewTables; - tableDir[6] = 0; // searchRange - tableDir[7] = (char)128; - tableDir[8] = 0; // entrySelector - tableDir[9] = 3; - tableDir[10] = 0; // rangeShift - tableDir[11] = (char)(16 * nNewTables - 128); - pos = 12; - for (i = 0; i < nNewTables; ++i) { - tableDir[pos ] = newTableHdrs[i].tag[0]; - tableDir[pos+ 1] = newTableHdrs[i].tag[1]; - tableDir[pos+ 2] = newTableHdrs[i].tag[2]; - tableDir[pos+ 3] = newTableHdrs[i].tag[3]; - tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24); - tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16); - tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >> 8); - tableDir[pos+ 7] = (char) newTableHdrs[i].checksum; - tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24); - tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16); - tableDir[pos+10] = (char)(newTableHdrs[i].offset >> 8); - tableDir[pos+11] = (char) newTableHdrs[i].offset; - tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24); - tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16); - tableDir[pos+14] = (char)(newTableHdrs[i].length >> 8); - tableDir[pos+15] = (char) newTableHdrs[i].length; - pos += 16; - } - - // compute the font checksum and store it in the head table - checksum = computeTableChecksum(tableDir, 12 + nNewTables*16); - for (i = 0; i < nNewTables; ++i) { - checksum += newTableHdrs[i].checksum; - } - checksum = 0xb1b0afba - checksum; // because the TrueType spec says so - headTable[ 8] = (char)(checksum >> 24); - headTable[ 9] = (char)(checksum >> 16); - headTable[10] = (char)(checksum >> 8); - headTable[11] = (char) checksum; - - // start the sfnts array - if (name) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, name->getCString(), name->getLength()); - (*outputFunc)(outputStream, " [\n", 3); - } else { - (*outputFunc)(outputStream, "/sfnts [\n", 9); - } - - // write the table directory - dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream); - - // write the tables - for (i = 0; i < nNewTables; ++i) { - if (i == t42HeadTable) { - dumpString(headTable, 54, outputFunc, outputStream); - } else if (i == t42LocaTable) { - length = (nGlyphs + 1) * (locaFmt ? 4 : 2); - dumpString(locaTable, length, outputFunc, outputStream); - } else if (i == t42GlyfTable) { - glyfPos = seekTable("glyf"); - for (j = 0; j < nGlyphs; ++j) { - length = origLocaTable[j].length; - if (length > 0 && - glyfPos + origLocaTable[j].pos + length <= len) { - dumpString(file + glyfPos + origLocaTable[j].pos, length, - outputFunc, outputStream); - } - } - } else { - // length == 0 means the table is missing and the error was - // already reported during the construction of the table - // headers - if ((length = newTableHdrs[i].length) > 0) { - j = seekTable(t42Tables[i].tag); - if (j >= 0) { - dumpString(file + seekTable(t42Tables[i].tag), length, - outputFunc, outputStream); - } - } - } - } - - // end the sfnts array - (*outputFunc)(outputStream, "] def\n", 6); - - gfree(origLocaTable); - gfree(locaTable); -} - -void TrueTypeFontFile::dumpString(char *s, int length, - FontFileOutputFunc outputFunc, - void *outputStream) { - char buf[64]; - int pad, i, j; - - (*outputFunc)(outputStream, "<", 1); - for (i = 0; i < length; i += 32) { - for (j = 0; j < 32 && i+j < length; ++j) { - sprintf(buf, "%02X", s[i+j] & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (i % (65536 - 32) == 65536 - 64) { - (*outputFunc)(outputStream, ">\n<", 3); - } else if (i+32 < length) { - (*outputFunc)(outputStream, "\n", 1); - } - } - if (length & 3) { - pad = 4 - (length & 3); - for (i = 0; i < pad; ++i) { - (*outputFunc)(outputStream, "00", 2); - } - } - // add an extra zero byte because the Adobe Type 42 spec says so - (*outputFunc)(outputStream, "00>\n", 4); -} - -Guint TrueTypeFontFile::computeTableChecksum(char *data, int length) { - Guint checksum, word; - int i; - - checksum = 0; - for (i = 0; i+3 < length; i += 4) { - word = ((data[i ] & 0xff) << 24) + - ((data[i+1] & 0xff) << 16) + - ((data[i+2] & 0xff) << 8) + - (data[i+3] & 0xff); - checksum += word; - } - if (length & 3) { - word = 0; - i = length & ~3; - switch (length & 3) { - case 3: - word |= (data[i+2] & 0xff) << 8; - case 2: - word |= (data[i+1] & 0xff) << 16; - case 1: - word |= (data[i ] & 0xff) << 24; - break; - } - checksum += word; - } - return checksum; -} - -void TrueTypeFontFile::writeTTF(FILE *out) { - static char cmapTab[20] = { - 0, 0, // table version number - 0, 1, // number of encoding tables - 0, 1, // platform ID - 0, 0, // encoding ID - 0, 0, 0, 12, // offset of subtable - 0, 0, // subtable format - 0, 1, // subtable length - 0, 1, // subtable version - 0, // map char 0 -> glyph 0 - 0 // pad to multiple of four bytes - }; - static char nameTab[8] = { - 0, 0, // format - 0, 0, // number of name records - 0, 6, // offset to start of string storage - 0, 0 // pad to multiple of four bytes - }; - static char postTab[32] = { - 0, 1, 0, 0, // format - 0, 0, 0, 0, // italic angle - 0, 0, // underline position - 0, 0, // underline thickness - 0, 0, 0, 0, // fixed pitch - 0, 0, 0, 0, // min Type 42 memory - 0, 0, 0, 0, // max Type 42 memory - 0, 0, 0, 0, // min Type 1 memory - 0, 0, 0, 0 // max Type 1 memory - }; - GBool haveCmap, haveName, havePost; - GBool dirCmap, dirName, dirPost; - GBool unsortedLoca; - int nNewTables, nZeroLengthTables, nAllTables; - TTFontTableHdr *newTableHdrs; - char *tableDir; - TrueTypeLoca *origLocaTable; - char *locaTable; - int length, glyfLength; - Guint t, pos, pos2, pos3; - int i, j, k; - - // 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); - 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 - nZeroLengthTables + nNewTables; - newTableHdrs = (TTFontTableHdr *)gmalloc(nAllTables * - sizeof(TTFontTableHdr)); - dirCmap = haveCmap; - dirName = haveName; - dirPost = havePost; - pos = 12 + nAllTables * 16; - j = 0; - for (i = 0; i < nTables; ++i) { - if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) { - memcpy(newTableHdrs[j].tag, "cmap", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(cmapTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - dirCmap = gTrue; - } - if (!dirName && strncmp(tableHdrs[i].tag, "name", 4) > 0) { - memcpy(newTableHdrs[j].tag, "name", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(nameTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - dirName = gTrue; - } - if (!dirPost && strncmp(tableHdrs[i].tag, "post", 4) > 0) { - memcpy(newTableHdrs[j].tag, "post", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(postTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - dirPost = gTrue; - } - // throw away zero-length tables - they confuse FreeType - if (tableHdrs[i].length > 0) { - memcpy(newTableHdrs[j].tag, tableHdrs[i].tag, 4); - newTableHdrs[j].checksum = tableHdrs[i].checksum; - newTableHdrs[j].offset = pos; - if (unsortedLoca && !strncmp(tableHdrs[i].tag, "loca", 4)) { - newTableHdrs[j].length = (nGlyphs + 1) * (locaFmt ? 4 : 2); - } else if (unsortedLoca && !strncmp(tableHdrs[i].tag, "glyf", 4)) { - newTableHdrs[j].length = glyfLength; - } else { - newTableHdrs[j].length = tableHdrs[i].length; - } - pos += newTableHdrs[j].length; - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - } - } - if (!dirCmap) { - memcpy(newTableHdrs[j].tag, "cmap", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(cmapTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - } - if (!dirName) { - memcpy(newTableHdrs[j].tag, "name", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(nameTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - } - if (!dirPost) { - memcpy(newTableHdrs[j].tag, "post", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(postTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - } - tableDir = (char *)gmalloc(12 + nAllTables * 16); - tableDir[0] = 0x00; // sfnt version - tableDir[1] = 0x01; - tableDir[2] = 0x00; - tableDir[3] = 0x00; - tableDir[4] = (char)((nAllTables >> 8) & 0xff); // numTables - tableDir[5] = (char)(nAllTables & 0xff); - for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ; - t = 1 << (4 + i); - tableDir[6] = (char)((t >> 8) & 0xff); // searchRange - tableDir[7] = (char)(t & 0xff); - tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector - tableDir[9] = (char)(i & 0xff); - t = nAllTables * 16 - t; - tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift - tableDir[11] = (char)(t & 0xff); - pos = 12; - for (i = 0; i < nAllTables; ++i) { - tableDir[pos ] = newTableHdrs[i].tag[0]; - tableDir[pos+ 1] = newTableHdrs[i].tag[1]; - tableDir[pos+ 2] = newTableHdrs[i].tag[2]; - tableDir[pos+ 3] = newTableHdrs[i].tag[3]; - tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24); - tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16); - tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >> 8); - tableDir[pos+ 7] = (char) newTableHdrs[i].checksum; - tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24); - tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16); - tableDir[pos+10] = (char)(newTableHdrs[i].offset >> 8); - tableDir[pos+11] = (char) newTableHdrs[i].offset; - tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24); - tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16); - tableDir[pos+14] = (char)(newTableHdrs[i].length >> 8); - tableDir[pos+15] = (char) newTableHdrs[i].length; - pos += 16; - } - - // write the table directory - fwrite(tableDir, 1, 12 + 16 * nAllTables, 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); - } -} |