diff options
Diffstat (limited to 'filters/kword/pdf/xpdf/xpdf/FontFile.cpp')
-rw-r--r-- | filters/kword/pdf/xpdf/xpdf/FontFile.cpp | 3883 |
1 files changed, 3883 insertions, 0 deletions
diff --git a/filters/kword/pdf/xpdf/xpdf/FontFile.cpp b/filters/kword/pdf/xpdf/xpdf/FontFile.cpp new file mode 100644 index 000000000..8a6597b08 --- /dev/null +++ b/filters/kword/pdf/xpdf/xpdf/FontFile.cpp @@ -0,0 +1,3883 @@ +//======================================================================== +// +// FontFile.cpp +// +// Copyright 1999-2002 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <math.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include "gmem.h" +#include "Error.h" +#include "GlobalParams.h" +#include "CharCodeToUnicode.h" +#include "FontEncodingTables.h" +#include "FontFile.h" + +#include "CompactFontTables.h" + +//------------------------------------------------------------------------ + +static inline const char *nextLine(const char *line, const char *end) { + while (line < end && *line != '\n' && *line != '\r') + ++line; + while (line < end && *line == '\n' || *line == '\r') + ++line; + return line; +} + +static const char hexChars[17] = "0123456789ABCDEF"; + +//------------------------------------------------------------------------ +// FontFile +//------------------------------------------------------------------------ + +FontFile::FontFile() { +} + +FontFile::~FontFile() { +} + +//------------------------------------------------------------------------ +// Type1FontFile +//------------------------------------------------------------------------ + +Type1FontFile::Type1FontFile(const char *file, int len) { + const char *line, *line1; + char *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(const char *fileA, int lenA) { + Guchar *nameIdxPtr, *idxPtr0, *idxPtr1; + + file = fileA; + len = lenA; + name = NULL; + encoding = NULL; + + // some tools embed Type 1C fonts with an extra whitespace char at + // the beginning + if (file[0] != '\x01') { + ++file; + } + + // read header + topOffSize = file[3] & 0xff; + + // read name index (first font only) + nameIdxPtr = (Guchar *)file + (file[2] & 0xff); + idxPtr0 = getIndexValPtr(nameIdxPtr, 0); + idxPtr1 = getIndexValPtr(nameIdxPtr, 1); + name = new GString((char *)idxPtr0, idxPtr1 - idxPtr0); + + topDictIdxPtr = getIndexEnd(nameIdxPtr); + stringIdxPtr = getIndexEnd(topDictIdxPtr); + gsubrIdxPtr = getIndexEnd(stringIdxPtr); +} + +Type1CFontFile::~Type1CFontFile() { + int i; + + delete name; + if (encoding) { + for (i = 0; i < 256; ++i) { + gfree(encoding[i]); + } + gfree(encoding); + } +} + +const char *Type1CFontFile::getName() { + return name->getCString(); +} + +char **Type1CFontFile::getEncoding() { + if (!encoding) { + readNameAndEncoding(); + } + return encoding; +} + +void Type1CFontFile::readNameAndEncoding() { + char buf[256]; + Guchar *idxPtr0, *idxPtr1, *ptr; + 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) + idxPtr0 = getIndexValPtr(topDictIdxPtr, 0); + idxPtr1 = getIndexValPtr(topDictIdxPtr, 1); + charset = enc = charstrings = 0; + i = 0; + ptr = idxPtr0; + while (ptr < idxPtr1) { + if (*ptr <= 27 || *ptr == 31) { + key = *ptr++; + if (key == 0x0c) { + key = (key << 8) | *ptr++; + } + if (key == 0x0f) { // charset + charset = (int)op[0]; + } else if (key == 0x10) { // encoding + enc = (int)op[0]; + } else if (key == 0x11) { // charstrings + charstrings = (int)op[0]; + } + i = 0; + } else { + x = getNum(&ptr, &isFP); + if (i < 48) { + op[i++] = x; + } + } + } + + // get number of glyphs from charstrings index + nGlyphs = getIndexLen((Guchar *)file + 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 { + ptr = (Guchar *)file + enc; + encFormat = *ptr++; + if ((encFormat & 0x7f) == 0) { + nCodes = 1 + *ptr++; + if (nCodes > nGlyphs) { + nCodes = nGlyphs; + } + for (i = 1; i < nCodes; ++i) { + c = *ptr++; + encoding[c] = copyString(getString(glyphNames[i], buf)); + } + } else if ((encFormat & 0x7f) == 1) { + nRanges = *ptr++; + nCodes = 1; + for (i = 0; i < nRanges; ++i) { + c = *ptr++; + nLeft = *ptr++; + for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { + encoding[c] = copyString(getString(glyphNames[nCodes], buf)); + ++nCodes; + ++c; + } + } + } + if (encFormat & 0x80) { + nSups = *ptr++; + for (i = 0; i < nSups; ++i) { + c = *ptr++; + sid = getWord(ptr, 2); + ptr += 2; + encoding[c] = copyString(getString(sid, buf)); + } + } + } + + if (charset > 2) { + gfree(glyphNames); + } +} + +void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, + void *outputStreamA) { + Type1CTopDict dict; + Type1CPrivateDict privateDict; + char buf[512], eBuf[256]; + Guchar *idxPtr0, *idxPtr1, *subrsIdxPtr, *charStringsIdxPtr, *ptr; + int nGlyphs, nCodes, nRanges, nLeft, nSups; + Gushort *glyphNames; + int encFormat, nSubrs, nCharStrings; + int c, sid; + int i, j, n; + + outputFunc = outputFuncA; + outputStream = outputStreamA; + + // read top dict (first font only) + readTopDict(&dict); + + // get global subrs + //~ ... global subrs are unimplemented + + // write header and font dictionary, up to encoding + (*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); + (*outputFunc)(outputStream, "11 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((Guchar *)file + 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 { + ptr = (Guchar *)file + dict.encoding; + encFormat = *ptr++; + if ((encFormat & 0x7f) == 0) { + nCodes = 1 + *ptr++; + if (nCodes > nGlyphs) { + nCodes = nGlyphs; + } + for (i = 1; i < nCodes; ++i) { + c = *ptr++; + sprintf(buf, "dup %d /", c); + (*outputFunc)(outputStream, buf, strlen(buf)); + getString(glyphNames[i], buf); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, " put\n", 5); + } + } else if ((encFormat & 0x7f) == 1) { + nRanges = *ptr++; + nCodes = 1; + for (i = 0; i < nRanges; ++i) { + c = *ptr++; + nLeft = *ptr++; + 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) { + nSups = *ptr++; + for (i = 0; i < nSups; ++i) { + c = *ptr++; + sid = getWord(ptr, 2); + ptr += 2; + sprintf(buf, "dup %d /", c); + (*outputFunc)(outputStream, buf, strlen(buf)); + getString(sid, buf); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, " put\n", 5); + } + } + } + (*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} ND\n"); + readPrivateDict(&privateDict, dict.privateOffset, dict.privateSize); + eexecWrite(privateDict.dictData->getCString()); + defaultWidthX = privateDict.defaultWidthX; + defaultWidthXFP = privateDict.defaultWidthXFP; + nominalWidthX = privateDict.nominalWidthX; + nominalWidthXFP = privateDict.nominalWidthXFP; + + // get subrs + if (privateDict.subrsOffset != 0) { + subrsIdxPtr = (Guchar *)file + dict.privateOffset + + privateDict.subrsOffset; + nSubrs = getIndexLen(subrsIdxPtr); + sprintf(eBuf, "/Subrs %d array\n", nSubrs); + eexecWrite(eBuf); + idxPtr1 = getIndexValPtr(subrsIdxPtr, 0); + for (i = 0; i < nSubrs; ++i) { + idxPtr0 = idxPtr1; + idxPtr1 = getIndexValPtr(subrsIdxPtr, i+1); + n = idxPtr1 - idxPtr0; +#if 1 //~ Type 2 subrs are unimplemented + error(-1, "Unimplemented Type 2 subrs"); +#else + sprintf(eBuf, "dup %d %d RD ", i, n); + eexecWrite(eBuf); + eexecCvtGlyph(idxPtr0, n); + eexecWrite(" NP\n"); +#endif + } + eexecWrite("ND\n"); + } + + // get CharStrings + charStringsIdxPtr = (Guchar *)file + dict.charStrings; + nCharStrings = getIndexLen(charStringsIdxPtr); + sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings); + eexecWrite(eBuf); + idxPtr1 = getIndexValPtr(charStringsIdxPtr, 0); + for (i = 0; i < nCharStrings; ++i) { + idxPtr0 = idxPtr1; + idxPtr1 = getIndexValPtr(charStringsIdxPtr, i+1); + n = idxPtr1 - idxPtr0; + eexecCvtGlyph(getString(glyphNames[i], buf), idxPtr0, n); + } + eexecWrite("end\n"); + eexecWrite("end\n"); + eexecWrite("readonly put\n"); + eexecWrite("noaccess put\n"); + eexecWrite("dup /FontName get exch definefont pop\n"); + eexecWrite("mark currentfile closefile\n"); + + // trailer + if (line > 0) { + (*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(const char *psName, + FontFileOutputFunc outputFuncA, + void *outputStreamA) { + Type1CTopDict dict; + Type1CPrivateDict *privateDicts; + GString *charStrings; + int *charStringOffsets; + Gushort *charset; + int *cidMap; + Guchar *fdSelect; + Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr; + 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 { + fdArrayIdx = (Guchar *)file + dict.fdArrayOffset; + nFDs = getIndexLen(fdArrayIdx); + privateDicts = (Type1CPrivateDict *) + gmalloc(nFDs * sizeof(Type1CPrivateDict)); + idxPtr1 = getIndexValPtr(fdArrayIdx, 0); + for (i = 0; i < nFDs; ++i) { + privateDicts[i].dictData = NULL; + idxPtr0 = idxPtr1; + idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1); + ptr = idxPtr0; + j = 0; + while (ptr < idxPtr1) { + if (*ptr <= 27 || *ptr == 31) { + key = *ptr++; + if (key == 0x0c) { + key = (key << 8) | *ptr++; + } + if (key == 0x0012) { + readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]); + } + j = 0; + } else { + x = getNum(&ptr, &isFP); + if (j < 48) { + op[j] = x; + fp[j++] = isFP; + } + } + } + if (!privateDicts[i].dictData) { + privateDicts[i].dictData = new GString(); + privateDicts[i].subrsOffset = 0; + privateDicts[i].defaultWidthX = 0; + privateDicts[i].defaultWidthXFP = gFalse; + privateDicts[i].nominalWidthX = 0; + privateDicts[i].nominalWidthXFP = gFalse; + } + } + } + + // get the glyph count + charStringsIdxPtr = (Guchar *)file + dict.charStrings; + nGlyphs = getIndexLen(charStringsIdxPtr); + + // read the FDSelect table + fdSelect = (Guchar *)gmalloc(nGlyphs); + if (dict.fdSelectOffset == 0) { + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + } else { + ptr = (Guchar *)file + dict.fdSelectOffset; + fdSelectFmt = *ptr++; + if (fdSelectFmt == 0) { + memcpy(fdSelect, ptr, nGlyphs); + } else if (fdSelectFmt == 3) { + nRanges = getWord(ptr, 2); + ptr += 2; + gid0 = getWord(ptr, 2); + ptr += 2; + for (i = 1; i <= nRanges; ++i) { + fd = *ptr++; + gid1 = getWord(ptr, 2); + ptr += 2; + for (j = gid0; j < gid1; ++j) { + fdSelect[j] = fd; + } + gid0 = gid1; + } + } else { + error(-1, "Unknown FDSelect table format in CID font"); + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + } + } + + // read the charset, compute the CID-to-GID mapping + charset = readCharset(dict.charset, nGlyphs); + nCIDs = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] >= nCIDs) { + nCIDs = charset[i] + 1; + } + } + cidMap = (int *)gmalloc(nCIDs * sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = -1; + } + for (i = 0; i < nGlyphs; ++i) { + cidMap[charset[i]] = i; + } + + // build the charstrings + charStrings = new GString(); + charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + charStringOffsets[i] = charStrings->getLength(); + if (cidMap[i] >= 0) { + idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i]); + idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i]+1); + n = idxPtr1 - idxPtr0; + j = fdSelect[cidMap[i]]; + defaultWidthX = privateDicts[j].defaultWidthX; + defaultWidthXFP = privateDicts[j].defaultWidthXFP; + nominalWidthX = privateDicts[j].nominalWidthX; + nominalWidthXFP = privateDicts[j].nominalWidthXFP; + cvtGlyph(idxPtr0, n); + charStrings->append(charBuf); + delete charBuf; + } + } + charStringOffsets[nCIDs] = charStrings->getLength(); + + // compute gdBytes = number of bytes needed for charstring offsets + // (offset size needs to account for the charstring offset table, + // with a worst case of five bytes per entry, plus the charstrings + // themselves) + i = (nCIDs + 1) * 5 + charStrings->getLength(); + if (i < 0x100) { + gdBytes = 1; + } else if (i < 0x10000) { + gdBytes = 2; + } else if (i < 0x1000000) { + gdBytes = 3; + } else { + gdBytes = 4; + } + + // begin the font dictionary + (*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); + + //~ need to deal with subrs + + // 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); + } + + for (i = 0; i < nFDs; ++i) { + delete privateDicts[i].dictData; + } + gfree(privateDicts); + gfree(cidMap); + gfree(charset); + gfree(charStringOffsets); + delete charStrings; + gfree(fdSelect); +} + +void Type1CFontFile::convertToType0(const char *psName, + FontFileOutputFunc outputFuncA, + void *outputStreamA) { + Type1CTopDict dict; + Type1CPrivateDict *privateDicts; + Gushort *charset; + int *cidMap; + Guchar *fdSelect; + Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr; + char buf[512]; + char eBuf[256]; + int nGlyphs, nCIDs, nFDs; + int fdSelectFmt, nRanges, gid0, gid1, fd; + int key; + double x; + GBool isFP; + int i, j, n; + + 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 { + fdArrayIdx = (Guchar *)file + dict.fdArrayOffset; + nFDs = getIndexLen(fdArrayIdx); + privateDicts = (Type1CPrivateDict *) + gmalloc(nFDs * sizeof(Type1CPrivateDict)); + idxPtr1 = getIndexValPtr(fdArrayIdx, 0); + for (i = 0; i < nFDs; ++i) { + privateDicts[i].dictData = NULL; + idxPtr0 = idxPtr1; + idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1); + ptr = idxPtr0; + j = 0; + while (ptr < idxPtr1) { + if (*ptr <= 27 || *ptr == 31) { + key = *ptr++; + if (key == 0x0c) { + key = (key << 8) | *ptr++; + } + if (key == 0x0012) { + readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]); + } + j = 0; + } else { + x = getNum(&ptr, &isFP); + if (j < 48) { + op[j] = x; + fp[j++] = isFP; + } + } + } + if (!privateDicts[i].dictData) { + privateDicts[i].dictData = new GString(); + privateDicts[i].subrsOffset = 0; + privateDicts[i].defaultWidthX = 0; + privateDicts[i].defaultWidthXFP = gFalse; + privateDicts[i].nominalWidthX = 0; + privateDicts[i].nominalWidthXFP = gFalse; + } + } + } + + // get the glyph count + charStringsIdxPtr = (Guchar *)file + dict.charStrings; + nGlyphs = getIndexLen(charStringsIdxPtr); + + // read the FDSelect table + fdSelect = (Guchar *)gmalloc(nGlyphs); + if (dict.fdSelectOffset == 0) { + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + } else { + ptr = (Guchar *)file + dict.fdSelectOffset; + fdSelectFmt = *ptr++; + if (fdSelectFmt == 0) { + memcpy(fdSelect, ptr, nGlyphs); + } else if (fdSelectFmt == 3) { + nRanges = getWord(ptr, 2); + ptr += 2; + gid0 = getWord(ptr, 2); + ptr += 2; + for (i = 1; i <= nRanges; ++i) { + fd = *ptr++; + gid1 = getWord(ptr, 2); + ptr += 2; + for (j = gid0; j < gid1; ++j) { + fdSelect[j] = fd; + } + gid0 = gid1; + } + } else { + error(-1, "Unknown FDSelect table format in CID font"); + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + } + } + + // read the charset, compute the CID-to-GID mapping + charset = readCharset(dict.charset, nGlyphs); + nCIDs = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] >= nCIDs) { + nCIDs = charset[i] + 1; + } + } + cidMap = (int *)gmalloc(nCIDs * sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = -1; + } + for (i = 0; i < nGlyphs; ++i) { + cidMap[charset[i]] = i; + } + + // write the descendant Type 1 fonts + for (i = 0; i < nCIDs; i += 256) { + + //~ this assumes that all CIDs in this block have the same FD -- + //~ to handle multiple FDs correctly, need to somehow divide the + //~ font up by FD + fd = 0; + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + if (cidMap[i+j] >= 0) { + fd = fdSelect[cidMap[i+j]]; + break; + } + } + + // font dictionary (unencrypted section) + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + sprintf(buf, "_%02x def\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", + dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2], + dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/FontBBox [%g %g %g %g] def\n", + dict.fontBBox[0], dict.fontBBox[1], + dict.fontBBox[2], dict.fontBBox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/PaintType %d def\n", dict.paintType); + (*outputFunc)(outputStream, buf, strlen(buf)); + if (dict.paintType != 0) { + sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + sprintf(buf, "dup %d /c%02x put\n", j, j); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "readonly def\n", 13); + (*outputFunc)(outputStream, "currentdict end\n", 16); + + // start the binary section + (*outputFunc)(outputStream, "currentfile eexec\n", 18); + r1 = 55665; + line = 0; + + // start the private dictionary + eexecWrite("\x83\xca\x73\xd5"); + eexecWrite("dup /Private 32 dict dup begin\n"); + eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n"); + eexecWrite("/ND {noaccess def} executeonly def\n"); + eexecWrite("/NP {noaccess put} executeonly def\n"); + eexecWrite("/MinFeature {16 16} ND\n"); + eexecWrite(privateDicts[fd].dictData->getCString()); + defaultWidthX = privateDicts[fd].defaultWidthX; + defaultWidthXFP = privateDicts[fd].defaultWidthXFP; + nominalWidthX = privateDicts[fd].nominalWidthX; + nominalWidthXFP = privateDicts[fd].nominalWidthXFP; + + // start the CharStrings + sprintf(eBuf, "2 index /CharStrings 256 dict dup begin\n"); + eexecWrite(eBuf); + + // write the .notdef CharString + idxPtr0 = getIndexValPtr(charStringsIdxPtr, 0); + idxPtr1 = getIndexValPtr(charStringsIdxPtr, 1); + n = idxPtr1 - idxPtr0; + eexecCvtGlyph(".notdef", idxPtr0, n); + + // write the CharStrings + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + if (cidMap[i+j] >= 0) { + idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]); + idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]+1); + n = idxPtr1 - idxPtr0; + sprintf(buf, "c%02x", j); + eexecCvtGlyph(buf, idxPtr0, n); + } + } + eexecWrite("end\n"); + eexecWrite("end\n"); + eexecWrite("readonly put\n"); + eexecWrite("noaccess put\n"); + eexecWrite("dup /FontName get exch definefont pop\n"); + eexecWrite("mark currentfile closefile\n"); + + // trailer + if (line > 0) { + (*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 + for (i = 0; i < nFDs; ++i) { + delete privateDicts[i].dictData; + } + gfree(privateDicts); + gfree(cidMap); + gfree(charset); + gfree(fdSelect); +} + +void Type1CFontFile::readTopDict(Type1CTopDict *dict) { + Guchar *idxPtr0, *idxPtr1, *ptr; + double x; + GBool isFP; + int key; + int i; + + idxPtr0 = getIndexValPtr(topDictIdxPtr, 0); + idxPtr1 = getIndexValPtr(topDictIdxPtr, 1); + dict->version = 0; + dict->notice = 0; + dict->copyright = 0; + dict->fullName = 0; + dict->familyName = 0; + dict->weight = 0; + dict->isFixedPitch = 0; + dict->italicAngle = 0; + dict->underlinePosition = -100; + dict->underlineThickness = 50; + dict->paintType = 0; + dict->charstringType = 2; + dict->fontMatrix[0] = 0.001; + dict->fontMatrix[1] = 0; + dict->fontMatrix[2] = 0; + dict->fontMatrix[3] = 0.001; + dict->fontMatrix[4] = 0; + dict->fontMatrix[5] = 0; + dict->uniqueID = 0; + dict->fontBBox[0] = 0; + dict->fontBBox[1] = 0; + dict->fontBBox[2] = 0; + dict->fontBBox[3] = 0; + dict->strokeWidth = 0; + dict->charset = 0; + dict->encoding = 0; + dict->charStrings = 0; + dict->privateSize = 0; + dict->privateOffset = 0; + dict->registry = 0; + dict->ordering = 0; + dict->supplement = 0; + dict->fdArrayOffset = 0; + dict->fdSelectOffset = 0; + i = 0; + ptr = idxPtr0; + while (ptr < idxPtr1) { + if (*ptr <= 27 || *ptr == 31) { + key = *ptr++; + if (key == 0x0c) { + key = (key << 8) | *ptr++; + } + switch (key) { + case 0x0000: dict->version = (int)op[0]; break; + case 0x0001: dict->notice = (int)op[0]; break; + case 0x0c00: dict->copyright = (int)op[0]; break; + case 0x0002: dict->fullName = (int)op[0]; break; + case 0x0003: dict->familyName = (int)op[0]; break; + case 0x0004: dict->weight = (int)op[0]; break; + case 0x0c01: dict->isFixedPitch = (int)op[0]; break; + case 0x0c02: dict->italicAngle = op[0]; break; + case 0x0c03: dict->underlinePosition = op[0]; break; + case 0x0c04: dict->underlineThickness = op[0]; break; + case 0x0c05: dict->paintType = (int)op[0]; break; + case 0x0c06: dict->charstringType = (int)op[0]; break; + case 0x0c07: dict->fontMatrix[0] = op[0]; + dict->fontMatrix[1] = op[1]; + dict->fontMatrix[2] = op[2]; + dict->fontMatrix[3] = op[3]; + dict->fontMatrix[4] = op[4]; + dict->fontMatrix[5] = op[5]; break; + case 0x000d: dict->uniqueID = (int)op[0]; break; + case 0x0005: dict->fontBBox[0] = op[0]; + dict->fontBBox[1] = op[1]; + dict->fontBBox[2] = op[2]; + dict->fontBBox[3] = op[3]; break; + case 0x0c08: dict->strokeWidth = op[0]; break; + case 0x000f: dict->charset = (int)op[0]; break; + case 0x0010: dict->encoding = (int)op[0]; break; + case 0x0011: dict->charStrings = (int)op[0]; break; + case 0x0012: dict->privateSize = (int)op[0]; + dict->privateOffset = (int)op[1]; break; + case 0x0c1e: dict->registry = (int)op[0]; + dict->ordering = (int)op[1]; + dict->supplement = (int)op[2]; break; + case 0x0c24: dict->fdArrayOffset = (int)op[0]; break; + case 0x0c25: dict->fdSelectOffset = (int)op[0]; break; + } + i = 0; + } else { + x = getNum(&ptr, &isFP); + if (i < 48) { + op[i] = x; + fp[i++] = isFP; + } + } + } +} + +void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict, + int offset, int size) { + Guchar *idxPtr0, *idxPtr1, *ptr; + char eBuf[256]; + int key; + double x; + GBool isFP; + int i; + + privateDict->dictData = new GString(); + privateDict->subrsOffset = 0; + privateDict->defaultWidthX = 0; + privateDict->defaultWidthXFP = gFalse; + privateDict->nominalWidthX = 0; + privateDict->nominalWidthXFP = gFalse; + idxPtr0 = (Guchar *)file + offset; + idxPtr1 = idxPtr0 + size; + ptr = idxPtr0; + i = 0; + while (ptr < idxPtr1) { + if (*ptr <= 27 || *ptr == 31) { + key = *ptr++; + if (key == 0x0c) { + key = (key << 8) | *ptr++; + } + switch (key) { + case 0x0006: + getDeltaInt(eBuf, "BlueValues", op, i); + 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 = (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(&ptr, &isFP); + if (i < 48) { + op[i] = x; + fp[i++] = isFP; + } + } + } +} + +Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) { + Gushort *glyphNames; + Guchar *ptr; + 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)); + glyphNames[0] = 0; + ptr = (Guchar *)file + charset; + charsetFormat = *ptr++; + if (charsetFormat == 0) { + for (i = 1; i < nGlyphs; ++i) { + glyphNames[i] = getWord(ptr, 2); + ptr += 2; + } + } else if (charsetFormat == 1) { + i = 1; + while (i < nGlyphs) { + c = getWord(ptr, 2); + ptr += 2; + nLeft = *ptr++; + for (j = 0; j <= nLeft && i < nGlyphs; ++j) { + glyphNames[i++] = c++; + } + } + } else if (charsetFormat == 2) { + i = 1; + while (i < nGlyphs) { + c = getWord(ptr, 2); + ptr += 2; + nLeft = getWord(ptr, 2); + ptr += 2; + for (j = 0; j <= nLeft && i < nGlyphs; ++j) { + glyphNames[i++] = c++; + } + } + } + } + return glyphNames; +} + +void Type1CFontFile::eexecWrite(const char *s) { + const Guchar *p; + Guchar x; + + for (p = (const 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(const char *glyphName, const Guchar *s, int n) { + char eBuf[256]; + + cvtGlyph(s, n); + sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength()); + eexecWrite(eBuf); + eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength()); + eexecWrite(" ND\n"); + delete charBuf; +} + +void Type1CFontFile::cvtGlyph(const Guchar *s, int n) { + int nHints; + int x; + GBool first = gTrue; + double d, dx, dy; + GBool dFP; + Gushort r2; + Guchar byte; + int i, k; + + charBuf = new GString(); + charBuf->append((char)73); + charBuf->append((char)58); + charBuf->append((char)147); + charBuf->append((char)134); + + i = 0; + nOps = 0; + nHints = 0; + while (i < n) { + if (s[i] == 12) { + switch (s[i+1]) { + case 0: // dotsection (should be Type 1 only?) + // ignored + break; + case 34: // hflex + if (nOps != 7) { + error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); + } + eexecDumpNum(op[0], fp[0]); + eexecDumpNum(0, gFalse); + eexecDumpNum(op[1], fp[1]); + eexecDumpNum(op[2], fp[2]); + eexecDumpNum(op[3], fp[3]); + eexecDumpNum(0, gFalse); + eexecDumpOp1(8); + eexecDumpNum(op[4], fp[4]); + eexecDumpNum(0, gFalse); + eexecDumpNum(op[5], fp[5]); + eexecDumpNum(-op[2], fp[2]); + eexecDumpNum(op[6], fp[6]); + eexecDumpNum(0, gFalse); + eexecDumpOp1(8); + break; + case 35: // flex + if (nOps != 13) { + error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); + } + eexecDumpNum(op[0], fp[0]); + eexecDumpNum(op[1], fp[1]); + eexecDumpNum(op[2], fp[2]); + eexecDumpNum(op[3], fp[3]); + eexecDumpNum(op[4], fp[4]); + eexecDumpNum(op[5], fp[5]); + eexecDumpOp1(8); + eexecDumpNum(op[6], fp[6]); + eexecDumpNum(op[7], fp[7]); + eexecDumpNum(op[8], fp[8]); + eexecDumpNum(op[9], fp[9]); + eexecDumpNum(op[10], fp[10]); + eexecDumpNum(op[11], fp[11]); + eexecDumpOp1(8); + break; + case 36: // hflex1 + if (nOps != 9) { + error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); + } + eexecDumpNum(op[0], fp[0]); + eexecDumpNum(op[1], fp[1]); + eexecDumpNum(op[2], fp[2]); + eexecDumpNum(op[3], fp[3]); + eexecDumpNum(op[4], fp[4]); + eexecDumpNum(0, gFalse); + eexecDumpOp1(8); + eexecDumpNum(op[5], fp[5]); + eexecDumpNum(0, gFalse); + eexecDumpNum(op[6], fp[6]); + eexecDumpNum(op[7], fp[7]); + eexecDumpNum(op[8], fp[8]); + eexecDumpNum(-(op[1] + op[3] + op[7]), fp[1] | fp[3] | fp[7]); + eexecDumpOp1(8); + break; + case 37: // flex1 + if (nOps != 11) { + error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); + } + eexecDumpNum(op[0], fp[0]); + eexecDumpNum(op[1], fp[1]); + eexecDumpNum(op[2], fp[2]); + eexecDumpNum(op[3], fp[3]); + eexecDumpNum(op[4], fp[4]); + eexecDumpNum(op[5], fp[5]); + eexecDumpOp1(8); + eexecDumpNum(op[6], fp[6]); + eexecDumpNum(op[7], fp[7]); + eexecDumpNum(op[8], fp[8]); + eexecDumpNum(op[9], fp[9]); + dx = op[0] + op[2] + op[4] + op[6] + op[8]; + dy = op[1] + op[3] + op[5] + op[7] + op[9]; + if (fabs(dx) > fabs(dy)) { + eexecDumpNum(op[10], fp[10]); + eexecDumpNum(-dy, fp[1] | fp[3] | fp[5] | fp[7] | fp[9]); + } 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", s[i+1]); + break; + default: + error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]); + break; + } + i += 2; + nOps = 0; + } else if (s[i] == 19) { // hintmask + // ignored + if (first) { + cvtGlyphWidth(nOps == 1); + first = gFalse; + } + if (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 (s[i] == 20) { // cntrmask + // ignored + if (first) { + cvtGlyphWidth(nOps == 1); + first = 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 (s[i] == 28) { + x = (s[i+1] << 8) + s[i+2]; + if (x & 0x8000) { + x |= -1 << 15; + } + if (nOps < 48) { + fp[nOps] = gFalse; + op[nOps++] = x; + } + i += 3; + } else if (s[i] <= 31) { + switch (s[i]) { + case 4: // vmoveto + if (first) { + cvtGlyphWidth(nOps == 2); + first = gFalse; + } + if (nOps != 1) { + error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); + } + eexecDumpNum(op[0], fp[0]); + eexecDumpOp1(4); + break; + case 5: // rlineto + if (nOps < 2 || nOps % 2 != 0) { + error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); + } + for (k = 0; k < nOps; k += 2) { + eexecDumpNum(op[k], fp[k]); + eexecDumpNum(op[k+1], fp[k+1]); + eexecDumpOp1(5); + } + break; + case 6: // hlineto + if (nOps < 1) { + error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); + } + for (k = 0; k < nOps; ++k) { + eexecDumpNum(op[k], fp[k]); + eexecDumpOp1((k & 1) ? 7 : 6); + } + break; + case 7: // vlineto + if (nOps < 1) { + error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); + } + for (k = 0; k < nOps; ++k) { + eexecDumpNum(op[k], fp[k]); + eexecDumpOp1((k & 1) ? 6 : 7); + } + break; + case 8: // rrcurveto + if (nOps < 6 || nOps % 6 != 0) { + error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); + } + for (k = 0; k < nOps; k += 6) { + eexecDumpNum(op[k], fp[k]); + eexecDumpNum(op[k+1], fp[k+1]); + eexecDumpNum(op[k+2], fp[k+2]); + eexecDumpNum(op[k+3], fp[k+3]); + eexecDumpNum(op[k+4], fp[k+4]); + eexecDumpNum(op[k+5], fp[k+5]); + eexecDumpOp1(8); + } + break; + case 14: // endchar / seac + if (first) { + cvtGlyphWidth(nOps == 1 || nOps == 5); + first = gFalse; + } + if (nOps == 4) { + eexecDumpNum(0, 0); + eexecDumpNum(op[0], fp[0]); + eexecDumpNum(op[1], fp[1]); + eexecDumpNum(op[2], fp[2]); + eexecDumpNum(op[3], fp[3]); + eexecDumpOp2(6); + } else if (nOps == 0) { + eexecDumpOp1(14); + } else { + error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); + } + break; + case 21: // rmoveto + if (first) { + cvtGlyphWidth(nOps == 3); + first = 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 (first) { + cvtGlyphWidth(nOps == 2); + first = 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 (first) { + cvtGlyphWidth(nOps & 1); + first = 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 (first) { + cvtGlyphWidth(nOps & 1); + first = 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 18: // hstemhm + // ignored + if (first) { + cvtGlyphWidth(nOps & 1); + first = gFalse; + } + if (nOps & 1) { + error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); + } + nHints += nOps / 2; + break; + case 23: // vstemhm + // ignored + if (first) { + cvtGlyphWidth(nOps & 1); + first = gFalse; + } + if (nOps & 1) { + error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); + } + nHints += nOps / 2; + break; + case 10: // callsubr + case 11: // return + case 16: // blend + case 29: // callgsubr + error(-1, "Unimplemented Type 2 charstring op: %d", s[i]); + break; + default: + error(-1, "Illegal Type 2 charstring op: %d", s[i]); + break; + } + ++i; + nOps = 0; + } else if (s[i] <= 246) { + if (nOps < 48) { + fp[nOps] = gFalse; + op[nOps++] = (int)s[i] - 139; + } + ++i; + } else if (s[i] <= 250) { + if (nOps < 48) { + fp[nOps] = gFalse; + op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108; + } + i += 2; + } else if (s[i] <= 254) { + if (nOps < 48) { + fp[nOps] = gFalse; + op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108; + } + i += 2; + } else { + x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4]; + if (x & 0x80000000) + x |= -1 << 31; + if (nOps < 48) { + fp[nOps] = gTrue; + op[nOps++] = (double)x / 65536.0; + } + i += 5; + } + } + + // charstring encryption + r2 = 4330; + for (i = 0; i < charBuf->getLength(); ++i) { + byte = charBuf->getChar(i) ^ (r2 >> 8); + charBuf->setChar(i, byte); + r2 = (byte + r2) * 52845 + 22719; + } +} + +void 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(const 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, const char *key, const 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, const char *key, const 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(Guchar *indexPtr) { + return (int)getWord(indexPtr, 2); +} + +Guchar *Type1CFontFile::getIndexValPtr(Guchar *indexPtr, int i) { + int n, offSize; + Guchar *idxStartPtr; + + n = (int)getWord(indexPtr, 2); + offSize = indexPtr[2]; + idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1; + return idxStartPtr + getWord(indexPtr + 3 + i * offSize, offSize); +} + +Guchar *Type1CFontFile::getIndexEnd(Guchar *indexPtr) { + int n, offSize; + Guchar *idxStartPtr; + + n = (int)getWord(indexPtr, 2); + offSize = indexPtr[2]; + idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1; + return idxStartPtr + getWord(indexPtr + 3 + n * offSize, offSize); +} + +Guint Type1CFontFile::getWord(Guchar *ptr, int size) { + Guint x; + int i; + + x = 0; + for (i = 0; i < size; ++i) { + x = (x << 8) + *ptr++; + } + return x; +} + +double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) { + static char nybChars[16] = "0123456789.ee -"; + int b0, b, nyb0, nyb1; + double x; + char buf[65]; + int i; + + x = 0; + *isFP = gFalse; + b0 = (*ptr)[0]; + if (b0 < 28) { + x = 0; + } else if (b0 == 28) { + x = ((*ptr)[1] << 8) + (*ptr)[2]; + *ptr += 3; + } else if (b0 == 29) { + x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4]; + *ptr += 5; + } else if (b0 == 30) { + *ptr += 1; + i = 0; + do { + b = *(*ptr)++; + nyb0 = b >> 4; + nyb1 = b & 0x0f; + if (nyb0 == 0xf) { + break; + } + buf[i++] = nybChars[nyb0]; + if (i == 64) { + break; + } + if (nyb0 == 0xc) { + buf[i++] = '-'; + } + if (i == 64) { + break; + } + if (nyb1 == 0xf) { + break; + } + buf[i++] = nybChars[nyb1]; + if (i == 64) { + break; + } + if (nyb1 == 0xc) { + buf[i++] = '-'; + } + } while (i < 64); + buf[i] = '\0'; + x = atof(buf); + *isFP = gTrue; + } else if (b0 == 31) { + x = 0; + } else if (b0 < 247) { + x = b0 - 139; + *ptr += 1; + } else if (b0 < 251) { + x = ((b0 - 247) << 8) + (*ptr)[1] + 108; + *ptr += 2; + } else { + x = -((b0 - 251) << 8) - (*ptr)[1] - 108; + *ptr += 2; + } + return x; +} + +char *Type1CFontFile::getString(int sid, char *buf) { + Guchar *idxPtr0, *idxPtr1; + int n; + + if (sid < 391) { + strcpy(buf, type1CStdStrings[sid]); + } else { + sid -= 391; + idxPtr0 = getIndexValPtr(stringIdxPtr, sid); + idxPtr1 = getIndexValPtr(stringIdxPtr, sid + 1); + if ((n = idxPtr1 - idxPtr0) > 255) { + n = 255; + } + strncpy(buf, (char *)idxPtr0, n); + buf[n] = '\0'; + } + return buf; +} + +//------------------------------------------------------------------------ +// TrueTypeFontFile +//------------------------------------------------------------------------ + +// +// Terminology +// ----------- +// +// character code = number used as an element of a text string +// +// character name = glyph name = name for a particular glyph within a +// font +// +// glyph index = position (within some internal table in the font) +// where the instructions to draw a particular glyph are +// stored +// +// Type 1 fonts +// ------------ +// +// Type 1 fonts contain: +// +// Encoding: array of glyph names, maps char codes to glyph names +// +// Encoding[charCode] = charName +// +// CharStrings: dictionary of instructions, keyed by character names, +// maps character name to glyph data +// +// CharStrings[charName] = glyphData +// +// TrueType fonts +// -------------- +// +// TrueType fonts contain: +// +// 'cmap' table: mapping from character code to glyph index; there may +// be multiple cmaps in a TrueType font +// +// cmap[charCode] = glyphIdx +// +// 'post' table: mapping from glyph index to glyph name +// +// post[glyphIdx] = glyphName +// +// Type 42 fonts +// ------------- +// +// Type 42 fonts contain: +// +// Encoding: array of glyph names, maps char codes to glyph names +// +// Encoding[charCode] = charName +// +// CharStrings: dictionary of glyph indexes, keyed by character names, +// maps character name to glyph index +// +// CharStrings[charName] = glyphIdx +// + +struct TTFontTableHdr { + char tag[4]; + Guint checksum; + Guint offset; + Guint length; +}; + +struct T42Table { + const char *tag; // 4-byte tag + GBool required; // required by the TrueType spec? +}; + +// TrueType tables to be embedded in Type 42 fonts. +// NB: the table names must be in alphabetical order here. +#define nT42Tables 11 +static T42Table t42Tables[nT42Tables] = { + { "cvt ", gTrue }, + { "fpgm", gTrue }, + { "glyf", gTrue }, + { "head", gTrue }, + { "hhea", gTrue }, + { "hmtx", gTrue }, + { "loca", gTrue }, + { "maxp", gTrue }, + { "prep", gTrue }, + { "vhea", gFalse }, + { "vmtx", gFalse } +}; +#define t42HeadTable 3 +#define t42LocaTable 6 +#define t42GlyfTable 2 + +// Glyph names in some arbitrary standard that Apple uses for their +// TrueType fonts. +static const char *macGlyphNames[258] = { + ".notdef", + "null", + "CR", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quotesingle", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "grave", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "Adieresis", + "Aring", + "Ccedilla", + "Eacute", + "Ntilde", + "Odieresis", + "Udieresis", + "aacute", + "agrave", + "acircumflex", + "adieresis", + "atilde", + "aring", + "ccedilla", + "eacute", + "egrave", + "ecircumflex", + "edieresis", + "iacute", + "igrave", + "icircumflex", + "idieresis", + "ntilde", + "oacute", + "ograve", + "ocircumflex", + "odieresis", + "otilde", + "uacute", + "ugrave", + "ucircumflex", + "udieresis", + "dagger", + "degree", + "cent", + "sterling", + "section", + "bullet", + "paragraph", + "germandbls", + "registered", + "copyright", + "trademark", + "acute", + "dieresis", + "notequal", + "AE", + "Oslash", + "infinity", + "plusminus", + "lessequal", + "greaterequal", + "yen", + "mu1", + "partialdiff", + "summation", + "product", + "pi", + "integral", + "ordfeminine", + "ordmasculine", + "Ohm", + "ae", + "oslash", + "questiondown", + "exclamdown", + "logicalnot", + "radical", + "florin", + "approxequal", + "increment", + "guillemotleft", + "guillemotright", + "ellipsis", + "nbspace", + "Agrave", + "Atilde", + "Otilde", + "OE", + "oe", + "endash", + "emdash", + "quotedblleft", + "quotedblright", + "quoteleft", + "quoteright", + "divide", + "lozenge", + "ydieresis", + "Ydieresis", + "fraction", + "currency", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "daggerdbl", + "periodcentered", + "quotesinglbase", + "quotedblbase", + "perthousand", + "Acircumflex", + "Ecircumflex", + "Aacute", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Oacute", + "Ocircumflex", + "applelogo", + "Ograve", + "Uacute", + "Ucircumflex", + "Ugrave", + "dotlessi", + "circumflex", + "tilde", + "overscore", + "breve", + "dotaccent", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron", + "Lslash", + "lslash", + "Scaron", + "scaron", + "Zcaron", + "zcaron", + "brokenbar", + "Eth", + "eth", + "Yacute", + "yacute", + "Thorn", + "thorn", + "minus", + "multiply", + "onesuperior", + "twosuperior", + "threesuperior", + "onehalf", + "onequarter", + "threequarters", + "franc", + "Gbreve", + "gbreve", + "Idot", + "Scedilla", + "scedilla", + "Cacute", + "cacute", + "Ccaron", + "ccaron", + "dmacron" +}; + +enum T42FontIndexMode { + t42FontModeUnicode, + t42FontModeCharCode, + t42FontModeCharCodeOffset, + t42FontModeMacRoman +}; + +TrueTypeFontFile::TrueTypeFontFile(const char *fileA, int lenA) { + int pos, i, idx, n, length; + Guint size, startPos, endPos; + + file = fileA; + len = lenA; + + encoding = NULL; + + // read table directory + nTables = getUShort(4); + tableHdrs = (TTFontTableHdr *)gmalloc(nTables * sizeof(TTFontTableHdr)); + pos = 12; + for (i = 0; i < nTables; ++i) { + tableHdrs[i].tag[0] = getByte(pos+0); + tableHdrs[i].tag[1] = getByte(pos+1); + tableHdrs[i].tag[2] = getByte(pos+2); + tableHdrs[i].tag[3] = getByte(pos+3); + tableHdrs[i].checksum = getULong(pos+4); + tableHdrs[i].offset = getULong(pos+8); + tableHdrs[i].length = getULong(pos+12); + pos += 16; + } + + // check for tables that are required by both the TrueType spec + // and the Type 42 spec + if (seekTable("head") < 0 || + seekTable("hhea") < 0 || + seekTable("loca") < 0 || + seekTable("maxp") < 0 || + seekTable("glyf") < 0 || + seekTable("hmtx") < 0) { + error(-1, "TrueType font file is missing a required table"); + return; + } + + // some embedded TrueType fonts have an incorrect (too small) cmap + // table size + idx = seekTableIdx("cmap"); + if (idx >= 0) { + pos = tableHdrs[idx].offset; + n = getUShort(pos + 2); + size = (Guint)(4 + 8 * n); + for (i = 0; i < n; ++i) { + startPos = getULong(pos + 4 + 8*i + 4); + length = getUShort(pos + startPos + 2); + endPos = startPos + length; + if (endPos > size) { + size = endPos; + } + } + if ((mungedCmapSize = size > tableHdrs[idx].length)) { +#if 0 // don't bother printing this error message - it's too common + error(-1, "Bad cmap table size in TrueType font"); +#endif + tableHdrs[idx].length = size; + } + } else { + mungedCmapSize = gFalse; + } + + // read the 'head' table + pos = seekTable("head"); + bbox[0] = getShort(pos + 36); + bbox[1] = getShort(pos + 38); + bbox[2] = getShort(pos + 40); + bbox[3] = getShort(pos + 42); + locaFmt = getShort(pos + 50); + + // read the 'maxp' table + pos = seekTable("maxp"); + nGlyphs = getUShort(pos + 4); +} + +TrueTypeFontFile::~TrueTypeFontFile() { + int i; + + if (encoding) { + for (i = 0; i < 256; ++i) { + gfree(encoding[i]); + } + gfree(encoding); + } + gfree(tableHdrs); +} + +const char *TrueTypeFontFile::getName() { + return NULL; +} + +char **TrueTypeFontFile::getEncoding() { + int cmap[256]; + int nCmaps, cmapPlatform, cmapEncoding, cmapFmt; + int cmapLen, cmapOffset, cmapFirst; + int segCnt, segStart, segEnd, segDelta, segOffset; + int pos, i, j, k; + Guint fmt; + GString *s; + int stringIdx, stringPos, n; + + if (encoding) { + return encoding; + } + + //----- construct the (char code) -> (glyph idx) mapping + + // map everything to the missing glyph + for (i = 0; i < 256; ++i) { + cmap[i] = 0; + } + + // look for the 'cmap' table + if ((pos = seekTable("cmap")) >= 0) { + nCmaps = getUShort(pos+2); + + // if the font has a Windows-symbol cmap, use it; + // otherwise, use the first cmap in the table + for (i = 0; i < nCmaps; ++i) { + cmapPlatform = getUShort(pos + 4 + 8*i); + cmapEncoding = getUShort(pos + 4 + 8*i + 2); + if (cmapPlatform == 3 && cmapEncoding == 0) { + break; + } + } + if (i >= nCmaps) { + i = 0; + cmapPlatform = getUShort(pos + 4); + cmapEncoding = getUShort(pos + 4 + 2); + } + pos += getULong(pos + 4 + 8*i + 4); + + // read the cmap + cmapFmt = getUShort(pos); + switch (cmapFmt) { + case 0: // byte encoding table (Apple standard) + cmapLen = getUShort(pos + 2); + for (i = 0; i < cmapLen && i < 256; ++i) { + cmap[i] = getByte(pos + 6 + i); + } + break; + case 4: // segment mapping to delta values (Microsoft standard) + if (cmapPlatform == 3 && cmapEncoding == 0) { + // Windows-symbol uses char codes 0xf000 - 0xf0ff + cmapOffset = 0xf000; + } else { + cmapOffset = 0; + } + segCnt = getUShort(pos + 6) / 2; + for (i = 0; i < segCnt; ++i) { + segEnd = getUShort(pos + 14 + 2*i); + segStart = getUShort(pos + 16 + 2*segCnt + 2*i); + segDelta = getUShort(pos + 16 + 4*segCnt + 2*i); + segOffset = getUShort(pos + 16 + 6*segCnt + 2*i); + if (segStart - cmapOffset <= 0xff && + segEnd - cmapOffset >= 0) { + for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset; + j <= segEnd && j - cmapOffset <= 0xff; + ++j) { + if (segOffset == 0) { + k = (j + segDelta) & 0xffff; + } else { + k = getUShort(pos + 16 + 6*segCnt + 2*i + + segOffset + 2 * (j - segStart)); + if (k != 0) { + k = (k + segDelta) & 0xffff; + } + } + cmap[j - cmapOffset] = k; + } + } + } + break; + case 6: // trimmed table mapping + cmapFirst = getUShort(pos + 6); + cmapLen = getUShort(pos + 8); + for (i = cmapFirst; i < 256 && i < cmapFirst + cmapLen; ++i) { + cmap[i] = getUShort(pos + 10 + 2*i); + } + break; + default: + error(-1, "Unimplemented cmap format (%d) in TrueType font file", + cmapFmt); + break; + } + } + + //----- construct the (glyph idx) -> (glyph name) mapping + //----- and compute the (char code) -> (glyph name) mapping + + encoding = (char **)gmalloc(256 * sizeof(char *)); + for (i = 0; i < 256; ++i) { + encoding[i] = NULL; + } + + if ((pos = seekTable("post")) >= 0) { + fmt = getULong(pos); + + // Apple font + if (fmt == 0x00010000) { + for (i = 0; i < 256; ++i) { + j = (cmap[i] < 258) ? cmap[i] : 0; + encoding[i] = copyString(macGlyphNames[j]); + } + + // Microsoft font + } else if (fmt == 0x00020000) { + stringIdx = 0; + stringPos = pos + 34 + 2*nGlyphs; + for (i = 0; i < 256; ++i) { + if (cmap[i] < nGlyphs) { + j = getUShort(pos + 34 + 2 * cmap[i]); + if (j < 258) { + encoding[i] = copyString(macGlyphNames[j]); + } else { + j -= 258; + if (j != stringIdx) { + for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs; + stringIdx < j; + ++stringIdx, stringPos += 1 + getByte(stringPos)) ; + } + n = getByte(stringPos); + s = new GString(file + stringPos + 1, n); + encoding[i] = copyString(s->getCString()); + delete s; + ++stringIdx; + stringPos += 1 + n; + } + } else { + encoding[i] = copyString(macGlyphNames[0]); + } + } + + // Apple subset + } else if (fmt == 0x000280000) { + for (i = 0; i < 256; ++i) { + if (cmap[i] < nGlyphs) { + j = i + getChar(pos + 32 + cmap[i]); + } else { + j = 0; + } + encoding[i] = copyString(macGlyphNames[j]); + } + + // Ugh, just assume the Apple glyph set + } else { + for (i = 0; i < 256; ++i) { + j = (cmap[i] < 258) ? cmap[i] : 0; + encoding[i] = copyString(macGlyphNames[j]); + } + } + + // no "post" table: assume the Apple glyph set + } else { + for (i = 0; i < 256; ++i) { + j = (cmap[i] < 258) ? cmap[i] : 0; + encoding[i] = copyString(macGlyphNames[j]); + } + } + + return encoding; +} + +void TrueTypeFontFile::convertToType42(const char *name, const char **encodingA, + CharCodeToUnicode *toUnicode, + GBool pdfFontHasEncoding, + FontFileOutputFunc outputFunc, + void *outputStream) { + char buf[512]; + + // write the header + sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0)); + (*outputFunc)(outputStream, buf, strlen(buf)); + + // begin the font dictionary + (*outputFunc)(outputStream, "10 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, name, strlen(name)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + sprintf(buf, "/FontBBox [%d %d %d %d] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + + // write the guts of the dictionary + cvtEncoding(encodingA, pdfFontHasEncoding, outputFunc, outputStream); + cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, + 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(const char *name, const 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(const char *name, const 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(const char *tag) { + int i; + + for (i = 0; i < nTables; ++i) { + if (!strncmp(tableHdrs[i].tag, tag, 4)) { + return tableHdrs[i].offset; + } + } + return -1; +} + +int TrueTypeFontFile::seekTableIdx(const char *tag) { + int i; + + for (i = 0; i < nTables; ++i) { + if (!strncmp(tableHdrs[i].tag, tag, 4)) { + return i; + } + } + return -1; +} + +void TrueTypeFontFile::cvtEncoding(const char **encodingA, GBool pdfFontHasEncoding, + FontFileOutputFunc outputFunc, + void *outputStream) { + const 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(const char **encodingA, + CharCodeToUnicode *toUnicode, + GBool pdfFontHasEncoding, + FontFileOutputFunc outputFunc, + void *outputStream) { + int unicodeCmap, macRomanCmap, msSymbolCmap; + int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapOffset; + T42FontIndexMode mode; + const char *name; + char buf[64], buf2[16]; + Unicode u; + int pos, i, j, k; + + // always define '.notdef' + (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32); + (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); + + // if there's no 'cmap' table, punt + if ((pos = seekTable("cmap")) < 0) { + goto err; + } + + // To match up with the Adobe-defined behaviour, we choose a cmap + // like this: + // 1. If the PDF font has an encoding: + // 1a. If the TrueType font has a Microsoft Unicode cmap, use it, + // and use the Unicode indexes, not the char codes. + // 1b. If the TrueType font has a Macintosh Roman cmap, use it, + // and reverse map the char names through MacRomanEncoding to + // get char codes. + // 2. If the PDF font does not have an encoding: + // 2a. If the TrueType font has a Macintosh Roman cmap, use it, + // and use char codes directly. + // 2b. If the TrueType font has a Microsoft Symbol cmap, use it, + // and use (0xf000 + char code). + // 3. If none of these rules apply, use the first cmap and hope for + // the best (this shouldn't happen). + nCmaps = getUShort(pos+2); + unicodeCmap = macRomanCmap = msSymbolCmap = -1; + cmapOffset = 0; + for (i = 0; i < nCmaps; ++i) { + cmapPlatform = getUShort(pos + 4 + 8*i); + cmapEncoding = getUShort(pos + 4 + 8*i + 2); + if (cmapPlatform == 3 && cmapEncoding == 1) { + unicodeCmap = i; + } else if (cmapPlatform == 1 && cmapEncoding == 0) { + macRomanCmap = i; + } else if (cmapPlatform == 3 && cmapEncoding == 0) { + msSymbolCmap = i; + } + } + i = 0; + mode = t42FontModeCharCode; + if (pdfFontHasEncoding) { + if (unicodeCmap >= 0) { + i = unicodeCmap; + mode = t42FontModeUnicode; + } else if (macRomanCmap >= 0) { + i = macRomanCmap; + mode = t42FontModeMacRoman; + } + } else { + if (macRomanCmap >= 0) { + i = macRomanCmap; + mode = t42FontModeCharCode; + } else if (msSymbolCmap >= 0) { + i = msSymbolCmap; + mode = t42FontModeCharCodeOffset; + cmapOffset = 0xf000; + } + } + cmapPlatform = getUShort(pos + 4 + 8*i); + cmapEncoding = getUShort(pos + 4 + 8*i + 2); + pos += getULong(pos + 4 + 8*i + 4); + cmapFmt = getUShort(pos); + if (cmapFmt != 0 && cmapFmt != 4 && cmapFmt != 6) { + error(-1, "Unimplemented cmap format (%d) in TrueType font file", + cmapFmt); + goto err; + } + + // map char name to glyph index: + // 1. use encoding to map name to char code + // 2. use cmap to map char code to glyph index + j = 0; // make gcc happy + for (i = 0; i < 256; ++i) { + if (pdfFontHasEncoding) { + name = encodingA[i]; + } else { + sprintf(buf2, "c%02x", i); + name = buf2; + } + if (name && strcmp(name, ".notdef")) { + switch (mode) { + case t42FontModeUnicode: + toUnicode->mapToUnicode((CharCode)i, &u, 1); + j = (int)u; + break; + case t42FontModeCharCode: + j = i; + break; + case t42FontModeCharCodeOffset: + j = cmapOffset + i; + break; + case t42FontModeMacRoman: + j = globalParams->getMacRomanCharCode(name); + break; + } + // note: Distiller (maybe Adobe's PS interpreter in general) + // doesn't like TrueType fonts that have CharStrings entries + // which point to nonexistent glyphs, hence the (k < nGlyphs) + // test + if ((k = getCmapEntry(cmapFmt, pos, j)) > 0 && + k < nGlyphs) { + (*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 (segOffset == 0) { + i = (code + segDelta) & 0xffff; + } else { + i = getUShort(pos + 16 + 6*segCnt + 2*b + + segOffset + 2 * (code - segStart)); + if (i != 0) { + i = (i + segDelta) & 0xffff; + } + } + return i; + + case 6: // trimmed table mapping + cmapFirst = getUShort(pos + 6); + cmapLen = getUShort(pos + 8); + if (code < cmapFirst || code >= cmapFirst + cmapLen) { + return 0; + } + return getUShort(pos + 10 + 2*(code - cmapFirst)); + + default: + // shouldn't happen - this is checked earlier + break; + } + return 0; +} + +void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc, + void *outputStream, GString *name) { + TTFontTableHdr newTableHdrs[nT42Tables]; + char tableDir[12 + nT42Tables*16]; + char headTable[54]; + int *origLocaTable; + char *locaTable; + int nNewTables; + Guint checksum; + int pos, glyfPos, length, glyphLength, pad; + int i, j, k; + + // construct the 'head' table, zero out the font checksum + memcpy(headTable, file + seekTable("head"), 54); + headTable[8] = headTable[9] = headTable[10] = headTable[11] = (char)0; + + // read the original 'loca' table and construct the new one + // (pad each glyph out to a multiple of 4 bytes) + origLocaTable = (int *)gmalloc((nGlyphs + 1) * sizeof(int)); + pos = seekTable("loca"); + for (i = 0; i <= nGlyphs; ++i) { + if (locaFmt) { + origLocaTable[i] = getULong(pos + 4*i); + } else { + origLocaTable[i] = 2 * getUShort(pos + 2*i); + } + } + locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2)); + if (locaFmt) { + locaTable[0] = locaTable[1] = locaTable[2] = locaTable[3] = 0; + } else { + locaTable[0] = locaTable[1] = 0; + } + pos = 0; + for (i = 1; i <= nGlyphs; ++i) { + length = origLocaTable[i] - origLocaTable[i-1]; + if (length & 3) { + length += 4 - (length & 3); + } + pos += length; + if (locaFmt) { + locaTable[4*i ] = (char)(pos >> 24); + locaTable[4*i+1] = (char)(pos >> 16); + locaTable[4*i+2] = (char)(pos >> 8); + locaTable[4*i+3] = (char) pos; + } else { + locaTable[2*i ] = (char)(pos >> 9); + locaTable[2*i+1] = (char)(pos >> 1); + } + } + + // count the number of tables + nNewTables = 0; + for (i = 0; i < nT42Tables; ++i) { + if (t42Tables[i].required || + seekTable(t42Tables[i].tag) >= 0) { + ++nNewTables; + } + } + + // construct the new table headers, including table checksums + // (pad each table out to a multiple of 4 bytes) + pos = 12 + nNewTables*16; + k = 0; + for (i = 0; i < nT42Tables; ++i) { + length = -1; + checksum = 0; // make gcc happy + if (i == t42HeadTable) { + length = 54; + checksum = computeTableChecksum(headTable, 54); + } else if (i == t42LocaTable) { + length = (nGlyphs + 1) * (locaFmt ? 4 : 2); + checksum = computeTableChecksum(locaTable, length); + } else if (i == t42GlyfTable) { + length = 0; + checksum = 0; + glyfPos = seekTable("glyf"); + for (j = 0; j < nGlyphs; ++j) { + glyphLength = origLocaTable[j+1] - origLocaTable[j]; + pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0; + length += glyphLength + pad; + checksum += computeTableChecksum(file + glyfPos + origLocaTable[j], + glyphLength); + } + } else { + if ((j = seekTableIdx(t42Tables[i].tag)) >= 0) { + length = tableHdrs[j].length; + checksum = computeTableChecksum(file + tableHdrs[j].offset, length); + } else if (t42Tables[i].required) { + error(-1, "Embedded TrueType font is missing a required table ('%s')", + t42Tables[i].tag); + length = 0; + checksum = 0; + } + } + if (length >= 0) { + strncpy(newTableHdrs[k].tag, t42Tables[i].tag, 4); + newTableHdrs[k].checksum = checksum; + newTableHdrs[k].offset = pos; + newTableHdrs[k].length = length; + pad = (length & 3) ? 4 - (length & 3) : 0; + pos += length + pad; + ++k; + } + } + + // construct the table directory + tableDir[0] = 0x00; // sfnt version + tableDir[1] = 0x01; + tableDir[2] = 0x00; + tableDir[3] = 0x00; + tableDir[4] = 0; // numTables + tableDir[5] = nNewTables; + tableDir[6] = 0; // searchRange + tableDir[7] = (char)128; + tableDir[8] = 0; // entrySelector + tableDir[9] = 3; + tableDir[10] = 0; // rangeShift + tableDir[11] = (char)(16 * nNewTables - 128); + pos = 12; + for (i = 0; i < nNewTables; ++i) { + tableDir[pos ] = newTableHdrs[i].tag[0]; + tableDir[pos+ 1] = newTableHdrs[i].tag[1]; + tableDir[pos+ 2] = newTableHdrs[i].tag[2]; + tableDir[pos+ 3] = newTableHdrs[i].tag[3]; + tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24); + tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16); + tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >> 8); + tableDir[pos+ 7] = (char) newTableHdrs[i].checksum; + tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24); + tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16); + tableDir[pos+10] = (char)(newTableHdrs[i].offset >> 8); + tableDir[pos+11] = (char) newTableHdrs[i].offset; + tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24); + tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16); + tableDir[pos+14] = (char)(newTableHdrs[i].length >> 8); + tableDir[pos+15] = (char) newTableHdrs[i].length; + pos += 16; + } + + // compute the font checksum and store it in the head table + checksum = computeTableChecksum(tableDir, 12 + nNewTables*16); + for (i = 0; i < nNewTables; ++i) { + checksum += newTableHdrs[i].checksum; + } + checksum = 0xb1b0afba - checksum; // because the TrueType spec says so + headTable[ 8] = (char)(checksum >> 24); + headTable[ 9] = (char)(checksum >> 16); + headTable[10] = (char)(checksum >> 8); + headTable[11] = (char) checksum; + + // start the sfnts array + if (name) { + (*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+1] - origLocaTable[j]; + if (length > 0) { + dumpString(file + glyfPos + origLocaTable[j], 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) { + 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(const 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(const char *data, int length) { + Guint checksum, word; + int i; + + checksum = 0; + for (i = 0; i+3 < length; i += 4) { + word = ((data[i ] & 0xff) << 24) + + ((data[i+1] & 0xff) << 16) + + ((data[i+2] & 0xff) << 8) + + (data[i+3] & 0xff); + checksum += word; + } + if (length & 3) { + word = 0; + i = length & ~3; + switch (length & 3) { + case 3: + word |= (data[i+2] & 0xff) << 8; + case 2: + word |= (data[i+1] & 0xff) << 16; + case 1: + word |= (data[i ] & 0xff) << 24; + break; + } + checksum += word; + } + return checksum; +} + +void TrueTypeFontFile::writeTTF(FILE *out) { + static char cmapTab[20] = { + 0, 0, // table version number + 0, 1, // number of encoding tables + 0, 1, // platform ID + 0, 0, // encoding ID + 0, 0, 0, 12, // offset of subtable + 0, 0, // subtable format + 0, 1, // subtable length + 0, 1, // subtable version + 0, // map char 0 -> glyph 0 + 0 // pad to multiple of four bytes + }; + static char nameTab[8] = { + 0, 0, // format + 0, 0, // number of name records + 0, 6, // offset to start of string storage + 0, 0 // pad to multiple of four bytes + }; + static char postTab[32] = { + 0, 1, 0, 0, // format + 0, 0, 0, 0, // italic angle + 0, 0, // underline position + 0, 0, // underline thickness + 0, 0, 0, 0, // fixed pitch + 0, 0, 0, 0, // min Type 42 memory + 0, 0, 0, 0, // max Type 42 memory + 0, 0, 0, 0, // min Type 1 memory + 0, 0, 0, 0 // max Type 1 memory + }; + GBool haveCmap, haveName, havePost; + GBool dirCmap, dirName, dirPost; + int nNewTables, nAllTables, pad; + char *tableDir; + Guint t, pos; + int i, j; + + // check for missing tables + haveCmap = seekTable("cmap") >= 0; + haveName = seekTable("name") >= 0; + havePost = seekTable("post") >= 0; + nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1); + if (!nNewTables && !mungedCmapSize) { + // none are missing - write the TTF file as is + fwrite(file, 1, len, out); + return; + } + + // construct the new table directory + nAllTables = nTables + nNewTables; + tableDir = (char *)gmalloc(12 + nAllTables * 16); + memcpy(tableDir, file, 12 + nTables * 16); + tableDir[4] = (char)((nAllTables >> 8) & 0xff); + tableDir[5] = (char)(nAllTables & 0xff); + for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ; + t = 1 << (4 + i); + tableDir[6] = (char)((t >> 8) & 0xff); + tableDir[7] = (char)(t & 0xff); + tableDir[8] = (char)((i >> 8) & 0xff); + tableDir[9] = (char)(i & 0xff); + t = nAllTables * 16 - t; + tableDir[10] = (char)((t >> 8) & 0xff); + tableDir[11] = (char)(t & 0xff); + dirCmap = haveCmap; + dirName = haveName; + dirPost = havePost; + j = 0; + pad = (len & 3) ? 4 - (len & 3) : 0; + pos = len + pad + 16 * nNewTables; + for (i = 0; i < nTables; ++i) { + if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) { + tableDir[12 + 16*j ] = 'c'; + tableDir[12 + 16*j + 1] = 'm'; + tableDir[12 + 16*j + 2] = 'a'; + tableDir[12 + 16*j + 3] = 'p'; + tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum + tableDir[12 + 16*j + 5] = (char)0; + tableDir[12 + 16*j + 6] = (char)0; + tableDir[12 + 16*j + 7] = (char)0; + tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); + tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); + tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); + tableDir[12 + 16*j + 11] = (char)( pos & 0xff); + tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff); + tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff); + tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff); + tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff); + pos += sizeof(cmapTab); + ++j; + dirCmap = gTrue; + } + if (!dirName && strncmp(tableHdrs[i].tag, "name", 4) > 0) { + tableDir[12 + 16*j ] = 'n'; + tableDir[12 + 16*j + 1] = 'a'; + tableDir[12 + 16*j + 2] = 'm'; + tableDir[12 + 16*j + 3] = 'e'; + tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum + tableDir[12 + 16*j + 5] = (char)0; + tableDir[12 + 16*j + 6] = (char)0; + tableDir[12 + 16*j + 7] = (char)0; + tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); + tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); + tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); + tableDir[12 + 16*j + 11] = (char)( pos & 0xff); + tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff); + tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff); + tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff); + tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff); + pos += sizeof(nameTab); + ++j; + dirName = gTrue; + } + if (!dirName && strncmp(tableHdrs[i].tag, "post", 4) > 0) { + tableDir[12 + 16*j ] = 'p'; + tableDir[12 + 16*j + 1] = 'o'; + tableDir[12 + 16*j + 2] = 's'; + tableDir[12 + 16*j + 3] = 't'; + tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum + tableDir[12 + 16*j + 5] = (char)0; + tableDir[12 + 16*j + 6] = (char)0; + tableDir[12 + 16*j + 7] = (char)0; + tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); + tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); + tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); + tableDir[12 + 16*j + 11] = (char)( pos & 0xff); + tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff); + tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff); + tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff); + tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff); + pos += sizeof(postTab); + ++j; + dirPost = gTrue; + } + tableDir[12 + 16*j ] = tableHdrs[i].tag[0]; + tableDir[12 + 16*j + 1] = tableHdrs[i].tag[1]; + tableDir[12 + 16*j + 2] = tableHdrs[i].tag[2]; + tableDir[12 + 16*j + 3] = tableHdrs[i].tag[3]; + tableDir[12 + 16*j + 4] = (char)((tableHdrs[i].checksum >> 24) & 0xff); + tableDir[12 + 16*j + 5] = (char)((tableHdrs[i].checksum >> 16) & 0xff); + tableDir[12 + 16*j + 6] = (char)((tableHdrs[i].checksum >> 8) & 0xff); + tableDir[12 + 16*j + 7] = (char)( tableHdrs[i].checksum & 0xff); + t = tableHdrs[i].offset + nNewTables * 16; + tableDir[12 + 16*j + 8] = (char)((t >> 24) & 0xff); + tableDir[12 + 16*j + 9] = (char)((t >> 16) & 0xff); + tableDir[12 + 16*j + 10] = (char)((t >> 8) & 0xff); + tableDir[12 + 16*j + 11] = (char)( t & 0xff); + tableDir[12 + 16*j + 12] = (char)((tableHdrs[i].length >> 24) & 0xff); + tableDir[12 + 16*j + 13] = (char)((tableHdrs[i].length >> 16) & 0xff); + tableDir[12 + 16*j + 14] = (char)((tableHdrs[i].length >> 8) & 0xff); + tableDir[12 + 16*j + 15] = (char)( tableHdrs[i].length & 0xff); + ++j; + } + if (!dirCmap) { + tableDir[12 + 16*j ] = 'c'; + tableDir[12 + 16*j + 1] = 'm'; + tableDir[12 + 16*j + 2] = 'a'; + tableDir[12 + 16*j + 3] = 'p'; + tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum + tableDir[12 + 16*j + 5] = (char)0; + tableDir[12 + 16*j + 6] = (char)0; + tableDir[12 + 16*j + 7] = (char)0; + tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); + tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); + tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); + tableDir[12 + 16*j + 11] = (char)( pos & 0xff); + tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff); + tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff); + tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff); + tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff); + pos += sizeof(cmapTab); + ++j; + dirCmap = gTrue; + } + if (!dirName) { + tableDir[12 + 16*j ] = 'n'; + tableDir[12 + 16*j + 1] = 'a'; + tableDir[12 + 16*j + 2] = 'm'; + tableDir[12 + 16*j + 3] = 'e'; + tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum + tableDir[12 + 16*j + 5] = (char)0; + tableDir[12 + 16*j + 6] = (char)0; + tableDir[12 + 16*j + 7] = (char)0; + tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); + tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); + tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); + tableDir[12 + 16*j + 11] = (char)( pos & 0xff); + tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff); + tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff); + tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff); + tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff); + pos += sizeof(nameTab); + ++j; + dirName = gTrue; + } + if (!dirPost) { + tableDir[12 + 16*j ] = 'p'; + tableDir[12 + 16*j + 1] = 'o'; + tableDir[12 + 16*j + 2] = 's'; + tableDir[12 + 16*j + 3] = 't'; + tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum + tableDir[12 + 16*j + 5] = (char)0; + tableDir[12 + 16*j + 6] = (char)0; + tableDir[12 + 16*j + 7] = (char)0; + tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); + tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); + tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); + tableDir[12 + 16*j + 11] = (char)( pos & 0xff); + tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff); + tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff); + tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff); + tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff); + pos += sizeof(postTab); + ++j; + dirPost = gTrue; + } + + // write the table directory + fwrite(tableDir, 1, 12 + 16 * nAllTables, out); + + // write the original tables + fwrite(file + 12 + 16*nTables, 1, len - (12 + 16*nTables), out); + + // write the new tables + for (i = 0; i < pad; ++i) { + fputc((char)0, out); + } + if (!haveCmap) { + fwrite(cmapTab, 1, sizeof(cmapTab), out); + } + if (!haveName) { + fwrite(nameTab, 1, sizeof(nameTab), out); + } + if (!havePost) { + fwrite(postTab, 1, sizeof(postTab), out); + } + + gfree(tableDir); +} |