mirror of
https://invent.kde.org/graphics/okular
synced 2024-10-03 06:34:13 +00:00
42c3c82014
svn path=/trunk/kdegraphics/kpdf/; revision=174591
3682 lines
94 KiB
C++
3682 lines
94 KiB
C++
//========================================================================
|
|
//
|
|
// FontFile.cc
|
|
//
|
|
// Copyright 1999-2002 Glyph & Cog, LLC
|
|
//
|
|
//========================================================================
|
|
|
|
#ifdef __GNUC__
|
|
#pragma implementation
|
|
#endif
|
|
|
|
#include <aconf.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.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 char *nextLine(char *line, char *end) {
|
|
while (line < end && *line != '\n' && *line != '\r')
|
|
++line;
|
|
while (line < end && *line == '\n' || *line == '\r')
|
|
++line;
|
|
return line;
|
|
}
|
|
|
|
static char hexChars[17] = "0123456789ABCDEF";
|
|
|
|
//------------------------------------------------------------------------
|
|
// FontFile
|
|
//------------------------------------------------------------------------
|
|
|
|
FontFile::FontFile() {
|
|
}
|
|
|
|
FontFile::~FontFile() {
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Type1FontFile
|
|
//------------------------------------------------------------------------
|
|
|
|
Type1FontFile::Type1FontFile(char *file, int len) {
|
|
char *line, *line1, *p, *p2;
|
|
GBool haveEncoding;
|
|
char buf[256];
|
|
char c;
|
|
int n, code, i, j;
|
|
|
|
name = NULL;
|
|
encoding = (char **)gmalloc(256 * sizeof(char *));
|
|
for (i = 0; i < 256; ++i) {
|
|
encoding[i] = NULL;
|
|
}
|
|
haveEncoding = gFalse;
|
|
|
|
for (i = 1, line = file;
|
|
i <= 100 && line < file + len && !haveEncoding;
|
|
++i) {
|
|
|
|
// get font name
|
|
if (!strncmp(line, "/FontName", 9)) {
|
|
strncpy(buf, line, 255);
|
|
buf[255] = '\0';
|
|
if ((p = strchr(buf+9, '/')) &&
|
|
(p = strtok(p+1, " \t\n\r"))) {
|
|
name = copyString(p);
|
|
}
|
|
line = nextLine(line, file + len);
|
|
|
|
// get encoding
|
|
} else if (!strncmp(line, "/Encoding StandardEncoding def", 30)) {
|
|
for (j = 0; j < 256; ++j) {
|
|
if (standardEncoding[j]) {
|
|
encoding[j] = copyString(standardEncoding[j]);
|
|
}
|
|
}
|
|
haveEncoding = gTrue;
|
|
} else if (!strncmp(line, "/Encoding 256 array", 19)) {
|
|
for (j = 0; j < 300; ++j) {
|
|
line1 = nextLine(line, file + len);
|
|
if ((n = line1 - line) > 255) {
|
|
n = 255;
|
|
}
|
|
strncpy(buf, line, n);
|
|
buf[n] = '\0';
|
|
for (p = buf; *p == ' ' || *p == '\t'; ++p) ;
|
|
if (!strncmp(p, "dup", 3)) {
|
|
for (p += 3; *p == ' ' || *p == '\t'; ++p) ;
|
|
for (p2 = p; *p2 >= '0' && *p2 <= '9'; ++p2) ;
|
|
if (*p2) {
|
|
c = *p2;
|
|
*p2 = '\0';
|
|
if ((code = atoi(p)) < 256) {
|
|
*p2 = c;
|
|
for (p = p2; *p == ' ' || *p == '\t'; ++p) ;
|
|
if (*p == '/') {
|
|
++p;
|
|
for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ;
|
|
*p2 = '\0';
|
|
encoding[code] = copyString(p);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (strtok(buf, " \t") &&
|
|
(p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) {
|
|
break;
|
|
}
|
|
}
|
|
line = line1;
|
|
}
|
|
//~ check for getinterval/putinterval junk
|
|
haveEncoding = gTrue;
|
|
|
|
} else {
|
|
line = nextLine(line, file + len);
|
|
}
|
|
}
|
|
}
|
|
|
|
Type1FontFile::~Type1FontFile() {
|
|
int i;
|
|
|
|
if (name) {
|
|
gfree(name);
|
|
}
|
|
for (i = 0; i < 256; ++i) {
|
|
gfree(encoding[i]);
|
|
}
|
|
gfree(encoding);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Type1CFontFile
|
|
//------------------------------------------------------------------------
|
|
|
|
struct Type1CTopDict {
|
|
int version;
|
|
int notice;
|
|
int copyright;
|
|
int fullName;
|
|
int familyName;
|
|
int weight;
|
|
int isFixedPitch;
|
|
double italicAngle;
|
|
double underlinePosition;
|
|
double underlineThickness;
|
|
int paintType;
|
|
int charstringType;
|
|
double fontMatrix[6];
|
|
int uniqueID;
|
|
double fontBBox[4];
|
|
double strokeWidth;
|
|
int charset;
|
|
int encoding;
|
|
int charStrings;
|
|
int privateSize;
|
|
int privateOffset;
|
|
|
|
//----- CIDFont entries
|
|
int registry;
|
|
int ordering;
|
|
int supplement;
|
|
int fdArrayOffset;
|
|
int fdSelectOffset;
|
|
};
|
|
|
|
struct Type1CPrivateDict {
|
|
GString *dictData;
|
|
int subrsOffset;
|
|
double defaultWidthX;
|
|
GBool defaultWidthXFP;
|
|
double nominalWidthX;
|
|
GBool nominalWidthXFP;
|
|
};
|
|
|
|
Type1CFontFile::Type1CFontFile(char *fileA, int lenA) {
|
|
Guchar *nameIdxPtr, *idxPtr0, *idxPtr1;
|
|
|
|
file = fileA;
|
|
len = lenA;
|
|
name = NULL;
|
|
encoding = NULL;
|
|
|
|
// some tools embed Type 1C fonts with an extra whitespace char at
|
|
// the beginning
|
|
if (file[0] != '\x01') {
|
|
++file;
|
|
}
|
|
|
|
// read header
|
|
topOffSize = file[3] & 0xff;
|
|
|
|
// read name index (first font only)
|
|
nameIdxPtr = (Guchar *)file + (file[2] & 0xff);
|
|
idxPtr0 = getIndexValPtr(nameIdxPtr, 0);
|
|
idxPtr1 = getIndexValPtr(nameIdxPtr, 1);
|
|
name = new GString((char *)idxPtr0, idxPtr1 - idxPtr0);
|
|
|
|
topDictIdxPtr = getIndexEnd(nameIdxPtr);
|
|
stringIdxPtr = getIndexEnd(topDictIdxPtr);
|
|
gsubrIdxPtr = getIndexEnd(stringIdxPtr);
|
|
}
|
|
|
|
Type1CFontFile::~Type1CFontFile() {
|
|
int i;
|
|
|
|
delete name;
|
|
if (encoding) {
|
|
for (i = 0; i < 256; ++i) {
|
|
gfree(encoding[i]);
|
|
}
|
|
gfree(encoding);
|
|
}
|
|
}
|
|
|
|
char *Type1CFontFile::getName() {
|
|
return name->getCString();
|
|
}
|
|
|
|
char **Type1CFontFile::getEncoding() {
|
|
if (!encoding) {
|
|
readNameAndEncoding();
|
|
}
|
|
return encoding;
|
|
}
|
|
|
|
void Type1CFontFile::readNameAndEncoding() {
|
|
char buf[256];
|
|
Guchar *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(FILE *outA) {
|
|
Type1CTopDict dict;
|
|
Type1CPrivateDict privateDict;
|
|
char buf[256], 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;
|
|
|
|
out = outA;
|
|
|
|
// read top dict (first font only)
|
|
readTopDict(&dict);
|
|
|
|
// get global subrs
|
|
//~ ... global subrs are unimplemented
|
|
|
|
// write header and font dictionary, up to encoding
|
|
fprintf(out, "%%!FontType1-1.0: %s", name->getCString());
|
|
if (dict.version != 0) {
|
|
fprintf(out, "%s", getString(dict.version, buf));
|
|
}
|
|
fprintf(out, "\n");
|
|
fprintf(out, "11 dict begin\n");
|
|
fprintf(out, "/FontInfo 10 dict dup begin\n");
|
|
if (dict.version != 0) {
|
|
fprintf(out, "/version (%s) readonly def\n",
|
|
getString(dict.version, buf));
|
|
}
|
|
if (dict.notice != 0) {
|
|
fprintf(out, "/Notice (%s) readonly def\n",
|
|
getString(dict.notice, buf));
|
|
}
|
|
if (dict.copyright != 0) {
|
|
fprintf(out, "/Copyright (%s) readonly def\n",
|
|
getString(dict.copyright, buf));
|
|
}
|
|
if (dict.fullName != 0) {
|
|
fprintf(out, "/FullName (%s) readonly def\n",
|
|
getString(dict.fullName, buf));
|
|
}
|
|
if (dict.familyName != 0) {
|
|
fprintf(out, "/FamilyName (%s) readonly def\n",
|
|
getString(dict.familyName, buf));
|
|
}
|
|
if (dict.weight != 0) {
|
|
fprintf(out, "/Weight (%s) readonly def\n",
|
|
getString(dict.weight, buf));
|
|
}
|
|
fprintf(out, "/isFixedPitch %s def\n", dict.isFixedPitch ? "true" : "false");
|
|
fprintf(out, "/ItalicAngle %g def\n", dict.italicAngle);
|
|
fprintf(out, "/UnderlinePosition %g def\n", dict.underlinePosition);
|
|
fprintf(out, "/UnderlineThickness %g def\n", dict.underlineThickness);
|
|
fprintf(out, "end readonly def\n");
|
|
fprintf(out, "/FontName /%s def\n", name->getCString());
|
|
fprintf(out, "/PaintType %d def\n", dict.paintType);
|
|
fprintf(out, "/FontType 1 def\n");
|
|
fprintf(out, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
|
|
dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
|
|
dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
|
|
fprintf(out, "/FontBBox [%g %g %g %g] readonly def\n",
|
|
dict.fontBBox[0], dict.fontBBox[1],
|
|
dict.fontBBox[2], dict.fontBBox[3]);
|
|
fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
|
|
if (dict.uniqueID != 0) {
|
|
fprintf(out, "/UniqueID %d def\n", dict.uniqueID);
|
|
}
|
|
|
|
// get number of glyphs from charstrings index
|
|
nGlyphs = getIndexLen((Guchar *)file + dict.charStrings);
|
|
|
|
// read charset
|
|
glyphNames = readCharset(dict.charset, nGlyphs);
|
|
|
|
// read encoding (glyph -> code mapping), write Type 1 encoding
|
|
fprintf(out, "/Encoding ");
|
|
if (dict.encoding == 0) {
|
|
fprintf(out, "StandardEncoding def\n");
|
|
} else {
|
|
fprintf(out, "256 array\n");
|
|
fprintf(out, "0 1 255 {1 index exch /.notdef put} for\n");
|
|
if (dict.encoding == 1) {
|
|
for (i = 0; i < 256; ++i) {
|
|
if (expertEncoding[i]) {
|
|
fprintf(out, "dup %d /%s put\n", i, expertEncoding[i]);
|
|
}
|
|
}
|
|
} 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++;
|
|
fprintf(out, "dup %d /%s put\n",
|
|
c, 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) {
|
|
fprintf(out, "dup %d /%s put\n",
|
|
c, 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;
|
|
fprintf(out, "dup %d /%s put\n", c, getString(sid, buf));
|
|
}
|
|
}
|
|
}
|
|
fprintf(out, "readonly def\n");
|
|
}
|
|
fprintf(out, "currentdict end\n");
|
|
|
|
// start the binary section
|
|
fprintf(out, "currentfile eexec\n");
|
|
r1 = 55665;
|
|
line = 0;
|
|
|
|
// get private dictionary
|
|
eexecWrite("\x83\xca\x73\xd5");
|
|
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) {
|
|
fputc('\n', out);
|
|
}
|
|
for (i = 0; i < 8; ++i) {
|
|
fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
|
|
}
|
|
fprintf(out, "cleartomark\n");
|
|
|
|
// clean up
|
|
delete privateDict.dictData;
|
|
if (dict.charset > 2) {
|
|
gfree(glyphNames);
|
|
}
|
|
}
|
|
|
|
void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
|
|
Type1CTopDict dict;
|
|
Type1CPrivateDict *privateDicts;
|
|
GString *charStrings;
|
|
int *charStringOffsets;
|
|
Gushort *charset;
|
|
int *cidMap;
|
|
Guchar *fdSelect;
|
|
Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
|
|
char buf[256];
|
|
int nGlyphs, nCIDs, gdBytes, nFDs;
|
|
int fdSelectFmt, nRanges, gid0, gid1, fd, offset;
|
|
int key;
|
|
double x;
|
|
GBool isFP;
|
|
int i, j, k, n;
|
|
|
|
out = outA;
|
|
|
|
fprintf(out, "/CIDInit /ProcSet findresource begin\n");
|
|
|
|
// read top dict (first font only)
|
|
readTopDict(&dict);
|
|
|
|
// read the FDArray dictionaries and Private dictionaries
|
|
if (dict.fdArrayOffset == 0) {
|
|
nFDs = 1;
|
|
privateDicts = (Type1CPrivateDict *)
|
|
gmalloc(nFDs * sizeof(Type1CPrivateDict));
|
|
privateDicts[0].dictData = new GString();
|
|
privateDicts[0].subrsOffset = 0;
|
|
privateDicts[0].defaultWidthX = 0;
|
|
privateDicts[0].defaultWidthXFP = gFalse;
|
|
privateDicts[0].nominalWidthX = 0;
|
|
privateDicts[0].nominalWidthXFP = gFalse;
|
|
} else {
|
|
fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
|
|
nFDs = getIndexLen(fdArrayIdx);
|
|
privateDicts = (Type1CPrivateDict *)
|
|
gmalloc(nFDs * sizeof(Type1CPrivateDict));
|
|
idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
|
|
for (i = 0; i < nFDs; ++i) {
|
|
privateDicts[i].dictData = NULL;
|
|
idxPtr0 = idxPtr1;
|
|
idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
|
|
ptr = idxPtr0;
|
|
j = 0;
|
|
while (ptr < idxPtr1) {
|
|
if (*ptr <= 27 || *ptr == 31) {
|
|
key = *ptr++;
|
|
if (key == 0x0c) {
|
|
key = (key << 8) | *ptr++;
|
|
}
|
|
if (key == 0x0012) {
|
|
readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
|
|
}
|
|
j = 0;
|
|
} else {
|
|
x = getNum(&ptr, &isFP);
|
|
if (j < 48) {
|
|
op[j] = x;
|
|
fp[j++] = isFP;
|
|
}
|
|
}
|
|
}
|
|
if (!privateDicts[i].dictData) {
|
|
privateDicts[i].dictData = new GString();
|
|
privateDicts[i].subrsOffset = 0;
|
|
privateDicts[i].defaultWidthX = 0;
|
|
privateDicts[i].defaultWidthXFP = gFalse;
|
|
privateDicts[i].nominalWidthX = 0;
|
|
privateDicts[i].nominalWidthXFP = gFalse;
|
|
}
|
|
}
|
|
}
|
|
|
|
// get the glyph count
|
|
charStringsIdxPtr = (Guchar *)file + dict.charStrings;
|
|
nGlyphs = getIndexLen(charStringsIdxPtr);
|
|
|
|
// read the FDSelect table
|
|
fdSelect = (Guchar *)gmalloc(nGlyphs);
|
|
if (dict.fdSelectOffset == 0) {
|
|
for (i = 0; i < nGlyphs; ++i) {
|
|
fdSelect[i] = 0;
|
|
}
|
|
} else {
|
|
ptr = (Guchar *)file + dict.fdSelectOffset;
|
|
fdSelectFmt = *ptr++;
|
|
if (fdSelectFmt == 0) {
|
|
memcpy(fdSelect, ptr, nGlyphs);
|
|
} else if (fdSelectFmt == 3) {
|
|
nRanges = getWord(ptr, 2);
|
|
ptr += 2;
|
|
gid0 = getWord(ptr, 2);
|
|
ptr += 2;
|
|
for (i = 1; i <= nRanges; ++i) {
|
|
fd = *ptr++;
|
|
gid1 = getWord(ptr, 2);
|
|
ptr += 2;
|
|
for (j = gid0; j < gid1; ++j) {
|
|
fdSelect[j] = fd;
|
|
}
|
|
gid0 = gid1;
|
|
}
|
|
} else {
|
|
error(-1, "Unknown FDSelect table format in CID font");
|
|
for (i = 0; i < nGlyphs; ++i) {
|
|
fdSelect[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// read the charset, compute the CID-to-GID mapping
|
|
charset = readCharset(dict.charset, nGlyphs);
|
|
nCIDs = 0;
|
|
for (i = 0; i < nGlyphs; ++i) {
|
|
if (charset[i] >= nCIDs) {
|
|
nCIDs = charset[i] + 1;
|
|
}
|
|
}
|
|
cidMap = (int *)gmalloc(nCIDs * sizeof(int));
|
|
for (i = 0; i < nCIDs; ++i) {
|
|
cidMap[i] = -1;
|
|
}
|
|
for (i = 0; i < nGlyphs; ++i) {
|
|
cidMap[charset[i]] = i;
|
|
}
|
|
|
|
// build the charstrings
|
|
charStrings = new GString();
|
|
charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int));
|
|
for (i = 0; i < nCIDs; ++i) {
|
|
charStringOffsets[i] = charStrings->getLength();
|
|
if (cidMap[i] >= 0) {
|
|
idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i]);
|
|
idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i]+1);
|
|
n = idxPtr1 - idxPtr0;
|
|
j = fdSelect[cidMap[i]];
|
|
defaultWidthX = privateDicts[j].defaultWidthX;
|
|
defaultWidthXFP = privateDicts[j].defaultWidthXFP;
|
|
nominalWidthX = privateDicts[j].nominalWidthX;
|
|
nominalWidthXFP = privateDicts[j].nominalWidthXFP;
|
|
cvtGlyph(idxPtr0, n);
|
|
charStrings->append(charBuf);
|
|
delete charBuf;
|
|
}
|
|
}
|
|
charStringOffsets[nCIDs] = charStrings->getLength();
|
|
|
|
// compute gdBytes = number of bytes needed for charstring offsets
|
|
// (offset size needs to account for the charstring offset table,
|
|
// with a worst case of five bytes per entry, plus the charstrings
|
|
// themselves)
|
|
i = (nCIDs + 1) * 5 + charStrings->getLength();
|
|
if (i < 0x100) {
|
|
gdBytes = 1;
|
|
} else if (i < 0x10000) {
|
|
gdBytes = 2;
|
|
} else if (i < 0x1000000) {
|
|
gdBytes = 3;
|
|
} else {
|
|
gdBytes = 4;
|
|
}
|
|
|
|
// begin the font dictionary
|
|
fprintf(out, "20 dict begin\n");
|
|
fprintf(out, "/CIDFontName /%s def\n", psName);
|
|
fprintf(out, "/CIDFontType 0 def\n");
|
|
fprintf(out, "/CIDSystemInfo 3 dict dup begin\n");
|
|
if (dict.registry > 0 && dict.ordering > 0) {
|
|
fprintf(out, " /Registry (%s) def\n", getString(dict.registry, buf));
|
|
fprintf(out, " /Ordering (%s) def\n", getString(dict.ordering, buf));
|
|
} else {
|
|
fprintf(out, " /Registry (Adobe) def\n");
|
|
fprintf(out, " /Ordering (Identity) def\n");
|
|
}
|
|
fprintf(out, " /Supplement %d def\n", dict.supplement);
|
|
fprintf(out, "end def\n");
|
|
fprintf(out, "/FontMatrix [%g %g %g %g %g %g] def\n",
|
|
dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
|
|
dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
|
|
fprintf(out, "/FontBBox [%g %g %g %g] def\n",
|
|
dict.fontBBox[0], dict.fontBBox[1],
|
|
dict.fontBBox[2], dict.fontBBox[3]);
|
|
fprintf(out, "/FontInfo 1 dict dup begin\n");
|
|
fprintf(out, " /FSType 8 def\n");
|
|
fprintf(out, "end def\n");
|
|
|
|
// CIDFont-specific entries
|
|
fprintf(out, "/CIDCount %d def\n", nCIDs);
|
|
fprintf(out, "/FDBytes 1 def\n");
|
|
fprintf(out, "/GDBytes %d def\n", gdBytes);
|
|
fprintf(out, "/CIDMapOffset 0 def\n");
|
|
if (dict.paintType != 0) {
|
|
fprintf(out, "/PaintType %d def\n", dict.paintType);
|
|
fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
|
|
}
|
|
|
|
// FDArray entry
|
|
fprintf(out, "/FDArray %d array\n", nFDs);
|
|
for (i = 0; i < nFDs; ++i) {
|
|
fprintf(out, "dup %d 10 dict begin\n", i);
|
|
fprintf(out, "/FontType 1 def\n");
|
|
fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
|
|
fprintf(out, "/PaintType %d def\n", dict.paintType);
|
|
fprintf(out, "/Private 32 dict begin\n");
|
|
fwrite(privateDicts[i].dictData->getCString(), 1,
|
|
privateDicts[i].dictData->getLength(), out);
|
|
fprintf(out, "currentdict end def\n");
|
|
fprintf(out, "currentdict end put\n");
|
|
}
|
|
fprintf(out, "def\n");
|
|
|
|
//~ need to deal with subrs
|
|
|
|
// start the binary section
|
|
offset = (nCIDs + 1) * (1 + gdBytes);
|
|
fprintf(out, "(Hex) %d StartData\n",
|
|
offset + charStrings->getLength());
|
|
|
|
// write the charstring offset (CIDMap) table
|
|
for (i = 0; i <= nCIDs; i += 6) {
|
|
for (j = 0; j < 6 && i+j <= nCIDs; ++j) {
|
|
if (cidMap[i+j] >= 0) {
|
|
buf[0] = (char)fdSelect[cidMap[i+j]];
|
|
} else {
|
|
buf[0] = (char)0;
|
|
}
|
|
n = offset + charStringOffsets[i+j];
|
|
for (k = gdBytes; k >= 1; --k) {
|
|
buf[k] = (char)(n & 0xff);
|
|
n >>= 8;
|
|
}
|
|
for (k = 0; k <= gdBytes; ++k) {
|
|
fprintf(out, "%02x", buf[k] & 0xff);
|
|
}
|
|
}
|
|
fputc('\n', out);
|
|
}
|
|
|
|
// write the charstring data
|
|
n = charStrings->getLength();
|
|
for (i = 0; i < n; i += 32) {
|
|
for (j = 0; j < 32 && i+j < n; ++j) {
|
|
fprintf(out, "%02x", charStrings->getChar(i+j) & 0xff);
|
|
}
|
|
if (i + 32 >= n) {
|
|
fputc('>', out);
|
|
}
|
|
fputc('\n', out);
|
|
}
|
|
|
|
for (i = 0; i < nFDs; ++i) {
|
|
delete privateDicts[i].dictData;
|
|
}
|
|
gfree(privateDicts);
|
|
gfree(cidMap);
|
|
gfree(charset);
|
|
gfree(charStringOffsets);
|
|
delete charStrings;
|
|
gfree(fdSelect);
|
|
}
|
|
|
|
void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
|
|
Type1CTopDict dict;
|
|
Type1CPrivateDict *privateDicts;
|
|
Gushort *charset;
|
|
int *cidMap;
|
|
Guchar *fdSelect;
|
|
Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
|
|
char buf[256];
|
|
char eBuf[256];
|
|
int nGlyphs, nCIDs, nFDs;
|
|
int fdSelectFmt, nRanges, gid0, gid1, fd;
|
|
int key;
|
|
double x;
|
|
GBool isFP;
|
|
int i, j, n;
|
|
|
|
out = outA;
|
|
|
|
// read top dict (first font only)
|
|
readTopDict(&dict);
|
|
|
|
// read the FDArray dictionaries and Private dictionaries
|
|
if (dict.fdArrayOffset == 0) {
|
|
nFDs = 1;
|
|
privateDicts = (Type1CPrivateDict *)
|
|
gmalloc(nFDs * sizeof(Type1CPrivateDict));
|
|
privateDicts[0].dictData = new GString();
|
|
privateDicts[0].subrsOffset = 0;
|
|
privateDicts[0].defaultWidthX = 0;
|
|
privateDicts[0].defaultWidthXFP = gFalse;
|
|
privateDicts[0].nominalWidthX = 0;
|
|
privateDicts[0].nominalWidthXFP = gFalse;
|
|
} else {
|
|
fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
|
|
nFDs = getIndexLen(fdArrayIdx);
|
|
privateDicts = (Type1CPrivateDict *)
|
|
gmalloc(nFDs * sizeof(Type1CPrivateDict));
|
|
idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
|
|
for (i = 0; i < nFDs; ++i) {
|
|
privateDicts[i].dictData = NULL;
|
|
idxPtr0 = idxPtr1;
|
|
idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
|
|
ptr = idxPtr0;
|
|
j = 0;
|
|
while (ptr < idxPtr1) {
|
|
if (*ptr <= 27 || *ptr == 31) {
|
|
key = *ptr++;
|
|
if (key == 0x0c) {
|
|
key = (key << 8) | *ptr++;
|
|
}
|
|
if (key == 0x0012) {
|
|
readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
|
|
}
|
|
j = 0;
|
|
} else {
|
|
x = getNum(&ptr, &isFP);
|
|
if (j < 48) {
|
|
op[j] = x;
|
|
fp[j++] = isFP;
|
|
}
|
|
}
|
|
}
|
|
if (!privateDicts[i].dictData) {
|
|
privateDicts[i].dictData = new GString();
|
|
privateDicts[i].subrsOffset = 0;
|
|
privateDicts[i].defaultWidthX = 0;
|
|
privateDicts[i].defaultWidthXFP = gFalse;
|
|
privateDicts[i].nominalWidthX = 0;
|
|
privateDicts[i].nominalWidthXFP = gFalse;
|
|
}
|
|
}
|
|
}
|
|
|
|
// get the glyph count
|
|
charStringsIdxPtr = (Guchar *)file + dict.charStrings;
|
|
nGlyphs = getIndexLen(charStringsIdxPtr);
|
|
|
|
// read the FDSelect table
|
|
fdSelect = (Guchar *)gmalloc(nGlyphs);
|
|
if (dict.fdSelectOffset == 0) {
|
|
for (i = 0; i < nGlyphs; ++i) {
|
|
fdSelect[i] = 0;
|
|
}
|
|
} else {
|
|
ptr = (Guchar *)file + dict.fdSelectOffset;
|
|
fdSelectFmt = *ptr++;
|
|
if (fdSelectFmt == 0) {
|
|
memcpy(fdSelect, ptr, nGlyphs);
|
|
} else if (fdSelectFmt == 3) {
|
|
nRanges = getWord(ptr, 2);
|
|
ptr += 2;
|
|
gid0 = getWord(ptr, 2);
|
|
ptr += 2;
|
|
for (i = 1; i <= nRanges; ++i) {
|
|
fd = *ptr++;
|
|
gid1 = getWord(ptr, 2);
|
|
ptr += 2;
|
|
for (j = gid0; j < gid1; ++j) {
|
|
fdSelect[j] = fd;
|
|
}
|
|
gid0 = gid1;
|
|
}
|
|
} else {
|
|
error(-1, "Unknown FDSelect table format in CID font");
|
|
for (i = 0; i < nGlyphs; ++i) {
|
|
fdSelect[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// read the charset, compute the CID-to-GID mapping
|
|
charset = readCharset(dict.charset, nGlyphs);
|
|
nCIDs = 0;
|
|
for (i = 0; i < nGlyphs; ++i) {
|
|
if (charset[i] >= nCIDs) {
|
|
nCIDs = charset[i] + 1;
|
|
}
|
|
}
|
|
cidMap = (int *)gmalloc(nCIDs * sizeof(int));
|
|
for (i = 0; i < nCIDs; ++i) {
|
|
cidMap[i] = -1;
|
|
}
|
|
for (i = 0; i < nGlyphs; ++i) {
|
|
cidMap[charset[i]] = i;
|
|
}
|
|
|
|
// write the descendant Type 1 fonts
|
|
for (i = 0; i < nCIDs; i += 256) {
|
|
|
|
//~ this assumes that all CIDs in this block have the same FD --
|
|
//~ to handle multiple FDs correctly, need to somehow divide the
|
|
//~ font up by FD
|
|
fd = 0;
|
|
for (j = 0; j < 256 && i+j < nCIDs; ++j) {
|
|
if (cidMap[i+j] >= 0) {
|
|
fd = fdSelect[cidMap[i+j]];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// font dictionary (unencrypted section)
|
|
fprintf(out, "16 dict begin\n");
|
|
fprintf(out, "/FontName /%s_%02x def\n", psName, i >> 8);
|
|
fprintf(out, "/FontType 1 def\n");
|
|
fprintf(out, "/FontMatrix [%g %g %g %g %g %g] def\n",
|
|
dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
|
|
dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
|
|
fprintf(out, "/FontBBox [%g %g %g %g] def\n",
|
|
dict.fontBBox[0], dict.fontBBox[1],
|
|
dict.fontBBox[2], dict.fontBBox[3]);
|
|
fprintf(out, "/PaintType %d def\n", dict.paintType);
|
|
if (dict.paintType != 0) {
|
|
fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
|
|
}
|
|
fprintf(out, "/Encoding 256 array\n");
|
|
for (j = 0; j < 256 && i+j < nCIDs; ++j) {
|
|
fprintf(out, "dup %d /c%02x put\n", j, j);
|
|
}
|
|
fprintf(out, "readonly def\n");
|
|
fprintf(out, "currentdict end\n");
|
|
|
|
// start the binary section
|
|
fprintf(out, "currentfile eexec\n");
|
|
r1 = 55665;
|
|
line = 0;
|
|
|
|
// start the private dictionary
|
|
eexecWrite("\x83\xca\x73\xd5");
|
|
eexecWrite("dup /Private 32 dict dup begin\n");
|
|
eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n");
|
|
eexecWrite("/ND {noaccess def} executeonly def\n");
|
|
eexecWrite("/NP {noaccess put} executeonly def\n");
|
|
eexecWrite("/MinFeature {16 16} ND\n");
|
|
eexecWrite(privateDicts[fd].dictData->getCString());
|
|
defaultWidthX = privateDicts[fd].defaultWidthX;
|
|
defaultWidthXFP = privateDicts[fd].defaultWidthXFP;
|
|
nominalWidthX = privateDicts[fd].nominalWidthX;
|
|
nominalWidthXFP = privateDicts[fd].nominalWidthXFP;
|
|
|
|
// start the CharStrings
|
|
sprintf(eBuf, "2 index /CharStrings 256 dict dup begin\n");
|
|
eexecWrite(eBuf);
|
|
|
|
// write the .notdef CharString
|
|
idxPtr0 = getIndexValPtr(charStringsIdxPtr, 0);
|
|
idxPtr1 = getIndexValPtr(charStringsIdxPtr, 1);
|
|
n = idxPtr1 - idxPtr0;
|
|
eexecCvtGlyph(".notdef", idxPtr0, n);
|
|
|
|
// write the CharStrings
|
|
for (j = 0; j < 256 && i+j < nCIDs; ++j) {
|
|
if (cidMap[i+j] >= 0) {
|
|
idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]);
|
|
idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]+1);
|
|
n = idxPtr1 - idxPtr0;
|
|
sprintf(buf, "c%02x", j);
|
|
eexecCvtGlyph(buf, idxPtr0, n);
|
|
}
|
|
}
|
|
eexecWrite("end\n");
|
|
eexecWrite("end\n");
|
|
eexecWrite("readonly put\n");
|
|
eexecWrite("noaccess put\n");
|
|
eexecWrite("dup /FontName get exch definefont pop\n");
|
|
eexecWrite("mark currentfile closefile\n");
|
|
|
|
// trailer
|
|
if (line > 0) {
|
|
fputc('\n', out);
|
|
}
|
|
for (j = 0; j < 8; ++j) {
|
|
fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
|
|
}
|
|
fprintf(out, "cleartomark\n");
|
|
}
|
|
|
|
// write the Type 0 parent font
|
|
fprintf(out, "16 dict begin\n");
|
|
fprintf(out, "/FontName /%s def\n", psName);
|
|
fprintf(out, "/FontType 0 def\n");
|
|
fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
|
|
fprintf(out, "/FMapType 2 def\n");
|
|
fprintf(out, "/Encoding [\n");
|
|
for (i = 0; i < nCIDs; i += 256) {
|
|
fprintf(out, "%d\n", i >> 8);
|
|
}
|
|
fprintf(out, "] def\n");
|
|
fprintf(out, "/FDepVector [\n");
|
|
for (i = 0; i < nCIDs; i += 256) {
|
|
fprintf(out, "/%s_%02x findfont\n", psName, i >> 8);
|
|
}
|
|
fprintf(out, "] def\n");
|
|
fprintf(out, "FontName currentdict end definefont pop\n");
|
|
|
|
// clean up
|
|
for (i = 0; i < nFDs; ++i) {
|
|
delete privateDicts[i].dictData;
|
|
}
|
|
gfree(privateDicts);
|
|
gfree(cidMap);
|
|
gfree(charset);
|
|
gfree(fdSelect);
|
|
}
|
|
|
|
void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
|
|
Guchar *idxPtr0, *idxPtr1, *ptr;
|
|
double x;
|
|
GBool isFP;
|
|
int key;
|
|
int i;
|
|
|
|
idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
|
|
idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
|
|
dict->version = 0;
|
|
dict->notice = 0;
|
|
dict->copyright = 0;
|
|
dict->fullName = 0;
|
|
dict->familyName = 0;
|
|
dict->weight = 0;
|
|
dict->isFixedPitch = 0;
|
|
dict->italicAngle = 0;
|
|
dict->underlinePosition = -100;
|
|
dict->underlineThickness = 50;
|
|
dict->paintType = 0;
|
|
dict->charstringType = 2;
|
|
dict->fontMatrix[0] = 0.001;
|
|
dict->fontMatrix[1] = 0;
|
|
dict->fontMatrix[2] = 0;
|
|
dict->fontMatrix[3] = 0.001;
|
|
dict->fontMatrix[4] = 0;
|
|
dict->fontMatrix[5] = 0;
|
|
dict->uniqueID = 0;
|
|
dict->fontBBox[0] = 0;
|
|
dict->fontBBox[1] = 0;
|
|
dict->fontBBox[2] = 0;
|
|
dict->fontBBox[3] = 0;
|
|
dict->strokeWidth = 0;
|
|
dict->charset = 0;
|
|
dict->encoding = 0;
|
|
dict->charStrings = 0;
|
|
dict->privateSize = 0;
|
|
dict->privateOffset = 0;
|
|
dict->registry = 0;
|
|
dict->ordering = 0;
|
|
dict->supplement = 0;
|
|
dict->fdArrayOffset = 0;
|
|
dict->fdSelectOffset = 0;
|
|
i = 0;
|
|
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(char *s) {
|
|
Guchar *p;
|
|
Guchar x;
|
|
|
|
for (p = (Guchar *)s; *p; ++p) {
|
|
x = *p ^ (r1 >> 8);
|
|
r1 = (x + r1) * 52845 + 22719;
|
|
fputc(hexChars[x >> 4], out);
|
|
fputc(hexChars[x & 0x0f], out);
|
|
line += 2;
|
|
if (line == 64) {
|
|
fputc('\n', out);
|
|
line = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Type1CFontFile::eexecCvtGlyph(char *glyphName, Guchar *s, int n) {
|
|
char eBuf[256];
|
|
|
|
cvtGlyph(s, n);
|
|
sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength());
|
|
eexecWrite(eBuf);
|
|
eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
|
|
eexecWrite(" ND\n");
|
|
delete charBuf;
|
|
}
|
|
|
|
void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
|
|
int nHints;
|
|
int x;
|
|
GBool first = gTrue;
|
|
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(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;
|
|
fputc(hexChars[x >> 4], out);
|
|
fputc(hexChars[x & 0x0f], out);
|
|
line += 2;
|
|
if (line == 64) {
|
|
fputc('\n', out);
|
|
line = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Type1CFontFile::getDeltaInt(char *buf, char *key, double *opA,
|
|
int n) {
|
|
int x, i;
|
|
|
|
sprintf(buf, "/%s [", key);
|
|
buf += strlen(buf);
|
|
x = 0;
|
|
for (i = 0; i < n; ++i) {
|
|
x += (int)opA[i];
|
|
sprintf(buf, "%s%d", i > 0 ? " " : "", x);
|
|
buf += strlen(buf);
|
|
}
|
|
sprintf(buf, "] def\n");
|
|
}
|
|
|
|
void Type1CFontFile::getDeltaReal(char *buf, char *key, double *opA,
|
|
int n) {
|
|
double x;
|
|
int i;
|
|
|
|
sprintf(buf, "/%s [", key);
|
|
buf += strlen(buf);
|
|
x = 0;
|
|
for (i = 0; i < n; ++i) {
|
|
x += opA[i];
|
|
sprintf(buf, "%s%g", i > 0 ? " " : "", x);
|
|
buf += strlen(buf);
|
|
}
|
|
sprintf(buf, "] def\n");
|
|
}
|
|
|
|
int Type1CFontFile::getIndexLen(Guchar *indexPtr) {
|
|
return (int)getWord(indexPtr, 2);
|
|
}
|
|
|
|
Guchar *Type1CFontFile::getIndexValPtr(Guchar *indexPtr, int i) {
|
|
int n, offSize;
|
|
Guchar *idxStartPtr;
|
|
|
|
n = (int)getWord(indexPtr, 2);
|
|
offSize = indexPtr[2];
|
|
idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
|
|
return idxStartPtr + getWord(indexPtr + 3 + i * offSize, offSize);
|
|
}
|
|
|
|
Guchar *Type1CFontFile::getIndexEnd(Guchar *indexPtr) {
|
|
int n, offSize;
|
|
Guchar *idxStartPtr;
|
|
|
|
n = (int)getWord(indexPtr, 2);
|
|
offSize = indexPtr[2];
|
|
idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
|
|
return idxStartPtr + getWord(indexPtr + 3 + n * offSize, offSize);
|
|
}
|
|
|
|
Guint Type1CFontFile::getWord(Guchar *ptr, int size) {
|
|
Guint x;
|
|
int i;
|
|
|
|
x = 0;
|
|
for (i = 0; i < size; ++i) {
|
|
x = (x << 8) + *ptr++;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) {
|
|
static char nybChars[16] = "0123456789.ee -";
|
|
int b0, b, nyb0, nyb1;
|
|
double x;
|
|
char buf[65];
|
|
int i;
|
|
|
|
x = 0;
|
|
*isFP = gFalse;
|
|
b0 = (*ptr)[0];
|
|
if (b0 < 28) {
|
|
x = 0;
|
|
} else if (b0 == 28) {
|
|
x = ((*ptr)[1] << 8) + (*ptr)[2];
|
|
*ptr += 3;
|
|
} else if (b0 == 29) {
|
|
x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4];
|
|
*ptr += 5;
|
|
} else if (b0 == 30) {
|
|
*ptr += 1;
|
|
i = 0;
|
|
do {
|
|
b = *(*ptr)++;
|
|
nyb0 = b >> 4;
|
|
nyb1 = b & 0x0f;
|
|
if (nyb0 == 0xf) {
|
|
break;
|
|
}
|
|
buf[i++] = nybChars[nyb0];
|
|
if (i == 64) {
|
|
break;
|
|
}
|
|
if (nyb0 == 0xc) {
|
|
buf[i++] = '-';
|
|
}
|
|
if (i == 64) {
|
|
break;
|
|
}
|
|
if (nyb1 == 0xf) {
|
|
break;
|
|
}
|
|
buf[i++] = nybChars[nyb1];
|
|
if (i == 64) {
|
|
break;
|
|
}
|
|
if (nyb1 == 0xc) {
|
|
buf[i++] = '-';
|
|
}
|
|
} while (i < 64);
|
|
buf[i] = '\0';
|
|
x = atof(buf);
|
|
*isFP = gTrue;
|
|
} else if (b0 == 31) {
|
|
x = 0;
|
|
} else if (b0 < 247) {
|
|
x = b0 - 139;
|
|
*ptr += 1;
|
|
} else if (b0 < 251) {
|
|
x = ((b0 - 247) << 8) + (*ptr)[1] + 108;
|
|
*ptr += 2;
|
|
} else {
|
|
x = -((b0 - 251) << 8) - (*ptr)[1] - 108;
|
|
*ptr += 2;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
char *Type1CFontFile::getString(int sid, char *buf) {
|
|
Guchar *idxPtr0, *idxPtr1;
|
|
int n;
|
|
|
|
if (sid < 391) {
|
|
strcpy(buf, type1CStdStrings[sid]);
|
|
} else {
|
|
sid -= 391;
|
|
idxPtr0 = getIndexValPtr(stringIdxPtr, sid);
|
|
idxPtr1 = getIndexValPtr(stringIdxPtr, sid + 1);
|
|
if ((n = idxPtr1 - idxPtr0) > 255) {
|
|
n = 255;
|
|
}
|
|
strncpy(buf, (char *)idxPtr0, n);
|
|
buf[n] = '\0';
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// TrueTypeFontFile
|
|
//------------------------------------------------------------------------
|
|
|
|
//
|
|
// Terminology
|
|
// -----------
|
|
//
|
|
// character code = number used as an element of a text string
|
|
//
|
|
// character name = glyph name = name for a particular glyph within a
|
|
// font
|
|
//
|
|
// glyph index = position (within some internal table in the font)
|
|
// where the instructions to draw a particular glyph are
|
|
// stored
|
|
//
|
|
// Type 1 fonts
|
|
// ------------
|
|
//
|
|
// Type 1 fonts contain:
|
|
//
|
|
// Encoding: array of glyph names, maps char codes to glyph names
|
|
//
|
|
// Encoding[charCode] = charName
|
|
//
|
|
// CharStrings: dictionary of instructions, keyed by character names,
|
|
// maps character name to glyph data
|
|
//
|
|
// CharStrings[charName] = glyphData
|
|
//
|
|
// TrueType fonts
|
|
// --------------
|
|
//
|
|
// TrueType fonts contain:
|
|
//
|
|
// 'cmap' table: mapping from character code to glyph index; there may
|
|
// be multiple cmaps in a TrueType font
|
|
//
|
|
// cmap[charCode] = glyphIdx
|
|
//
|
|
// 'post' table: mapping from glyph index to glyph name
|
|
//
|
|
// post[glyphIdx] = glyphName
|
|
//
|
|
// Type 42 fonts
|
|
// -------------
|
|
//
|
|
// Type 42 fonts contain:
|
|
//
|
|
// Encoding: array of glyph names, maps char codes to glyph names
|
|
//
|
|
// Encoding[charCode] = charName
|
|
//
|
|
// CharStrings: dictionary of glyph indexes, keyed by character names,
|
|
// maps character name to glyph index
|
|
//
|
|
// CharStrings[charName] = glyphIdx
|
|
//
|
|
|
|
struct TTFontTableHdr {
|
|
char tag[4];
|
|
Guint checksum;
|
|
Guint offset;
|
|
Guint length;
|
|
};
|
|
|
|
struct T42Table {
|
|
char *tag; // 4-byte tag
|
|
GBool required; // required by the TrueType spec?
|
|
};
|
|
|
|
// TrueType tables to be embedded in Type 42 fonts.
|
|
// NB: the table names must be in alphabetical order here.
|
|
#define nT42Tables 11
|
|
static T42Table t42Tables[nT42Tables] = {
|
|
{ "cvt ", gTrue },
|
|
{ "fpgm", gTrue },
|
|
{ "glyf", gTrue },
|
|
{ "head", gTrue },
|
|
{ "hhea", gTrue },
|
|
{ "hmtx", gTrue },
|
|
{ "loca", gTrue },
|
|
{ "maxp", gTrue },
|
|
{ "prep", gTrue },
|
|
{ "vhea", gFalse },
|
|
{ "vmtx", gFalse }
|
|
};
|
|
#define t42HeadTable 3
|
|
#define t42LocaTable 6
|
|
#define t42GlyfTable 2
|
|
|
|
// Glyph names in some arbitrary standard that Apple uses for their
|
|
// TrueType fonts.
|
|
static char *macGlyphNames[258] = {
|
|
".notdef",
|
|
"null",
|
|
"CR",
|
|
"space",
|
|
"exclam",
|
|
"quotedbl",
|
|
"numbersign",
|
|
"dollar",
|
|
"percent",
|
|
"ampersand",
|
|
"quotesingle",
|
|
"parenleft",
|
|
"parenright",
|
|
"asterisk",
|
|
"plus",
|
|
"comma",
|
|
"hyphen",
|
|
"period",
|
|
"slash",
|
|
"zero",
|
|
"one",
|
|
"two",
|
|
"three",
|
|
"four",
|
|
"five",
|
|
"six",
|
|
"seven",
|
|
"eight",
|
|
"nine",
|
|
"colon",
|
|
"semicolon",
|
|
"less",
|
|
"equal",
|
|
"greater",
|
|
"question",
|
|
"at",
|
|
"A",
|
|
"B",
|
|
"C",
|
|
"D",
|
|
"E",
|
|
"F",
|
|
"G",
|
|
"H",
|
|
"I",
|
|
"J",
|
|
"K",
|
|
"L",
|
|
"M",
|
|
"N",
|
|
"O",
|
|
"P",
|
|
"Q",
|
|
"R",
|
|
"S",
|
|
"T",
|
|
"U",
|
|
"V",
|
|
"W",
|
|
"X",
|
|
"Y",
|
|
"Z",
|
|
"bracketleft",
|
|
"backslash",
|
|
"bracketright",
|
|
"asciicircum",
|
|
"underscore",
|
|
"grave",
|
|
"a",
|
|
"b",
|
|
"c",
|
|
"d",
|
|
"e",
|
|
"f",
|
|
"g",
|
|
"h",
|
|
"i",
|
|
"j",
|
|
"k",
|
|
"l",
|
|
"m",
|
|
"n",
|
|
"o",
|
|
"p",
|
|
"q",
|
|
"r",
|
|
"s",
|
|
"t",
|
|
"u",
|
|
"v",
|
|
"w",
|
|
"x",
|
|
"y",
|
|
"z",
|
|
"braceleft",
|
|
"bar",
|
|
"braceright",
|
|
"asciitilde",
|
|
"Adieresis",
|
|
"Aring",
|
|
"Ccedilla",
|
|
"Eacute",
|
|
"Ntilde",
|
|
"Odieresis",
|
|
"Udieresis",
|
|
"aacute",
|
|
"agrave",
|
|
"acircumflex",
|
|
"adieresis",
|
|
"atilde",
|
|
"aring",
|
|
"ccedilla",
|
|
"eacute",
|
|
"egrave",
|
|
"ecircumflex",
|
|
"edieresis",
|
|
"iacute",
|
|
"igrave",
|
|
"icircumflex",
|
|
"idieresis",
|
|
"ntilde",
|
|
"oacute",
|
|
"ograve",
|
|
"ocircumflex",
|
|
"odieresis",
|
|
"otilde",
|
|
"uacute",
|
|
"ugrave",
|
|
"ucircumflex",
|
|
"udieresis",
|
|
"dagger",
|
|
"degree",
|
|
"cent",
|
|
"sterling",
|
|
"section",
|
|
"bullet",
|
|
"paragraph",
|
|
"germandbls",
|
|
"registered",
|
|
"copyright",
|
|
"trademark",
|
|
"acute",
|
|
"dieresis",
|
|
"notequal",
|
|
"AE",
|
|
"Oslash",
|
|
"infinity",
|
|
"plusminus",
|
|
"lessequal",
|
|
"greaterequal",
|
|
"yen",
|
|
"mu1",
|
|
"partialdiff",
|
|
"summation",
|
|
"product",
|
|
"pi",
|
|
"integral",
|
|
"ordfeminine",
|
|
"ordmasculine",
|
|
"Ohm",
|
|
"ae",
|
|
"oslash",
|
|
"questiondown",
|
|
"exclamdown",
|
|
"logicalnot",
|
|
"radical",
|
|
"florin",
|
|
"approxequal",
|
|
"increment",
|
|
"guillemotleft",
|
|
"guillemotright",
|
|
"ellipsis",
|
|
"nbspace",
|
|
"Agrave",
|
|
"Atilde",
|
|
"Otilde",
|
|
"OE",
|
|
"oe",
|
|
"endash",
|
|
"emdash",
|
|
"quotedblleft",
|
|
"quotedblright",
|
|
"quoteleft",
|
|
"quoteright",
|
|
"divide",
|
|
"lozenge",
|
|
"ydieresis",
|
|
"Ydieresis",
|
|
"fraction",
|
|
"currency",
|
|
"guilsinglleft",
|
|
"guilsinglright",
|
|
"fi",
|
|
"fl",
|
|
"daggerdbl",
|
|
"periodcentered",
|
|
"quotesinglbase",
|
|
"quotedblbase",
|
|
"perthousand",
|
|
"Acircumflex",
|
|
"Ecircumflex",
|
|
"Aacute",
|
|
"Edieresis",
|
|
"Egrave",
|
|
"Iacute",
|
|
"Icircumflex",
|
|
"Idieresis",
|
|
"Igrave",
|
|
"Oacute",
|
|
"Ocircumflex",
|
|
"applelogo",
|
|
"Ograve",
|
|
"Uacute",
|
|
"Ucircumflex",
|
|
"Ugrave",
|
|
"dotlessi",
|
|
"circumflex",
|
|
"tilde",
|
|
"overscore",
|
|
"breve",
|
|
"dotaccent",
|
|
"ring",
|
|
"cedilla",
|
|
"hungarumlaut",
|
|
"ogonek",
|
|
"caron",
|
|
"Lslash",
|
|
"lslash",
|
|
"Scaron",
|
|
"scaron",
|
|
"Zcaron",
|
|
"zcaron",
|
|
"brokenbar",
|
|
"Eth",
|
|
"eth",
|
|
"Yacute",
|
|
"yacute",
|
|
"Thorn",
|
|
"thorn",
|
|
"minus",
|
|
"multiply",
|
|
"onesuperior",
|
|
"twosuperior",
|
|
"threesuperior",
|
|
"onehalf",
|
|
"onequarter",
|
|
"threequarters",
|
|
"franc",
|
|
"Gbreve",
|
|
"gbreve",
|
|
"Idot",
|
|
"Scedilla",
|
|
"scedilla",
|
|
"Cacute",
|
|
"cacute",
|
|
"Ccaron",
|
|
"ccaron",
|
|
"dmacron"
|
|
};
|
|
|
|
enum T42FontIndexMode {
|
|
t42FontModeUnicode,
|
|
t42FontModeCharCode,
|
|
t42FontModeCharCodeOffset,
|
|
t42FontModeMacRoman
|
|
};
|
|
|
|
TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
|
|
int pos, i;
|
|
|
|
file = fileA;
|
|
len = lenA;
|
|
|
|
encoding = NULL;
|
|
|
|
// read table directory
|
|
nTables = getUShort(4);
|
|
tableHdrs = (TTFontTableHdr *)gmalloc(nTables * sizeof(TTFontTableHdr));
|
|
pos = 12;
|
|
for (i = 0; i < nTables; ++i) {
|
|
tableHdrs[i].tag[0] = getByte(pos+0);
|
|
tableHdrs[i].tag[1] = getByte(pos+1);
|
|
tableHdrs[i].tag[2] = getByte(pos+2);
|
|
tableHdrs[i].tag[3] = getByte(pos+3);
|
|
tableHdrs[i].checksum = getULong(pos+4);
|
|
tableHdrs[i].offset = getULong(pos+8);
|
|
tableHdrs[i].length = getULong(pos+12);
|
|
pos += 16;
|
|
}
|
|
|
|
// check for tables that are required by both the TrueType spec
|
|
// and the Type 42 spec
|
|
if (seekTable("head") < 0 ||
|
|
seekTable("hhea") < 0 ||
|
|
seekTable("loca") < 0 ||
|
|
seekTable("maxp") < 0 ||
|
|
seekTable("glyf") < 0 ||
|
|
seekTable("hmtx") < 0) {
|
|
error(-1, "TrueType font file is missing a required table");
|
|
return;
|
|
}
|
|
|
|
// read the 'head' table
|
|
pos = seekTable("head");
|
|
bbox[0] = getShort(pos + 36);
|
|
bbox[1] = getShort(pos + 38);
|
|
bbox[2] = getShort(pos + 40);
|
|
bbox[3] = getShort(pos + 42);
|
|
locaFmt = getShort(pos + 50);
|
|
|
|
// read the 'maxp' table
|
|
pos = seekTable("maxp");
|
|
nGlyphs = getUShort(pos + 4);
|
|
}
|
|
|
|
TrueTypeFontFile::~TrueTypeFontFile() {
|
|
int i;
|
|
|
|
if (encoding) {
|
|
for (i = 0; i < 256; ++i) {
|
|
gfree(encoding[i]);
|
|
}
|
|
gfree(encoding);
|
|
}
|
|
gfree(tableHdrs);
|
|
}
|
|
|
|
char *TrueTypeFontFile::getName() {
|
|
return NULL;
|
|
}
|
|
|
|
char **TrueTypeFontFile::getEncoding() {
|
|
int cmap[256];
|
|
int nCmaps, cmapPlatform, cmapEncoding, cmapFmt;
|
|
int cmapLen, cmapOffset, cmapFirst;
|
|
int segCnt, segStart, segEnd, segDelta, segOffset;
|
|
int pos, i, j, k;
|
|
Guint fmt;
|
|
GString *s;
|
|
int stringIdx, stringPos, n;
|
|
|
|
if (encoding) {
|
|
return encoding;
|
|
}
|
|
|
|
//----- construct the (char code) -> (glyph idx) mapping
|
|
|
|
// map everything to the missing glyph
|
|
for (i = 0; i < 256; ++i) {
|
|
cmap[i] = 0;
|
|
}
|
|
|
|
// look for the 'cmap' table
|
|
if ((pos = seekTable("cmap")) >= 0) {
|
|
nCmaps = getUShort(pos+2);
|
|
|
|
// if the font has a Windows-symbol cmap, use it;
|
|
// otherwise, use the first cmap in the table
|
|
for (i = 0; i < nCmaps; ++i) {
|
|
cmapPlatform = getUShort(pos + 4 + 8*i);
|
|
cmapEncoding = getUShort(pos + 4 + 8*i + 2);
|
|
if (cmapPlatform == 3 && cmapEncoding == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (i >= nCmaps) {
|
|
i = 0;
|
|
cmapPlatform = getUShort(pos + 4);
|
|
cmapEncoding = getUShort(pos + 4 + 2);
|
|
}
|
|
pos += getULong(pos + 4 + 8*i + 4);
|
|
|
|
// read the cmap
|
|
cmapFmt = getUShort(pos);
|
|
switch (cmapFmt) {
|
|
case 0: // byte encoding table (Apple standard)
|
|
cmapLen = getUShort(pos + 2);
|
|
for (i = 0; i < cmapLen && i < 256; ++i) {
|
|
cmap[i] = getByte(pos + 6 + i);
|
|
}
|
|
break;
|
|
case 4: // segment mapping to delta values (Microsoft standard)
|
|
if (cmapPlatform == 3 && cmapEncoding == 0) {
|
|
// Windows-symbol uses char codes 0xf000 - 0xf0ff
|
|
cmapOffset = 0xf000;
|
|
} else {
|
|
cmapOffset = 0;
|
|
}
|
|
segCnt = getUShort(pos + 6) / 2;
|
|
for (i = 0; i < segCnt; ++i) {
|
|
segEnd = getUShort(pos + 14 + 2*i);
|
|
segStart = getUShort(pos + 16 + 2*segCnt + 2*i);
|
|
segDelta = getUShort(pos + 16 + 4*segCnt + 2*i);
|
|
segOffset = getUShort(pos + 16 + 6*segCnt + 2*i);
|
|
if (segStart - cmapOffset <= 0xff &&
|
|
segEnd - cmapOffset >= 0) {
|
|
for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset;
|
|
j <= segEnd && j - cmapOffset <= 0xff;
|
|
++j) {
|
|
if (segOffset == 0) {
|
|
k = (j + segDelta) & 0xffff;
|
|
} else {
|
|
k = getUShort(pos + 16 + 6*segCnt + 2*i +
|
|
segOffset + 2 * (j - segStart));
|
|
if (k != 0) {
|
|
k = (k + segDelta) & 0xffff;
|
|
}
|
|
}
|
|
cmap[j - cmapOffset] = k;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 6: // trimmed table mapping
|
|
cmapFirst = getUShort(pos + 6);
|
|
cmapLen = getUShort(pos + 8);
|
|
for (i = cmapFirst; i < 256 && i < cmapFirst + cmapLen; ++i) {
|
|
cmap[i] = getUShort(pos + 10 + 2*i);
|
|
}
|
|
break;
|
|
default:
|
|
error(-1, "Unimplemented cmap format (%d) in TrueType font file",
|
|
cmapFmt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----- construct the (glyph idx) -> (glyph name) mapping
|
|
//----- and compute the (char code) -> (glyph name) mapping
|
|
|
|
encoding = (char **)gmalloc(256 * sizeof(char *));
|
|
for (i = 0; i < 256; ++i) {
|
|
encoding[i] = NULL;
|
|
}
|
|
|
|
if ((pos = seekTable("post")) >= 0) {
|
|
fmt = getULong(pos);
|
|
|
|
// Apple font
|
|
if (fmt == 0x00010000) {
|
|
for (i = 0; i < 256; ++i) {
|
|
j = (cmap[i] < 258) ? cmap[i] : 0;
|
|
encoding[i] = copyString(macGlyphNames[j]);
|
|
}
|
|
|
|
// Microsoft font
|
|
} else if (fmt == 0x00020000) {
|
|
stringIdx = 0;
|
|
stringPos = pos + 34 + 2*nGlyphs;
|
|
for (i = 0; i < 256; ++i) {
|
|
if (cmap[i] < nGlyphs) {
|
|
j = getUShort(pos + 34 + 2 * cmap[i]);
|
|
if (j < 258) {
|
|
encoding[i] = copyString(macGlyphNames[j]);
|
|
} else {
|
|
j -= 258;
|
|
if (j != stringIdx) {
|
|
for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs;
|
|
stringIdx < j;
|
|
++stringIdx, stringPos += 1 + getByte(stringPos)) ;
|
|
}
|
|
n = getByte(stringPos);
|
|
s = new GString(file + stringPos + 1, n);
|
|
encoding[i] = copyString(s->getCString());
|
|
delete s;
|
|
++stringIdx;
|
|
stringPos += 1 + n;
|
|
}
|
|
} else {
|
|
encoding[i] = copyString(macGlyphNames[0]);
|
|
}
|
|
}
|
|
|
|
// Apple subset
|
|
} else if (fmt == 0x000280000) {
|
|
for (i = 0; i < 256; ++i) {
|
|
if (cmap[i] < nGlyphs) {
|
|
j = i + getChar(pos + 32 + cmap[i]);
|
|
} else {
|
|
j = 0;
|
|
}
|
|
encoding[i] = copyString(macGlyphNames[j]);
|
|
}
|
|
|
|
// Ugh, just assume the Apple glyph set
|
|
} else {
|
|
for (i = 0; i < 256; ++i) {
|
|
j = (cmap[i] < 258) ? cmap[i] : 0;
|
|
encoding[i] = copyString(macGlyphNames[j]);
|
|
}
|
|
}
|
|
|
|
// no "post" table: assume the Apple glyph set
|
|
} else {
|
|
for (i = 0; i < 256; ++i) {
|
|
j = (cmap[i] < 258) ? cmap[i] : 0;
|
|
encoding[i] = copyString(macGlyphNames[j]);
|
|
}
|
|
}
|
|
|
|
return encoding;
|
|
}
|
|
|
|
void TrueTypeFontFile::convertToType42(char *name, char **encodingA,
|
|
CharCodeToUnicode *toUnicode,
|
|
GBool pdfFontHasEncoding, FILE *out) {
|
|
// write the header
|
|
fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
|
|
|
|
// begin the font dictionary
|
|
fprintf(out, "10 dict begin\n");
|
|
fprintf(out, "/FontName /%s def\n", name);
|
|
fprintf(out, "/FontType 42 def\n");
|
|
fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
|
|
fprintf(out, "/FontBBox [%d %d %d %d] def\n",
|
|
bbox[0], bbox[1], bbox[2], bbox[3]);
|
|
fprintf(out, "/PaintType 0 def\n");
|
|
|
|
// write the guts of the dictionary
|
|
cvtEncoding(encodingA, out);
|
|
cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, out);
|
|
cvtSfnts(out, NULL);
|
|
|
|
// end the dictionary and define the font
|
|
fprintf(out, "FontName currentdict end definefont pop\n");
|
|
}
|
|
|
|
void TrueTypeFontFile::convertToCIDType2(char *name, Gushort *cidMap,
|
|
int nCIDs, FILE *out) {
|
|
Gushort cid;
|
|
int i, j, k;
|
|
|
|
// write the header
|
|
fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
|
|
|
|
// begin the font dictionary
|
|
fprintf(out, "20 dict begin\n");
|
|
fprintf(out, "/CIDFontName /%s def\n", name);
|
|
fprintf(out, "/CIDFontType 2 def\n");
|
|
fprintf(out, "/FontType 42 def\n");
|
|
fprintf(out, "/CIDSystemInfo 3 dict dup begin\n");
|
|
fprintf(out, " /Registry (Adobe) def\n");
|
|
fprintf(out, " /Ordering (Identity) def\n");
|
|
fprintf(out, " /Supplement 0 def\n");
|
|
fprintf(out, " end def\n");
|
|
fprintf(out, "/GDBytes 2 def\n");
|
|
if (cidMap) {
|
|
fprintf(out, "/CIDCount %d def\n", nCIDs);
|
|
if (nCIDs > 32767) {
|
|
fprintf(out, "/CIDMap [");
|
|
for (i = 0; i < nCIDs; i += 32768 - 16) {
|
|
fprintf(out, "<\n");
|
|
for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
|
|
fprintf(out, " ");
|
|
for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
|
|
cid = cidMap[i+j+k];
|
|
fprintf(out, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
|
|
}
|
|
fprintf(out, "\n");
|
|
}
|
|
fprintf(out, " >");
|
|
}
|
|
fprintf(out, "\n");
|
|
fprintf(out, "] def\n");
|
|
} else {
|
|
fprintf(out, "/CIDMap <\n");
|
|
for (i = 0; i < nCIDs; i += 16) {
|
|
fprintf(out, " ");
|
|
for (j = 0; j < 16 && i+j < nCIDs; ++j) {
|
|
cid = cidMap[i+j];
|
|
fprintf(out, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
|
|
}
|
|
fprintf(out, "\n");
|
|
}
|
|
fprintf(out, "> def\n");
|
|
}
|
|
} else {
|
|
// direct mapping - just fill the string(s) with s[i]=i
|
|
fprintf(out, "/CIDCount %d def\n", nGlyphs);
|
|
if (nGlyphs > 32767) {
|
|
fprintf(out, "/CIDMap [\n");
|
|
for (i = 0; i < nGlyphs; i += 32767) {
|
|
j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
|
|
fprintf(out, " %d string 0 1 %d {\n", 2 * j, j - 1);
|
|
fprintf(out, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
|
|
fprintf(out, " 1 index exch dup 2 mul 1 add exch %d add"
|
|
" 255 and put\n", i);
|
|
fprintf(out, " } for\n");
|
|
}
|
|
fprintf(out, "] def\n");
|
|
} else {
|
|
fprintf(out, "/CIDMap %d string\n", 2 * nGlyphs);
|
|
fprintf(out, " 0 1 %d {\n", nGlyphs - 1);
|
|
fprintf(out, " 2 copy dup 2 mul exch -8 bitshift put\n");
|
|
fprintf(out, " 1 index exch dup 2 mul 1 add exch 255 and put\n");
|
|
fprintf(out, " } for\n");
|
|
fprintf(out, "def\n");
|
|
}
|
|
}
|
|
fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
|
|
fprintf(out, "/FontBBox [%d %d %d %d] def\n",
|
|
bbox[0], bbox[1], bbox[2], bbox[3]);
|
|
fprintf(out, "/PaintType 0 def\n");
|
|
fprintf(out, "/Encoding [] readonly def\n");
|
|
fprintf(out, "/CharStrings 1 dict dup begin\n");
|
|
fprintf(out, " /.notdef 0 def\n");
|
|
fprintf(out, " end readonly def\n");
|
|
|
|
// write the guts of the dictionary
|
|
cvtSfnts(out, NULL);
|
|
|
|
// end the dictionary and define the font
|
|
fprintf(out, "CIDFontName currentdict end /CIDFont defineresource pop\n");
|
|
}
|
|
|
|
void TrueTypeFontFile::convertToType0(char *name, Gushort *cidMap,
|
|
int nCIDs, FILE *out) {
|
|
GString *sfntsName;
|
|
int n, i, j;
|
|
|
|
// write the Type 42 sfnts array
|
|
sfntsName = (new GString(name))->append("_sfnts");
|
|
cvtSfnts(out, sfntsName);
|
|
delete sfntsName;
|
|
|
|
// write the descendant Type 42 fonts
|
|
n = cidMap ? nCIDs : nGlyphs;
|
|
for (i = 0; i < n; i += 256) {
|
|
fprintf(out, "10 dict begin\n");
|
|
fprintf(out, "/FontName /%s_%02x def\n", name, i >> 8);
|
|
fprintf(out, "/FontType 42 def\n");
|
|
fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
|
|
fprintf(out, "/FontBBox [%d %d %d %d] def\n",
|
|
bbox[0], bbox[1], bbox[2], bbox[3]);
|
|
fprintf(out, "/PaintType 0 def\n");
|
|
fprintf(out, "/sfnts %s_sfnts def\n", name);
|
|
fprintf(out, "/Encoding 256 array\n");
|
|
for (j = 0; j < 256 && i+j < n; ++j) {
|
|
fprintf(out, "dup %d /c%02x put\n", j, j);
|
|
}
|
|
fprintf(out, "readonly def\n");
|
|
fprintf(out, "/CharStrings 257 dict dup begin\n");
|
|
fprintf(out, "/.notdef 0 def\n");
|
|
for (j = 0; j < 256 && i+j < n; ++j) {
|
|
fprintf(out, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
|
|
}
|
|
fprintf(out, "end readonly def\n");
|
|
fprintf(out, "FontName currentdict end definefont pop\n");
|
|
}
|
|
|
|
// write the Type 0 parent font
|
|
fprintf(out, "16 dict begin\n");
|
|
fprintf(out, "/FontName /%s def\n", name);
|
|
fprintf(out, "/FontType 0 def\n");
|
|
fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
|
|
fprintf(out, "/FMapType 2 def\n");
|
|
fprintf(out, "/Encoding [\n");
|
|
for (i = 0; i < n; i += 256) {
|
|
fprintf(out, "%d\n", i >> 8);
|
|
}
|
|
fprintf(out, "] def\n");
|
|
fprintf(out, "/FDepVector [\n");
|
|
for (i = 0; i < n; i += 256) {
|
|
fprintf(out, "/%s_%02x findfont\n", name, i >> 8);
|
|
}
|
|
fprintf(out, "] def\n");
|
|
fprintf(out, "FontName currentdict end definefont pop\n");
|
|
}
|
|
|
|
int TrueTypeFontFile::getByte(int pos) {
|
|
if (pos < 0 || pos >= len) {
|
|
return 0;
|
|
}
|
|
return file[pos] & 0xff;
|
|
}
|
|
|
|
int TrueTypeFontFile::getChar(int pos) {
|
|
int x;
|
|
|
|
if (pos < 0 || pos >= len) {
|
|
return 0;
|
|
}
|
|
x = file[pos] & 0xff;
|
|
if (x & 0x80)
|
|
x |= 0xffffff00;
|
|
return x;
|
|
}
|
|
|
|
int TrueTypeFontFile::getUShort(int pos) {
|
|
int x;
|
|
|
|
if (pos < 0 || pos+1 >= len) {
|
|
return 0;
|
|
}
|
|
x = file[pos] & 0xff;
|
|
x = (x << 8) + (file[pos+1] & 0xff);
|
|
return x;
|
|
}
|
|
|
|
int TrueTypeFontFile::getShort(int pos) {
|
|
int x;
|
|
|
|
if (pos < 0 || pos+1 >= len) {
|
|
return 0;
|
|
}
|
|
x = file[pos] & 0xff;
|
|
x = (x << 8) + (file[pos+1] & 0xff);
|
|
if (x & 0x8000)
|
|
x |= 0xffff0000;
|
|
return x;
|
|
}
|
|
|
|
Guint TrueTypeFontFile::getULong(int pos) {
|
|
int x;
|
|
|
|
if (pos < 0 || pos+3 >= len) {
|
|
return 0;
|
|
}
|
|
x = file[pos] & 0xff;
|
|
x = (x << 8) + (file[pos+1] & 0xff);
|
|
x = (x << 8) + (file[pos+2] & 0xff);
|
|
x = (x << 8) + (file[pos+3] & 0xff);
|
|
return x;
|
|
}
|
|
|
|
double TrueTypeFontFile::getFixed(int pos) {
|
|
int x, y;
|
|
|
|
x = getShort(pos);
|
|
y = getUShort(pos+2);
|
|
return (double)x + (double)y / 65536;
|
|
}
|
|
|
|
int TrueTypeFontFile::seekTable(char *tag) {
|
|
int i;
|
|
|
|
for (i = 0; i < nTables; ++i) {
|
|
if (!strncmp(tableHdrs[i].tag, tag, 4)) {
|
|
return tableHdrs[i].offset;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int TrueTypeFontFile::seekTableIdx(char *tag) {
|
|
int i;
|
|
|
|
for (i = 0; i < nTables; ++i) {
|
|
if (!strncmp(tableHdrs[i].tag, tag, 4)) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void TrueTypeFontFile::cvtEncoding(char **encodingA, FILE *out) {
|
|
char *name;
|
|
int i;
|
|
|
|
fprintf(out, "/Encoding 256 array\n");
|
|
for (i = 0; i < 256; ++i) {
|
|
if (!(name = encodingA[i])) {
|
|
name = ".notdef";
|
|
}
|
|
fprintf(out, "dup %d /%s put\n", i, name);
|
|
}
|
|
fprintf(out, "readonly def\n");
|
|
}
|
|
|
|
void TrueTypeFontFile::cvtCharStrings(char **encodingA,
|
|
CharCodeToUnicode *toUnicode,
|
|
GBool pdfFontHasEncoding, FILE *out) {
|
|
int unicodeCmap, macRomanCmap, msSymbolCmap;
|
|
int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapOffset;
|
|
T42FontIndexMode mode;
|
|
char *name;
|
|
Unicode u;
|
|
int pos, i, j, k;
|
|
|
|
// always define '.notdef'
|
|
fprintf(out, "/CharStrings 256 dict dup begin\n");
|
|
fprintf(out, "/.notdef 0 def\n");
|
|
|
|
// if there's no 'cmap' table, punt
|
|
if ((pos = seekTable("cmap")) < 0) {
|
|
goto err;
|
|
}
|
|
|
|
// To match up with the Adobe-defined behaviour, we choose a cmap
|
|
// like this:
|
|
// 1. If the PDF font has an encoding:
|
|
// 1a. If the TrueType font has a Microsoft Unicode cmap, use it,
|
|
// and use the Unicode indexes, not the char codes.
|
|
// 1b. If the TrueType font has a Macintosh Roman cmap, use it,
|
|
// and reverse map the char names through MacRomanEncoding to
|
|
// get char codes.
|
|
// 2. If the PDF font does not have an encoding:
|
|
// 2a. If the TrueType font has a Macintosh Roman cmap, use it,
|
|
// and use char codes directly.
|
|
// 2b. If the TrueType font has a Microsoft Symbol cmap, use it,
|
|
// and use (0xf000 + char code).
|
|
// 3. If none of these rules apply, use the first cmap and hope for
|
|
// the best (this shouldn't happen).
|
|
nCmaps = getUShort(pos+2);
|
|
unicodeCmap = macRomanCmap = msSymbolCmap = -1;
|
|
cmapOffset = 0;
|
|
for (i = 0; i < nCmaps; ++i) {
|
|
cmapPlatform = getUShort(pos + 4 + 8*i);
|
|
cmapEncoding = getUShort(pos + 4 + 8*i + 2);
|
|
if (cmapPlatform == 3 && cmapEncoding == 1) {
|
|
unicodeCmap = i;
|
|
} else if (cmapPlatform == 1 && cmapEncoding == 0) {
|
|
macRomanCmap = i;
|
|
} else if (cmapPlatform == 3 && cmapEncoding == 0) {
|
|
msSymbolCmap = i;
|
|
}
|
|
}
|
|
i = 0;
|
|
mode = t42FontModeCharCode;
|
|
if (pdfFontHasEncoding) {
|
|
if (unicodeCmap >= 0) {
|
|
i = unicodeCmap;
|
|
mode = t42FontModeUnicode;
|
|
} else if (macRomanCmap >= 0) {
|
|
i = macRomanCmap;
|
|
mode = t42FontModeMacRoman;
|
|
}
|
|
} else {
|
|
if (macRomanCmap >= 0) {
|
|
i = macRomanCmap;
|
|
mode = t42FontModeCharCode;
|
|
} else if (msSymbolCmap >= 0) {
|
|
i = msSymbolCmap;
|
|
mode = t42FontModeCharCodeOffset;
|
|
cmapOffset = 0xf000;
|
|
}
|
|
}
|
|
cmapPlatform = getUShort(pos + 4 + 8*i);
|
|
cmapEncoding = getUShort(pos + 4 + 8*i + 2);
|
|
pos += getULong(pos + 4 + 8*i + 4);
|
|
cmapFmt = getUShort(pos);
|
|
if (cmapFmt != 0 && cmapFmt != 4 && cmapFmt != 6) {
|
|
error(-1, "Unimplemented cmap format (%d) in TrueType font file",
|
|
cmapFmt);
|
|
goto err;
|
|
}
|
|
|
|
// map char name to glyph index:
|
|
// 1. use encoding to map name to char code
|
|
// 2. use cmap to map char code to glyph index
|
|
j = 0; // make gcc happy
|
|
for (i = 0; i < 256; ++i) {
|
|
name = encodingA[i];
|
|
if (name && strcmp(name, ".notdef")) {
|
|
switch (mode) {
|
|
case t42FontModeUnicode:
|
|
toUnicode->mapToUnicode((CharCode)i, &u, 1);
|
|
j = (int)u;
|
|
break;
|
|
case t42FontModeCharCode:
|
|
j = i;
|
|
break;
|
|
case t42FontModeCharCodeOffset:
|
|
j = cmapOffset + i;
|
|
break;
|
|
case t42FontModeMacRoman:
|
|
j = globalParams->getMacRomanCharCode(name);
|
|
break;
|
|
}
|
|
// note: Distiller (maybe Adobe's PS interpreter in general)
|
|
// doesn't like TrueType fonts that have CharStrings entries
|
|
// which point to nonexistent glyphs, hence the (k < nGlyphs)
|
|
// test
|
|
if ((k = getCmapEntry(cmapFmt, pos, j)) > 0 &&
|
|
k < nGlyphs) {
|
|
fprintf(out, "/%s %d def\n", name, k);
|
|
}
|
|
}
|
|
}
|
|
|
|
err:
|
|
fprintf(out, "end readonly def\n");
|
|
}
|
|
|
|
int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) {
|
|
int cmapLen, cmapFirst;
|
|
int segCnt, segEnd, segStart, segDelta, segOffset;
|
|
int a, b, m, i;
|
|
|
|
switch (cmapFmt) {
|
|
case 0: // byte encoding table (Apple standard)
|
|
cmapLen = getUShort(pos + 2);
|
|
if (code >= cmapLen) {
|
|
return 0;
|
|
}
|
|
return getByte(pos + 6 + code);
|
|
|
|
case 4: // segment mapping to delta values (Microsoft standard)
|
|
segCnt = getUShort(pos + 6) / 2;
|
|
a = -1;
|
|
b = segCnt - 1;
|
|
segEnd = getUShort(pos + 14 + 2*b);
|
|
if (code > segEnd) {
|
|
// malformed font -- the TrueType spec requires the last segEnd
|
|
// to be 0xffff
|
|
return 0;
|
|
}
|
|
// invariant: seg[a].end < code <= seg[b].end
|
|
while (b - a > 1) {
|
|
m = (a + b) / 2;
|
|
segEnd = getUShort(pos + 14 + 2*m);
|
|
if (segEnd < code) {
|
|
a = m;
|
|
} else {
|
|
b = m;
|
|
}
|
|
}
|
|
segStart = getUShort(pos + 16 + 2*segCnt + 2*b);
|
|
segDelta = getUShort(pos + 16 + 4*segCnt + 2*b);
|
|
segOffset = getUShort(pos + 16 + 6*segCnt + 2*b);
|
|
if (segOffset == 0) {
|
|
i = (code + segDelta) & 0xffff;
|
|
} else {
|
|
i = getUShort(pos + 16 + 6*segCnt + 2*b +
|
|
segOffset + 2 * (code - segStart));
|
|
if (i != 0) {
|
|
i = (i + segDelta) & 0xffff;
|
|
}
|
|
}
|
|
return i;
|
|
|
|
case 6: // trimmed table mapping
|
|
cmapFirst = getUShort(pos + 6);
|
|
cmapLen = getUShort(pos + 8);
|
|
if (code < cmapFirst || code >= cmapFirst + cmapLen) {
|
|
return 0;
|
|
}
|
|
return getUShort(pos + 10 + 2*(code - cmapFirst));
|
|
|
|
default:
|
|
// shouldn't happen - this is checked earlier
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void TrueTypeFontFile::cvtSfnts(FILE *out, GString *name) {
|
|
TTFontTableHdr newTableHdrs[nT42Tables];
|
|
char tableDir[12 + nT42Tables*16];
|
|
char headTable[54];
|
|
int *origLocaTable;
|
|
char *locaTable;
|
|
int nNewTables;
|
|
Guint checksum;
|
|
int pos, glyfPos, length, glyphLength, pad;
|
|
int i, j, k;
|
|
|
|
// construct the 'head' table, zero out the font checksum
|
|
memcpy(headTable, file + seekTable("head"), 54);
|
|
headTable[8] = headTable[9] = headTable[10] = headTable[11] = (char)0;
|
|
|
|
// read the original 'loca' table and construct the new one
|
|
// (pad each glyph out to a multiple of 4 bytes)
|
|
origLocaTable = (int *)gmalloc((nGlyphs + 1) * sizeof(int));
|
|
pos = seekTable("loca");
|
|
for (i = 0; i <= nGlyphs; ++i) {
|
|
if (locaFmt) {
|
|
origLocaTable[i] = getULong(pos + 4*i);
|
|
} else {
|
|
origLocaTable[i] = 2 * getUShort(pos + 2*i);
|
|
}
|
|
}
|
|
locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
|
|
if (locaFmt) {
|
|
locaTable[0] = locaTable[1] = locaTable[2] = locaTable[3] = 0;
|
|
} else {
|
|
locaTable[0] = locaTable[1] = 0;
|
|
}
|
|
pos = 0;
|
|
for (i = 1; i <= nGlyphs; ++i) {
|
|
length = origLocaTable[i] - origLocaTable[i-1];
|
|
if (length & 3) {
|
|
length += 4 - (length & 3);
|
|
}
|
|
pos += length;
|
|
if (locaFmt) {
|
|
locaTable[4*i ] = (char)(pos >> 24);
|
|
locaTable[4*i+1] = (char)(pos >> 16);
|
|
locaTable[4*i+2] = (char)(pos >> 8);
|
|
locaTable[4*i+3] = (char) pos;
|
|
} else {
|
|
locaTable[2*i ] = (char)(pos >> 9);
|
|
locaTable[2*i+1] = (char)(pos >> 1);
|
|
}
|
|
}
|
|
|
|
// count the number of tables
|
|
nNewTables = 0;
|
|
for (i = 0; i < nT42Tables; ++i) {
|
|
if (t42Tables[i].required ||
|
|
seekTable(t42Tables[i].tag) >= 0) {
|
|
++nNewTables;
|
|
}
|
|
}
|
|
|
|
// construct the new table headers, including table checksums
|
|
// (pad each table out to a multiple of 4 bytes)
|
|
pos = 12 + nNewTables*16;
|
|
k = 0;
|
|
for (i = 0; i < nT42Tables; ++i) {
|
|
length = -1;
|
|
checksum = 0; // make gcc happy
|
|
if (i == t42HeadTable) {
|
|
length = 54;
|
|
checksum = computeTableChecksum(headTable, 54);
|
|
} else if (i == t42LocaTable) {
|
|
length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
|
|
checksum = computeTableChecksum(locaTable, length);
|
|
} else if (i == t42GlyfTable) {
|
|
length = 0;
|
|
checksum = 0;
|
|
glyfPos = seekTable("glyf");
|
|
for (j = 0; j < nGlyphs; ++j) {
|
|
glyphLength = origLocaTable[j+1] - origLocaTable[j];
|
|
pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0;
|
|
length += glyphLength + pad;
|
|
checksum += computeTableChecksum(file + glyfPos + origLocaTable[j],
|
|
glyphLength);
|
|
}
|
|
} else {
|
|
if ((j = seekTableIdx(t42Tables[i].tag)) >= 0) {
|
|
length = tableHdrs[j].length;
|
|
checksum = computeTableChecksum(file + tableHdrs[j].offset, length);
|
|
} else if (t42Tables[i].required) {
|
|
error(-1, "Embedded TrueType font is missing a required table ('%s')",
|
|
t42Tables[i].tag);
|
|
length = 0;
|
|
checksum = 0;
|
|
}
|
|
}
|
|
if (length >= 0) {
|
|
strncpy(newTableHdrs[k].tag, t42Tables[i].tag, 4);
|
|
newTableHdrs[k].checksum = checksum;
|
|
newTableHdrs[k].offset = pos;
|
|
newTableHdrs[k].length = length;
|
|
pad = (length & 3) ? 4 - (length & 3) : 0;
|
|
pos += length + pad;
|
|
++k;
|
|
}
|
|
}
|
|
|
|
// construct the table directory
|
|
tableDir[0] = 0x00; // sfnt version
|
|
tableDir[1] = 0x01;
|
|
tableDir[2] = 0x00;
|
|
tableDir[3] = 0x00;
|
|
tableDir[4] = 0; // numTables
|
|
tableDir[5] = nNewTables;
|
|
tableDir[6] = 0; // searchRange
|
|
tableDir[7] = (char)128;
|
|
tableDir[8] = 0; // entrySelector
|
|
tableDir[9] = 3;
|
|
tableDir[10] = 0; // rangeShift
|
|
tableDir[11] = (char)(16 * nNewTables - 128);
|
|
pos = 12;
|
|
for (i = 0; i < nNewTables; ++i) {
|
|
tableDir[pos ] = newTableHdrs[i].tag[0];
|
|
tableDir[pos+ 1] = newTableHdrs[i].tag[1];
|
|
tableDir[pos+ 2] = newTableHdrs[i].tag[2];
|
|
tableDir[pos+ 3] = newTableHdrs[i].tag[3];
|
|
tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24);
|
|
tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16);
|
|
tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >> 8);
|
|
tableDir[pos+ 7] = (char) newTableHdrs[i].checksum;
|
|
tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24);
|
|
tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16);
|
|
tableDir[pos+10] = (char)(newTableHdrs[i].offset >> 8);
|
|
tableDir[pos+11] = (char) newTableHdrs[i].offset;
|
|
tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24);
|
|
tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16);
|
|
tableDir[pos+14] = (char)(newTableHdrs[i].length >> 8);
|
|
tableDir[pos+15] = (char) newTableHdrs[i].length;
|
|
pos += 16;
|
|
}
|
|
|
|
// compute the font checksum and store it in the head table
|
|
checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
|
|
for (i = 0; i < nNewTables; ++i) {
|
|
checksum += newTableHdrs[i].checksum;
|
|
}
|
|
checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
|
|
headTable[ 8] = (char)(checksum >> 24);
|
|
headTable[ 9] = (char)(checksum >> 16);
|
|
headTable[10] = (char)(checksum >> 8);
|
|
headTable[11] = (char) checksum;
|
|
|
|
// start the sfnts array
|
|
if (name) {
|
|
fprintf(out, "/%s [\n", name->getCString());
|
|
} else {
|
|
fprintf(out, "/sfnts [\n");
|
|
}
|
|
|
|
// write the table directory
|
|
dumpString(tableDir, 12 + nNewTables*16, out);
|
|
|
|
// write the tables
|
|
for (i = 0; i < nNewTables; ++i) {
|
|
if (i == t42HeadTable) {
|
|
dumpString(headTable, 54, out);
|
|
} else if (i == t42LocaTable) {
|
|
length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
|
|
dumpString(locaTable, length, out);
|
|
} else if (i == t42GlyfTable) {
|
|
glyfPos = seekTable("glyf");
|
|
for (j = 0; j < nGlyphs; ++j) {
|
|
length = origLocaTable[j+1] - origLocaTable[j];
|
|
if (length > 0) {
|
|
dumpString(file + glyfPos + origLocaTable[j], length, out);
|
|
}
|
|
}
|
|
} else {
|
|
// length == 0 means the table is missing and the error was
|
|
// already reported during the construction of the table
|
|
// headers
|
|
if ((length = newTableHdrs[i].length) > 0) {
|
|
dumpString(file + seekTable(t42Tables[i].tag), length, out);
|
|
}
|
|
}
|
|
}
|
|
|
|
// end the sfnts array
|
|
fprintf(out, "] def\n");
|
|
|
|
gfree(origLocaTable);
|
|
gfree(locaTable);
|
|
}
|
|
|
|
void TrueTypeFontFile::dumpString(char *s, int length, FILE *out) {
|
|
int pad, i, j;
|
|
|
|
fprintf(out, "<");
|
|
for (i = 0; i < length; i += 32) {
|
|
for (j = 0; j < 32 && i+j < length; ++j) {
|
|
fprintf(out, "%02X", s[i+j] & 0xff);
|
|
}
|
|
if (i % (65536 - 32) == 65536 - 64) {
|
|
fprintf(out, ">\n<");
|
|
} else if (i+32 < length) {
|
|
fprintf(out, "\n");
|
|
}
|
|
}
|
|
if (length & 3) {
|
|
pad = 4 - (length & 3);
|
|
for (i = 0; i < pad; ++i) {
|
|
fprintf(out, "00");
|
|
}
|
|
}
|
|
// add an extra zero byte because the Adobe Type 42 spec says so
|
|
fprintf(out, "00>\n");
|
|
}
|
|
|
|
Guint TrueTypeFontFile::computeTableChecksum(char *data, int length) {
|
|
Guint checksum, word;
|
|
int i;
|
|
|
|
checksum = 0;
|
|
for (i = 0; i+3 < length; i += 4) {
|
|
word = ((data[i ] & 0xff) << 24) +
|
|
((data[i+1] & 0xff) << 16) +
|
|
((data[i+2] & 0xff) << 8) +
|
|
(data[i+3] & 0xff);
|
|
checksum += word;
|
|
}
|
|
if (length & 3) {
|
|
word = 0;
|
|
i = length & ~3;
|
|
switch (length & 3) {
|
|
case 3:
|
|
word |= (data[i+2] & 0xff) << 8;
|
|
case 2:
|
|
word |= (data[i+1] & 0xff) << 16;
|
|
case 1:
|
|
word |= (data[i ] & 0xff) << 24;
|
|
break;
|
|
}
|
|
checksum += word;
|
|
}
|
|
return checksum;
|
|
}
|
|
|
|
void TrueTypeFontFile::writeTTF(FILE *out) {
|
|
static char cmapTab[20] = {
|
|
0, 0, // table version number
|
|
0, 1, // number of encoding tables
|
|
0, 1, // platform ID
|
|
0, 0, // encoding ID
|
|
0, 0, 0, 12, // offset of subtable
|
|
0, 0, // subtable format
|
|
0, 1, // subtable length
|
|
0, 1, // subtable version
|
|
0, // map char 0 -> glyph 0
|
|
0 // pad to multiple of four bytes
|
|
};
|
|
static char nameTab[8] = {
|
|
0, 0, // format
|
|
0, 0, // number of name records
|
|
0, 6, // offset to start of string storage
|
|
0, 0 // pad to multiple of four bytes
|
|
};
|
|
static char postTab[32] = {
|
|
0, 1, 0, 0, // format
|
|
0, 0, 0, 0, // italic angle
|
|
0, 0, // underline position
|
|
0, 0, // underline thickness
|
|
0, 0, 0, 0, // fixed pitch
|
|
0, 0, 0, 0, // min Type 42 memory
|
|
0, 0, 0, 0, // max Type 42 memory
|
|
0, 0, 0, 0, // min Type 1 memory
|
|
0, 0, 0, 0 // max Type 1 memory
|
|
};
|
|
GBool haveCmap, haveName, havePost;
|
|
GBool dirCmap, dirName, dirPost;
|
|
int nNewTables, nAllTables, pad;
|
|
char *tableDir;
|
|
Guint t, pos;
|
|
int i, j;
|
|
|
|
// check for missing tables
|
|
haveCmap = seekTable("cmap") >= 0;
|
|
haveName = seekTable("name") >= 0;
|
|
havePost = seekTable("post") >= 0;
|
|
nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1);
|
|
if (!nNewTables) {
|
|
// none are missing - write the TTF file as is
|
|
fwrite(file, 1, len, out);
|
|
return;
|
|
}
|
|
|
|
// construct the new table directory
|
|
nAllTables = nTables + nNewTables;
|
|
tableDir = (char *)gmalloc(12 + nAllTables * 16);
|
|
memcpy(tableDir, file, 12 + nTables * 16);
|
|
tableDir[4] = (char)((nAllTables >> 8) & 0xff);
|
|
tableDir[5] = (char)(nAllTables & 0xff);
|
|
for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ;
|
|
t = 1 << (4 + i);
|
|
tableDir[6] = (char)((t >> 8) & 0xff);
|
|
tableDir[7] = (char)(t & 0xff);
|
|
tableDir[8] = (char)((i >> 8) & 0xff);
|
|
tableDir[9] = (char)(i & 0xff);
|
|
t = nAllTables * 16 - t;
|
|
tableDir[10] = (char)((t >> 8) & 0xff);
|
|
tableDir[11] = (char)(t & 0xff);
|
|
dirCmap = haveCmap;
|
|
dirName = haveName;
|
|
dirPost = havePost;
|
|
j = 0;
|
|
pad = (len & 3) ? 4 - (len & 3) : 0;
|
|
pos = len + pad + 16 * nNewTables;
|
|
for (i = 0; i < nTables; ++i) {
|
|
if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) {
|
|
tableDir[12 + 16*j ] = 'c';
|
|
tableDir[12 + 16*j + 1] = 'm';
|
|
tableDir[12 + 16*j + 2] = 'a';
|
|
tableDir[12 + 16*j + 3] = 'p';
|
|
tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
|
|
tableDir[12 + 16*j + 5] = (char)0;
|
|
tableDir[12 + 16*j + 6] = (char)0;
|
|
tableDir[12 + 16*j + 7] = (char)0;
|
|
tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
|
|
tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff);
|
|
pos += sizeof(cmapTab);
|
|
++j;
|
|
dirCmap = gTrue;
|
|
}
|
|
if (!dirName && strncmp(tableHdrs[i].tag, "name", 4) > 0) {
|
|
tableDir[12 + 16*j ] = 'n';
|
|
tableDir[12 + 16*j + 1] = 'a';
|
|
tableDir[12 + 16*j + 2] = 'm';
|
|
tableDir[12 + 16*j + 3] = 'e';
|
|
tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
|
|
tableDir[12 + 16*j + 5] = (char)0;
|
|
tableDir[12 + 16*j + 6] = (char)0;
|
|
tableDir[12 + 16*j + 7] = (char)0;
|
|
tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
|
|
tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff);
|
|
pos += sizeof(nameTab);
|
|
++j;
|
|
dirName = gTrue;
|
|
}
|
|
if (!dirName && strncmp(tableHdrs[i].tag, "post", 4) > 0) {
|
|
tableDir[12 + 16*j ] = 'p';
|
|
tableDir[12 + 16*j + 1] = 'o';
|
|
tableDir[12 + 16*j + 2] = 's';
|
|
tableDir[12 + 16*j + 3] = 't';
|
|
tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
|
|
tableDir[12 + 16*j + 5] = (char)0;
|
|
tableDir[12 + 16*j + 6] = (char)0;
|
|
tableDir[12 + 16*j + 7] = (char)0;
|
|
tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
|
|
tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff);
|
|
pos += sizeof(postTab);
|
|
++j;
|
|
dirPost = gTrue;
|
|
}
|
|
memcpy(&tableDir[12 + 16*j], file + 12 + 16*i, 16);
|
|
t = tableHdrs[i].offset + nNewTables * 16;
|
|
tableDir[12 + 16*j + 8] = (char)((t >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 9] = (char)((t >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 10] = (char)((t >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 11] = (char)( t & 0xff);
|
|
++j;
|
|
}
|
|
if (!dirCmap) {
|
|
tableDir[12 + 16*j ] = 'c';
|
|
tableDir[12 + 16*j + 1] = 'm';
|
|
tableDir[12 + 16*j + 2] = 'a';
|
|
tableDir[12 + 16*j + 3] = 'p';
|
|
tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
|
|
tableDir[12 + 16*j + 5] = (char)0;
|
|
tableDir[12 + 16*j + 6] = (char)0;
|
|
tableDir[12 + 16*j + 7] = (char)0;
|
|
tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
|
|
tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff);
|
|
pos += sizeof(cmapTab);
|
|
++j;
|
|
dirCmap = gTrue;
|
|
}
|
|
if (!dirName) {
|
|
tableDir[12 + 16*j ] = 'n';
|
|
tableDir[12 + 16*j + 1] = 'a';
|
|
tableDir[12 + 16*j + 2] = 'm';
|
|
tableDir[12 + 16*j + 3] = 'e';
|
|
tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
|
|
tableDir[12 + 16*j + 5] = (char)0;
|
|
tableDir[12 + 16*j + 6] = (char)0;
|
|
tableDir[12 + 16*j + 7] = (char)0;
|
|
tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
|
|
tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff);
|
|
pos += sizeof(nameTab);
|
|
++j;
|
|
dirName = gTrue;
|
|
}
|
|
if (!dirPost) {
|
|
tableDir[12 + 16*j ] = 'p';
|
|
tableDir[12 + 16*j + 1] = 'o';
|
|
tableDir[12 + 16*j + 2] = 's';
|
|
tableDir[12 + 16*j + 3] = 't';
|
|
tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
|
|
tableDir[12 + 16*j + 5] = (char)0;
|
|
tableDir[12 + 16*j + 6] = (char)0;
|
|
tableDir[12 + 16*j + 7] = (char)0;
|
|
tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
|
|
tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
|
|
tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
|
|
tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff);
|
|
tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff);
|
|
pos += sizeof(postTab);
|
|
++j;
|
|
dirPost = gTrue;
|
|
}
|
|
|
|
// write the table directory
|
|
fwrite(tableDir, 1, 12 + 16 * nAllTables, out);
|
|
|
|
// write the original tables
|
|
fwrite(file + 12 + 16*nTables, 1, len - (12 + 16*nTables), out);
|
|
|
|
// write the new tables
|
|
for (i = 0; i < pad; ++i) {
|
|
fputc((char)0, out);
|
|
}
|
|
if (!haveCmap) {
|
|
fwrite(cmapTab, 1, sizeof(cmapTab), out);
|
|
}
|
|
if (!haveName) {
|
|
fwrite(nameTab, 1, sizeof(nameTab), out);
|
|
}
|
|
if (!havePost) {
|
|
fwrite(postTab, 1, sizeof(postTab), out);
|
|
}
|
|
|
|
gfree(tableDir);
|
|
}
|