#pragma implementation
#endif
+#include <stdlib.h>
#include "gmem.h"
#include "Object.h"
+#include "Catalog.h"
#include "Gfx.h"
+#include "Lexer.h"
#include "Annot.h"
//------------------------------------------------------------------------
// Annot
//------------------------------------------------------------------------
-Annot::Annot(XRef *xrefA, Dict *dict) {
+Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) {
Object apObj, asObj, obj1, obj2;
+ GBool regen, isTextField;
double t;
ok = gFalse;
xref = xrefA;
-
- if (dict->lookup("AP", &apObj)->isDict()) {
- if (dict->lookup("AS", &asObj)->isName()) {
- if (apObj.dictLookup("N", &obj1)->isDict()) {
- if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) {
- obj2.copy(&appearance);
- ok = gTrue;
- }
- obj2.free();
- }
- obj1.free();
- } else {
- if (apObj.dictLookupNF("N", &obj1)->isRef()) {
- obj1.copy(&appearance);
- ok = gTrue;
- }
- obj1.free();
- }
- asObj.free();
- }
- apObj.free();
+ appearBuf = NULL;
if (dict->lookup("Rect", &obj1)->isArray() &&
obj1.arrayGetLength() == 4) {
xMax = yMax = 1;
}
obj1.free();
+
+ // check if field apperances need to be regenerated
+ regen = gFalse;
+ if (acroForm) {
+ acroForm->lookup("NeedAppearances", &obj1);
+ if (obj1.isBool() && obj1.getBool()) {
+ regen = gTrue;
+ }
+ obj1.free();
+ }
+
+ // check for a text-type field
+ isTextField = dict->lookup("FT", &obj1)->isName("Tx");
+ obj1.free();
+
+#if 0 //~ appearance stream generation is not finished yet
+ if (regen && isTextField) {
+ generateAppearance(acroForm, dict);
+ } else {
+#endif
+ if (dict->lookup("AP", &apObj)->isDict()) {
+ if (dict->lookup("AS", &asObj)->isName()) {
+ if (apObj.dictLookup("N", &obj1)->isDict()) {
+ if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) {
+ obj2.copy(&appearance);
+ ok = gTrue;
+ } else {
+ obj2.free();
+ if (obj1.dictLookupNF("Off", &obj2)->isRef()) {
+ obj2.copy(&appearance);
+ ok = gTrue;
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ } else {
+ if (apObj.dictLookupNF("N", &obj1)->isRef()) {
+ obj1.copy(&appearance);
+ ok = gTrue;
+ }
+ obj1.free();
+ }
+ asObj.free();
+ }
+ apObj.free();
+#if 0 //~ appearance stream generation is not finished yet
+ }
+#endif
}
Annot::~Annot() {
appearance.free();
+ if (appearBuf) {
+ delete appearBuf;
+ }
+}
+
+void Annot::generateAppearance(Dict *acroForm, Dict *dict) {
+ MemStream *appearStream;
+ Object daObj, vObj, drObj, appearDict, obj1, obj2;
+ GString *daStr, *daStr1, *vStr, *s;
+ char buf[256];
+ double fontSize;
+ int c;
+ int i0, i1;
+
+ //~ DA can be inherited
+ if (dict->lookup("DA", &daObj)->isString()) {
+ daStr = daObj.getString();
+
+ // look for a font size
+ //~ may want to parse the DS entry in place of this (if it exists)
+ daStr1 = NULL;
+ fontSize = 10;
+ for (i1 = daStr->getLength() - 2; i1 >= 0; --i1) {
+ if (daStr->getChar(i1) == 'T' && daStr->getChar(i1+1) == 'f') {
+ for (--i1; i1 >= 0 && Lexer::isSpace(daStr->getChar(i1)); --i1) ;
+ for (i0 = i1; i0 >= 0 && !Lexer::isSpace(daStr->getChar(i0)); --i0) ;
+ if (i0 >= 0) {
+ ++i0;
+ ++i1;
+ s = new GString(daStr, i0, i1 - i0);
+ fontSize = atof(s->getCString());
+ delete s;
+
+ // autosize the font
+ if (fontSize == 0) {
+ fontSize = 0.67 * (yMax - yMin);
+ daStr1 = new GString(daStr, 0, i0);
+ sprintf(buf, "%.2f", fontSize);
+ daStr1->append(buf);
+ daStr1->append(daStr->getCString() + i1,
+ daStr->getLength() - i1);
+ }
+ }
+ break;
+ }
+ }
+
+ // build the appearance stream contents
+ appearBuf = new GString();
+ appearBuf->append("/Tx BMC\n");
+ appearBuf->append("q BT\n");
+ appearBuf->append(daStr1 ? daStr1 : daStr)->append("\n");
+ if (dict->lookup("V", &vObj)->isString()) {
+ //~ handle quadding -- this requires finding the font and using
+ //~ the encoding and char widths
+ sprintf(buf, "1 0 0 1 %.2f %.2f Tm\n", 2.0, yMax - yMin - fontSize);
+ appearBuf->append(buf);
+ sprintf(buf, "%g TL\n", fontSize);
+ appearBuf->append(buf);
+ vStr = vObj.getString();
+ i0 = 0;
+ while (i0 < vStr->getLength()) {
+ for (i1 = i0;
+ i1 < vStr->getLength() &&
+ vStr->getChar(i1) != '\n' && vStr->getChar(i1) != '\r';
+ ++i1) ;
+ if (i0 > 0) {
+ appearBuf->append("T*\n");
+ }
+ appearBuf->append('(');
+ for (; i0 < i1; ++i0) {
+ c = vStr->getChar(i0);
+ if (c == '(' || c == ')' || c == '\\') {
+ appearBuf->append('\\');
+ appearBuf->append(c);
+ } else if (c < 0x20 || c >= 0x80) {
+ sprintf(buf, "\\%03o", c);
+ appearBuf->append(buf);
+ } else {
+ appearBuf->append(c);
+ }
+ }
+ appearBuf->append(") Tj\n");
+ if (i1 + 1 < vStr->getLength() &&
+ vStr->getChar(i1) == '\r' && vStr->getChar(i1 + 1) == '\n') {
+ i0 = i1 + 2;
+ } else {
+ i0 = i1 + 1;
+ }
+ }
+ }
+ vObj.free();
+ appearBuf->append("ET Q\n");
+ appearBuf->append("EMC\n");
+
+ // build the appearance stream dictionary
+ appearDict.initDict(xref);
+ appearDict.dictAdd(copyString("Length"),
+ obj1.initInt(appearBuf->getLength()));
+ appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
+ obj1.initArray(xref);
+ obj1.arrayAdd(obj2.initReal(0));
+ obj1.arrayAdd(obj2.initReal(0));
+ obj1.arrayAdd(obj2.initReal(xMax - xMin));
+ obj1.arrayAdd(obj2.initReal(yMax - yMin));
+ appearDict.dictAdd(copyString("BBox"), &obj1);
+
+ // find the resource dictionary
+ dict->lookup("DR", &drObj);
+ if (!drObj.isDict()) {
+ dict->lookup("Parent", &obj1);
+ while (obj1.isDict()) {
+ drObj.free();
+ obj1.dictLookup("DR", &drObj);
+ if (drObj.isDict()) {
+ break;
+ }
+ obj1.dictLookup("Parent", &obj2);
+ obj1.free();
+ obj1 = obj2;
+ }
+ obj1.free();
+ if (!drObj.isDict()) {
+ if (acroForm) {
+ drObj.free();
+ acroForm->lookup("DR", &drObj);
+ }
+ }
+ }
+ if (drObj.isDict()) {
+ appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1));
+ }
+ drObj.free();
+
+ // build the appearance stream
+ appearStream = new MemStream(appearBuf->getCString(), 0,
+ appearBuf->getLength(), &appearDict);
+ appearance.initStream(appearStream);
+ ok = gTrue;
+
+ if (daStr1) {
+ delete daStr1;
+ }
+ }
+ daObj.free();
}
void Annot::draw(Gfx *gfx) {
// Annots
//------------------------------------------------------------------------
-Annots::Annots(XRef *xref, Object *annotsObj) {
+Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) {
+ Dict *acroForm;
Annot *annot;
Object obj1;
int size;
size = 0;
nAnnots = 0;
+ acroForm = catalog->getAcroForm()->isDict() ?
+ catalog->getAcroForm()->getDict() : NULL;
if (annotsObj->isArray()) {
for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
if (annotsObj->arrayGet(i, &obj1)->isDict()) {
- annot = new Annot(xref, obj1.getDict());
+ annot = new Annot(xref, acroForm, obj1.getDict());
if (annot->isOk()) {
if (nAnnots >= size) {
size += 16;
- annots = (Annot **)grealloc(annots, size * sizeof(Annot *));
+ annots = (Annot **)greallocn(annots, size, sizeof(Annot *));
}
annots[nAnnots++] = annot;
} else {
#endif
class XRef;
+class Catalog;
class Gfx;
//------------------------------------------------------------------------
class Annot {
public:
- Annot(XRef *xrefA, Dict *dict);
+ Annot(XRef *xrefA, Dict *acroForm, Dict *dict);
~Annot();
GBool isOk() { return ok; }
Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); }
private:
+
+ void generateAppearance(Dict *acroForm, Dict *dict);
XRef *xref; // the xref table for this PDF file
Object appearance; // a reference to the Form XObject stream
// for the normal appearance
+ GString *appearBuf;
double xMin, yMin, // annotation rectangle
xMax, yMax;
GBool ok;
public:
// Extract non-link annotations from array of annotations.
- Annots(XRef *xref, Object *annotsObj);
+ Annots(XRef *xref, Catalog *catalog, Object *annotsObj);
~Annots();
} else {
size *= 2;
}
- elems = (Object *)grealloc(elems, size * sizeof(Object));
+ elems = (Object *)greallocn(elems, size, sizeof(Object));
}
elems[length] = *elem;
++length;
int i, h;
size = sizeA;
- tab = (BuiltinFontWidth **)gmalloc(size * sizeof(BuiltinFontWidth *));
+ tab = (BuiltinFontWidth **)gmallocn(size, sizeof(BuiltinFontWidth *));
for (i = 0; i < size; ++i) {
tab[i] = NULL;
}
PSTokenizer *pst;
char tok1[256], tok2[256], tok3[256];
int n1, n2, n3;
- Guint start, end;
+ Guint start, end, code;
if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
}
}
pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "begincidchar")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endcidchar")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endcidchar")) {
+ error(-1, "Illegal entry in cidchar block in CMap");
+ break;
+ }
+ if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ n1 >= 4 && (n1 & 1) == 0)) {
+ error(-1, "Illegal entry in cidchar block in CMap");
+ continue;
+ }
+ tok1[n1 - 1] = '\0';
+ if (sscanf(tok1 + 1, "%x", &code) != 1) {
+ error(-1, "Illegal entry in cidchar block in CMap");
+ continue;
+ }
+ n1 = (n1 - 2) / 2;
+ cmap->addCIDs(code, code, n1, (CID)atoi(tok2));
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
} else if (!strcmp(tok2, "begincidrange")) {
while (pst->getToken(tok1, sizeof(tok1), &n1)) {
if (!strcmp(tok1, "endcidrange")) {
collection = collectionA;
cMapName = cMapNameA;
wMode = 0;
- vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
+ vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
for (i = 0; i < 256; ++i) {
vector[i].isVector = gFalse;
vector[i].cid = 0;
if (!dest[i].isVector) {
dest[i].isVector = gTrue;
dest[i].vector =
- (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
+ (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
for (j = 0; j < 256; ++j) {
dest[i].vector[j].isVector = gFalse;
dest[i].vector[j].cid = 0;
if (!vec[i].isVector) {
vec[i].isVector = gTrue;
vec[i].vector =
- (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
+ (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
for (j = 0; j < 256; ++j) {
vec[i].vector[j].isVector = gFalse;
vec[i].vector[j].cid = 0;
for (i = nBytes - 1; i >= 1; --i) {
byte = (start >> (8 * i)) & 0xff;
if (!vec[byte].isVector) {
- error(-1, "Invalid CID (%*x - %*x) in CMap",
+ error(-1, "Invalid CID (%0*x - %0*x) in CMap",
2*nBytes, start, 2*nBytes, end);
return;
}
cid = firstCID;
for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
if (vec[byte].isVector) {
- error(-1, "Invalid CID (%*x - %*x) in CMap",
+ error(-1, "Invalid CID (%0*x - %0*x) in CMap",
2*nBytes, start, 2*nBytes, end);
} else {
vec[byte].cid = cid;
CMapVectorEntry *vector; // vector for first byte (NULL for
// identity CMap)
int refCnt;
-#ifdef MULTITHREADED
+#if MULTITHREADED
GMutex mutex;
#endif
};
}
pagesSize = numPages0 = (int)obj.getNum();
obj.free();
- pages = (Page **)gmalloc(pagesSize * sizeof(Page *));
- pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref));
+ pages = (Page **)gmallocn(pagesSize, sizeof(Page *));
+ pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref));
for (i = 0; i < pagesSize; ++i) {
pages[i] = NULL;
pageRefs[i].num = -1;
// get the outline dictionary
catDict.dictLookup("Outlines", &outline);
+ // get the AcroForm dictionary
+ catDict.dictLookup("AcroForm", &acroForm);
+
catDict.free();
return;
metadata.free();
structTreeRoot.free();
outline.free();
+ acroForm.free();
}
GString *Catalog::readMetadata() {
}
if (start >= pagesSize) {
pagesSize += 32;
- pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *));
- pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref));
+ pages = (Page **)greallocn(pages, pagesSize, sizeof(Page *));
+ pageRefs = (Ref *)greallocn(pageRefs, pagesSize, sizeof(Ref));
for (j = pagesSize - 32; j < pagesSize; ++j) {
pages[j] = NULL;
pageRefs[j].num = -1;
} else {
error(-1, "Kid object (page %d) is wrong type (%s)",
start+1, kid.getTypeName());
- goto err2;
}
kid.free();
}
Object *getOutline() { return &outline; }
+ Object *getAcroForm() { return &acroForm; }
+
private:
XRef *xref; // the xref table for this PDF file
Object metadata; // metadata stream
Object structTreeRoot; // structure tree root dictionary
Object outline; // outline dictionary
+ Object acroForm; // AcroForm dictionary
GBool ok; // true if catalog is valid
int readPageTree(Dict *pages, PageAttrs *attrs, int start);
}
size = 32768;
- mapA = (Unicode *)gmalloc(size * sizeof(Unicode));
+ mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
mapLenA = 0;
while (getLine(buf, sizeof(buf), f)) {
if (mapLenA == size) {
size *= 2;
- mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode));
+ mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
}
if (sscanf(buf, "%x", &u) == 1) {
mapA[mapLenA] = u;
}
size = 4096;
- mapA = (Unicode *)gmalloc(size * sizeof(Unicode));
+ mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
memset(mapA, 0, size * sizeof(Unicode));
len = 0;
sMapA = NULL;
while (u0 >= size) {
size *= 2;
}
- mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode));
+ mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode));
}
if (n == 1) {
if (sMapLenA == sMapSizeA) {
sMapSizeA += 16;
sMapA = (CharCodeToUnicodeString *)
- grealloc(sMapA, sMapSizeA * sizeof(CharCodeToUnicodeString));
+ greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString));
}
sMapA[sMapLenA].c = u0;
for (i = 0; i < n; ++i) {
error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
continue;
}
- addMapping(code1, tok2 + 1, n2 - 1, 0);
+ addMapping(code1, tok2 + 1, n2 - 2, 0);
}
pst->getToken(tok1, sizeof(tok1), &n1);
} else if (!strcmp(tok2, "beginbfrange")) {
if (code >= mapLen) {
oldLen = mapLen;
mapLen = (code + 256) & ~255;
- map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode));
+ map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode));
for (i = oldLen; i < mapLen; ++i) {
map[i] = 0;
}
if (sMapLen >= sMapSize) {
sMapSize = sMapSize + 16;
sMap = (CharCodeToUnicodeString *)
- grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString));
+ greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
}
map[code] = 0;
sMap[sMapLen].c = code;
tag = tagA;
mapLen = 256;
- map = (Unicode *)gmalloc(mapLen * sizeof(Unicode));
+ map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
for (i = 0; i < mapLen; ++i) {
map[i] = 0;
}
tag = tagA;
mapLen = mapLenA;
if (copyMap) {
- map = (Unicode *)gmalloc(mapLen * sizeof(Unicode));
+ map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
memcpy(map, mapA, mapLen * sizeof(Unicode));
} else {
map = mapA;
}
void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) {
- int i;
+ int i, j;
if (len == 1) {
map[c] = u[0];
} else {
- map[c] = 0;
- if (sMapLen == sMapSize) {
- sMapSize += 8;
- sMap = (CharCodeToUnicodeString *)
- grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString));
+ for (i = 0; i < sMapLen; ++i) {
+ if (sMap[i].c == c) {
+ break;
+ }
}
- sMap[sMapLen].c = c;
- sMap[sMapLen].len = len;
- for (i = 0; i < len && i < maxUnicodeString; ++i) {
- sMap[sMapLen].u[i] = u[i];
+ if (i == sMapLen) {
+ if (sMapLen == sMapSize) {
+ sMapSize += 8;
+ sMap = (CharCodeToUnicodeString *)
+ greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+ }
+ ++sMapLen;
+ }
+ map[c] = 0;
+ sMap[i].c = c;
+ sMap[i].len = len;
+ for (j = 0; j < len && j < maxUnicodeString; ++j) {
+ sMap[i].u[j] = u[j];
}
- ++sMapLen;
}
}
int i;
size = sizeA;
- cache = (CharCodeToUnicode **)gmalloc(size * sizeof(CharCodeToUnicode *));
+ cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *));
for (i = 0; i < size; ++i) {
cache[i] = NULL;
}
// Map a CharCode to Unicode.
int mapToUnicode(CharCode c, Unicode *u, int size);
+ // Return the mapping's length, i.e., one more than the max char
+ // code supported by the mapping.
+ CharCode getLength() { return mapLen; }
+
private:
void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits);
CharCodeToUnicodeString *sMap;
int sMapLen, sMapSize;
int refCnt;
-#ifdef MULTITHREADED
+#if MULTITHREADED
GMutex mutex;
#endif
};
#pragma implementation
#endif
+#include <string.h>
#include "gmem.h"
#include "Decrypt.h"
GString *ownerKey, GString *userKey,
int permissions, GString *fileID,
GString *ownerPassword, GString *userPassword,
- Guchar *fileKey, GBool *ownerPasswordOk) {
+ Guchar *fileKey, GBool encryptMetadata,
+ GBool *ownerPasswordOk) {
Guchar test[32], test2[32];
GString *userPassword2;
Guchar fState[256];
}
userPassword2 = new GString((char *)test2, 32);
if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
- permissions, fileID, userPassword2, fileKey)) {
+ permissions, fileID, userPassword2, fileKey,
+ encryptMetadata)) {
*ownerPasswordOk = gTrue;
delete userPassword2;
return gTrue;
// try using the supplied user password
return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
- permissions, fileID, userPassword, fileKey);
+ permissions, fileID, userPassword, fileKey,
+ encryptMetadata);
}
GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength,
GString *ownerKey, GString *userKey,
int permissions, GString *fileID,
- GString *userPassword, Guchar *fileKey) {
+ GString *userPassword, Guchar *fileKey,
+ GBool encryptMetadata) {
Guchar *buf;
Guchar test[32];
Guchar fState[256];
GBool ok;
// generate file key
- buf = (Guchar *)gmalloc(68 + fileID->getLength());
+ buf = (Guchar *)gmalloc(72 + fileID->getLength());
if (userPassword) {
len = userPassword->getLength();
if (len < 32) {
buf[66] = (permissions >> 16) & 0xff;
buf[67] = (permissions >> 24) & 0xff;
memcpy(buf + 68, fileID->getCString(), fileID->getLength());
- md5(buf, 68 + fileID->getLength(), fileKey);
+ len = 68 + fileID->getLength();
+ if (!encryptMetadata) {
+ buf[len++] = 0xff;
+ buf[len++] = 0xff;
+ buf[len++] = 0xff;
+ buf[len++] = 0xff;
+ }
+ md5(buf, len, fileKey);
if (encRevision == 3) {
for (i = 0; i < 50; ++i) {
md5(fileKey, keyLength, fileKey);
GString *ownerKey, GString *userKey,
int permissions, GString *fileID,
GString *ownerPassword, GString *userPassword,
- Guchar *fileKey, GBool *ownerPasswordOk);
+ Guchar *fileKey, GBool encryptMetadata,
+ GBool *ownerPasswordOk);
private:
static GBool makeFileKey2(int encVersion, int encRevision, int keyLength,
GString *ownerKey, GString *userKey,
int permissions, GString *fileID,
- GString *userPassword, Guchar *fileKey);
+ GString *userPassword, Guchar *fileKey,
+ GBool encryptMetadata);
int objKeyLength;
Guchar objKey[21];
} else {
size *= 2;
}
- entries = (DictEntry *)grealloc(entries, size * sizeof(DictEntry));
+ entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry));
}
entries[length].key = key;
entries[length].val = *val;
#endif
#include <stdlib.h>
+#include <string.h>
#include "gtypes.h"
#include "gmem.h"
#include "GString.h"
//------------------------------------------------------------------------
+#define ttcfTag 0x74746366
+
+//------------------------------------------------------------------------
+
struct TrueTypeTable {
Guint tag;
Guint checksum;
#define cmapTag 0x636d6170
#define glyfTag 0x676c7966
+#define headTag 0x68656164
#define locaTag 0x6c6f6361
#define nameTag 0x6e616d65
#define postTag 0x706f7374
{ "vhea", gFalse },
{ "vmtx", gFalse }
};
-#define t42HeadTable 3
-#define t42LocaTable 6
-#define t42GlyfTable 2
+#define t42HeadTable 3
+#define t42LocaTable 6
+#define t42GlyfTable 2
+#define t42VheaTable 9
+#define t42VmtxTable 10
//------------------------------------------------------------------------
FoFiTrueType::~FoFiTrueType() {
gfree(tables);
gfree(cmaps);
- delete nameToGID;
+ if (nameToGID) {
+ delete nameToGID;
+ }
}
int FoFiTrueType::getNumCmaps() {
// write the guts of the dictionary
cvtEncoding(encoding, outputFunc, outputStream);
cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
- cvtSfnts(outputFunc, outputStream, NULL);
+ cvtSfnts(outputFunc, outputStream, NULL, gFalse);
// end the dictionary and define the font
(*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
void FoFiTrueType::convertToCIDType2(char *psName,
Gushort *cidMap, int nCIDs,
+ GBool needVerticalMetrics,
FoFiOutputFunc outputFunc,
void *outputStream) {
char buf[512];
(*outputFunc)(outputStream, " end readonly def\n", 19);
// write the guts of the dictionary
- cvtSfnts(outputFunc, outputStream, NULL);
+ cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics);
// end the dictionary and define the font
(*outputFunc)(outputStream,
}
void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
+ GBool needVerticalMetrics,
FoFiOutputFunc outputFunc,
void *outputStream) {
char buf[512];
// write the Type 42 sfnts array
sfntsName = (new GString(psName))->append("_sfnts");
- cvtSfnts(outputFunc, outputStream, sfntsName);
+ cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics);
delete sfntsName;
// write the descendant Type 42 fonts
}
void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
- void *outputStream) {
- static char cmapTab[20] = {
+ void *outputStream, char *name,
+ Gushort *codeToGID) {
+ // this substitute cmap table maps char codes 0000-ffff directly to
+ // glyphs 0000-ffff
+ static char cmapTab[36] = {
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
+ 0, 4, // subtable format
+ 0, 24, // subtable length
+ 0, 0, // subtable version
+ 0, 2, // segment count * 2
+ 0, 2, // 2 * 2 ^ floor(log2(segCount))
+ 0, 0, // floor(log2(segCount))
+ 0, 0, // 2*segCount - 2*2^floor(log2(segCount))
+ (char)0xff, (char)0xff, // endCount[0]
+ 0, 0, // reserved
+ 0, 0, // startCount[0]
+ 0, 0, // idDelta[0]
+ 0, 0 // pad to a mulitple of four bytes
};
static char nameTab[8] = {
0, 0, // format
int nZeroLengthTables;
TrueTypeLoca *locaTable;
TrueTypeTable *newTables;
- int nNewTables, cmapIdx, cmapLen, glyfLen;
+ char *newNameTab, *newCmapTab;
+ int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
+ Guint locaChecksum, glyfChecksum, fileChecksum;
char *tableDir;
- char locaBuf[4];
+ char locaBuf[4], checksumBuf[4];
GBool ok;
Guint t;
int pos, i, j, k, n;
missingPost = seekTable("post") < 0;
// read the loca table, check to see if it's sorted
- locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca));
+ locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
unsortedLoca = gFalse;
i = seekTable("loca");
pos = tables[i].offset;
// if nothing is broken, just write the TTF file as is
if (!missingCmap && !missingName && !missingPost && !unsortedLoca &&
- !badCmapLen && nZeroLengthTables == 0) {
+ !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) {
(*outputFunc)(outputStream, (char *)file, len);
goto done1;
}
glyfLen = pos;
}
+ // compute checksums for the loca and glyf tables
+ locaChecksum = glyfChecksum = 0;
+ if (unsortedLoca) {
+ if (locaFmt) {
+ for (j = 0; j <= nGlyphs; ++j) {
+ locaChecksum += locaTable[j].newOffset;
+ }
+ } else {
+ for (j = 0; j <= nGlyphs; j += 2) {
+ locaChecksum += locaTable[j].newOffset << 16;
+ if (j + 1 <= nGlyphs) {
+ locaChecksum += locaTable[j+1].newOffset;
+ }
+ }
+ }
+ pos = tables[seekTable("glyf")].offset;
+ for (j = 0; j < nGlyphs; ++j) {
+ n = locaTable[j].len;
+ if (n > 0) {
+ k = locaTable[j].origOffset;
+ if (checkRegion(pos + k, n)) {
+ glyfChecksum += computeTableChecksum(file + pos + k, n);
+ }
+ }
+ }
+ }
+
+ // construct the new name table
+ if (name) {
+ n = strlen(name);
+ newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3;
+ newNameTab = (char *)gmalloc(newNameLen);
+ memset(newNameTab, 0, newNameLen);
+ newNameTab[0] = 0; // format selector
+ newNameTab[1] = 0;
+ newNameTab[2] = 0; // number of name records
+ newNameTab[3] = 4;
+ newNameTab[4] = 0; // offset to start of string storage
+ newNameTab[5] = 6 + 4*12;
+ next = 0;
+ for (i = 0; i < 4; ++i) {
+ newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft
+ newNameTab[6 + i*12 + 1] = 3;
+ newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode
+ newNameTab[6 + i*12 + 3] = 1;
+ newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English
+ newNameTab[6 + i*12 + 5] = 0x09;
+ newNameTab[6 + i*12 + 6] = 0; // name ID
+ newNameTab[6 + i*12 + 7] = i + 1;
+ newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length
+ newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff);
+ newNameTab[6 + i*12 + 10] = next >> 8; // string offset
+ newNameTab[6 + i*12 + 11] = next & 0xff;
+ if (i+1 == 2) {
+ memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14);
+ next += 14;
+ } else {
+ for (j = 0; j < n; ++j) {
+ newNameTab[6 + 4*12 + next + 2*j] = 0;
+ newNameTab[6 + 4*12 + next + 2*j + 1] = name[j];
+ }
+ next += 2*n;
+ }
+ }
+ } else {
+ newNameLen = 0;
+ newNameTab = NULL;
+ }
+
+ // construct the new cmap table
+ if (codeToGID) {
+ newCmapLen = 44 + 256 * 2;
+ newCmapTab = (char *)gmalloc(newCmapLen);
+ newCmapTab[0] = 0; // table version number = 0
+ newCmapTab[1] = 0;
+ newCmapTab[2] = 0; // number of encoding tables = 1
+ newCmapTab[3] = 1;
+ newCmapTab[4] = 0; // platform ID = Microsoft
+ newCmapTab[5] = 3;
+ newCmapTab[6] = 0; // encoding ID = Unicode
+ newCmapTab[7] = 1;
+ newCmapTab[8] = 0; // offset of subtable
+ newCmapTab[9] = 0;
+ newCmapTab[10] = 0;
+ newCmapTab[11] = 12;
+ newCmapTab[12] = 0; // subtable format = 4
+ newCmapTab[13] = 4;
+ newCmapTab[14] = 0x02; // subtable length
+ newCmapTab[15] = 0x20;
+ newCmapTab[16] = 0; // subtable version = 0
+ newCmapTab[17] = 0;
+ newCmapTab[18] = 0; // segment count * 2
+ newCmapTab[19] = 4;
+ newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount))
+ newCmapTab[21] = 4;
+ newCmapTab[22] = 0; // floor(log2(segCount))
+ newCmapTab[23] = 1;
+ newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount))
+ newCmapTab[25] = 0;
+ newCmapTab[26] = 0x00; // endCount[0]
+ newCmapTab[27] = (char)0xff;
+ newCmapTab[28] = (char)0xff; // endCount[1]
+ newCmapTab[29] = (char)0xff;
+ newCmapTab[30] = 0; // reserved
+ newCmapTab[31] = 0;
+ newCmapTab[32] = 0x00; // startCount[0]
+ newCmapTab[33] = 0x00;
+ newCmapTab[34] = (char)0xff; // startCount[1]
+ newCmapTab[35] = (char)0xff;
+ newCmapTab[36] = 0; // idDelta[0]
+ newCmapTab[37] = 0;
+ newCmapTab[38] = 0; // idDelta[1]
+ newCmapTab[39] = 1;
+ newCmapTab[40] = 0; // idRangeOffset[0]
+ newCmapTab[41] = 4;
+ newCmapTab[42] = 0; // idRangeOffset[1]
+ newCmapTab[43] = 0;
+ for (i = 0; i < 256; ++i) {
+ newCmapTab[44 + 2*i] = codeToGID[i] >> 8;
+ newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff;
+ }
+ } else {
+ newCmapLen = 0;
+ newCmapTab = NULL;
+ }
+
// construct the new table directory:
// - keep all original tables with non-zero length
// - fix the cmap table's length, if necessary
// - add missing tables
// - sort the table by tag
// - compute new table positions, including 4-byte alignment
+ // - (re)compute table checksums
nNewTables = nTables - nZeroLengthTables +
(missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
(missingPost ? 1 : 0);
- newTables = (TrueTypeTable *)gmalloc(nNewTables * sizeof(TrueTypeTable));
+ newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
j = 0;
for (i = 0; i < nTables; ++i) {
if (tables[i].len > 0) {
newTables[j] = tables[i];
newTables[j].origOffset = tables[i].offset;
- if (newTables[j].tag == cmapTag && badCmapLen) {
+ if (checkRegion(tables[i].offset, newTables[i].len)) {
+ newTables[j].checksum =
+ computeTableChecksum(file + tables[i].offset, tables[i].len);
+ if (tables[i].tag == headTag) {
+ // don't include the file checksum
+ newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok);
+ }
+ }
+ if (newTables[j].tag == cmapTag && codeToGID) {
+ newTables[j].len = newCmapLen;
+ newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
+ newCmapLen);
+ } else if (newTables[j].tag == cmapTag && badCmapLen) {
newTables[j].len = cmapLen;
} else if (newTables[j].tag == locaTag && unsortedLoca) {
newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+ newTables[j].checksum = locaChecksum;
} else if (newTables[j].tag == glyfTag && unsortedLoca) {
newTables[j].len = glyfLen;
+ newTables[j].checksum = glyfChecksum;
+ } else if (newTables[j].tag == nameTag && name) {
+ newTables[j].len = newNameLen;
+ newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
+ newNameLen);
}
++j;
}
}
if (missingCmap) {
newTables[j].tag = cmapTag;
- newTables[j].checksum = 0; //~ should compute the checksum
- newTables[j].len = sizeof(cmapTab);
+ if (codeToGID) {
+ newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
+ newCmapLen);
+ newTables[j].len = newCmapLen;
+ } else {
+ newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab,
+ sizeof(cmapTab));
+ newTables[j].len = sizeof(cmapTab);
+ }
++j;
}
if (missingName) {
newTables[j].tag = nameTag;
- newTables[j].checksum = 0; //~ should compute the checksum
- newTables[j].len = sizeof(nameTab);
+ if (name) {
+ newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
+ newNameLen);
+ newTables[j].len = newNameLen;
+ } else {
+ newTables[j].checksum = computeTableChecksum((Guchar *)nameTab,
+ sizeof(nameTab));
+ newTables[j].len = sizeof(nameTab);
+ }
++j;
}
if (missingPost) {
newTables[j].tag = postTag;
- newTables[j].checksum = 0; //~ should compute the checksum
+ newTables[j].checksum = computeTableChecksum((Guchar *)postTab,
+ sizeof(postTab));
newTables[j].len = sizeof(postTab);
++j;
}
}
(*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
+ // compute the file checksum
+ fileChecksum = computeTableChecksum((Guchar *)tableDir,
+ 12 + nNewTables * 16);
+ for (i = 0; i < nNewTables; ++i) {
+ fileChecksum += newTables[i].checksum;
+ }
+ fileChecksum = 0xb1b0afba - fileChecksum;
+
// write the tables
for (i = 0; i < nNewTables; ++i) {
- if (newTables[i].tag == cmapTag && missingCmap) {
+ if (newTables[i].tag == headTag) {
+ if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
+ (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8);
+ checksumBuf[0] = fileChecksum >> 24;
+ checksumBuf[1] = fileChecksum >> 16;
+ checksumBuf[2] = fileChecksum >> 8;
+ checksumBuf[3] = fileChecksum;
+ (*outputFunc)(outputStream, checksumBuf, 4);
+ (*outputFunc)(outputStream,
+ (char *)file + newTables[i].origOffset + 12,
+ newTables[i].len - 12);
+ } else {
+ for (j = 0; j < newTables[i].len; ++j) {
+ (*outputFunc)(outputStream, "\0", 1);
+ }
+ }
+ } else if (newTables[i].tag == cmapTag && codeToGID) {
+ (*outputFunc)(outputStream, newCmapTab, newTables[i].len);
+ } else if (newTables[i].tag == cmapTag && missingCmap) {
(*outputFunc)(outputStream, cmapTab, newTables[i].len);
+ } else if (newTables[i].tag == nameTag && name) {
+ (*outputFunc)(outputStream, newNameTab, newTables[i].len);
} else if (newTables[i].tag == nameTag && missingName) {
(*outputFunc)(outputStream, nameTab, newTables[i].len);
} else if (newTables[i].tag == postTag && missingPost) {
}
}
+ gfree(newCmapTab);
+ gfree(newNameTab);
gfree(tableDir);
gfree(newTables);
done1:
}
void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
- void *outputStream, GString *name) {
+ void *outputStream, GString *name,
+ GBool needVerticalMetrics) {
Guchar headData[54];
TrueTypeLoca *locaTable;
Guchar *locaData;
Guint checksum;
int nNewTables;
int length, pos, glyfPos, i, j, k;
+ Guchar vheaTab[36] = {
+ 0, 1, 0, 0, // table version number
+ 0, 0, // ascent
+ 0, 0, // descent
+ 0, 0, // reserved
+ 0, 0, // max advance height
+ 0, 0, // min top side bearing
+ 0, 0, // min bottom side bearing
+ 0, 0, // y max extent
+ 0, 0, // caret slope rise
+ 0, 1, // caret slope run
+ 0, 0, // caret offset
+ 0, 0, // reserved
+ 0, 0, // reserved
+ 0, 0, // reserved
+ 0, 0, // reserved
+ 0, 0, // metric data format
+ 0, 1 // number of advance heights in vmtx table
+ };
+ Guchar *vmtxTab;
+ GBool needVhea, needVmtx;
+ int advance;
// construct the 'head' table, zero out the font checksum
i = seekTable("head");
// table, cmpTrueTypeLocaPos uses offset as its primary sort key,
// and idx as its secondary key (ensuring that adjacent entries with
// the same pos value remain in the same order)
- locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca));
+ locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
i = seekTable("loca");
pos = tables[i].offset;
ok = gTrue;
}
// construct the new 'loca' table
- locaData = (Guchar *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
+ locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2));
for (i = 0; i <= nGlyphs; ++i) {
pos = locaTable[i].newOffset;
if (locaFmt) {
++nNewTables;
}
}
+ vmtxTab = NULL; // make gcc happy
+ advance = 0; // make gcc happy
+ if (needVerticalMetrics) {
+ needVhea = seekTable("vhea") < 0;
+ needVmtx = seekTable("vmtx") < 0;
+ if (needVhea || needVmtx) {
+ i = seekTable("head");
+ advance = getU16BE(tables[i].offset + 18, &ok); // units per em
+ if (needVhea) {
+ ++nNewTables;
+ }
+ if (needVmtx) {
+ ++nNewTables;
+ }
+ }
+ }
// construct the new table headers, including table checksums
// (pad each table out to a multiple of 4 bytes)
if (checkRegion(tables[j].offset, length)) {
checksum = computeTableChecksum(file + tables[j].offset, length);
}
+ } else if (needVerticalMetrics && i == t42VheaTable) {
+ vheaTab[10] = advance / 256; // max advance height
+ vheaTab[11] = advance % 256;
+ length = sizeof(vheaTab);
+ checksum = computeTableChecksum(vheaTab, length);
+ } else if (needVerticalMetrics && i == t42VmtxTable) {
+ length = 4 + (nGlyphs - 1) * 4;
+ vmtxTab = (Guchar *)gmalloc(length);
+ vmtxTab[0] = advance / 256;
+ vmtxTab[1] = advance % 256;
+ for (j = 2; j < length; j += 2) {
+ vmtxTab[j] = 0;
+ vmtxTab[j+1] = 0;
+ }
+ checksum = computeTableChecksum(vmtxTab, length);
} else if (t42Tables[i].required) {
//~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
//~ t42Tables[i].tag);
checkRegion(tables[j].offset, tables[j].len)) {
dumpString(file + tables[j].offset, tables[j].len,
outputFunc, outputStream);
+ } else if (needVerticalMetrics && i == t42VheaTable) {
+ dumpString(vheaTab, length, outputFunc, outputStream);
+ } else if (needVerticalMetrics && i == t42VmtxTable) {
+ dumpString(vmtxTab, length, outputFunc, outputStream);
+ gfree(vmtxTab);
}
}
}
}
void FoFiTrueType::parse() {
+ Guint topTag;
int pos, i, j;
parsedOk = gTrue;
+ // look for a collection (TTC)
+ topTag = getU32BE(0, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ if (topTag == ttcfTag) {
+ pos = getU32BE(12, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ } else {
+ pos = 0;
+ }
+
// read the table directory
- nTables = getU16BE(4, &parsedOk);
+ nTables = getU16BE(pos + 4, &parsedOk);
if (!parsedOk) {
return;
}
- tables = (TrueTypeTable *)gmalloc(nTables * sizeof(TrueTypeTable));
- pos = 12;
+ tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
+ pos += 12;
for (i = 0; i < nTables; ++i) {
tables[i].tag = getU32BE(pos, &parsedOk);
tables[i].checksum = getU32BE(pos + 4, &parsedOk);
if (!parsedOk) {
return;
}
- cmaps = (TrueTypeCmap *)gmalloc(nCmaps * sizeof(TrueTypeCmap));
+ cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
for (j = 0; j < nCmaps; ++j) {
cmaps[j].platform = getU16BE(pos, &parsedOk);
cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
return;
}
- // read the post table
- readPostTable();
+ // make sure the loca table is sane (correct length and entries are
+ // in bounds)
+ i = seekTable("loca");
+ if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
+ parsedOk = gFalse;
+ return;
+ }
+ for (j = 0; j <= nGlyphs; ++j) {
+ if (locaFmt) {
+ pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
+ } else {
+ pos = getU16BE(tables[i].offset + j*2, &parsedOk);
+ }
+ if (pos < 0 || pos > len) {
+ parsedOk = gFalse;
+ }
+ }
if (!parsedOk) {
return;
}
+
+ // read the post table
+ readPostTable();
}
void FoFiTrueType::readPostTable() {
GString *name;
int tablePos, postFmt, stringIdx, stringPos;
+ GBool ok;
int i, j, n, m;
+ ok = gTrue;
if ((i = seekTable("post")) < 0) {
return;
}
tablePos = tables[i].offset;
- postFmt = getU32BE(tablePos, &parsedOk);
- if (!parsedOk) {
- return;
+ postFmt = getU32BE(tablePos, &ok);
+ if (!ok) {
+ goto err;
}
if (postFmt == 0x00010000) {
nameToGID = new GHash(gTrue);
}
} else if (postFmt == 0x00020000) {
nameToGID = new GHash(gTrue);
- n = getU16BE(tablePos + 32, &parsedOk);
- if (!parsedOk) {
- return;
+ n = getU16BE(tablePos + 32, &ok);
+ if (!ok) {
+ goto err;
}
if (n > nGlyphs) {
n = nGlyphs;
stringIdx = 0;
stringPos = tablePos + 34 + 2*n;
for (i = 0; i < n; ++i) {
- j = getU16BE(tablePos + 34 + 2*i, &parsedOk);
+ j = getU16BE(tablePos + 34 + 2*i, &ok);
if (j < 258) {
nameToGID->removeInt(macGlyphNames[j]);
nameToGID->add(new GString(macGlyphNames[j]), i);
if (j != stringIdx) {
for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
stringIdx < j;
- ++stringIdx, stringPos += 1 + getU8(stringPos, &parsedOk)) ;
- if (!parsedOk) {
- return;
+ ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ;
+ if (!ok) {
+ goto err;
}
}
- m = getU8(stringPos, &parsedOk);
- if (!parsedOk || !checkRegion(stringPos + 1, m)) {
- parsedOk = gFalse;
- return;
+ m = getU8(stringPos, &ok);
+ if (!ok || !checkRegion(stringPos + 1, m)) {
+ goto err;
}
name = new GString((char *)&file[stringPos + 1], m);
nameToGID->removeInt(name);
} else if (postFmt == 0x00028000) {
nameToGID = new GHash(gTrue);
for (i = 0; i < nGlyphs; ++i) {
- j = getU8(tablePos + 32 + i, &parsedOk);
- if (!parsedOk) {
- return;
+ j = getU8(tablePos + 32 + i, &ok);
+ if (!ok) {
+ goto err;
}
if (j < 258) {
nameToGID->removeInt(macGlyphNames[j]);
}
}
}
+
+ return;
+
+ err:
+ if (nameToGID) {
+ delete nameToGID;
+ nameToGID = NULL;
+ }
}
int FoFiTrueType::seekTable(char *tag) {
#include "gtypes.h"
#include "FoFiBase.h"
+class GString;
class GHash;
struct TrueTypeTable;
struct TrueTypeCmap;
// font). The <cidMap> array maps CIDs to GIDs; it has <nCIDs>
// entries.
void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs,
+ GBool needVerticalMetrics,
FoFiOutputFunc outputFunc, void *outputStream);
// Convert to a Type 0 (but non-CID) composite font, suitable for
// table in the font). The <cidMap> array maps CIDs to GIDs; it has
// <nCIDs> entries.
void convertToType0(char *psName, Gushort *cidMap, int nCIDs,
+ GBool needVerticalMetrics,
FoFiOutputFunc outputFunc, void *outputStream);
// Write a clean TTF file, filling in missing tables and correcting
- // various other errors. If the font is complete and correct, it
- // will be written unmodified.
- void writeTTF(FoFiOutputFunc outputFunc, void *outputStream);
+ // various other errors. If <name> is non-NULL, the font is renamed
+ // to <name>. If <codeToGID> is non-NULL, the font is re-encoded,
+ // using a Windows Unicode cmap. If <name> is NULL and the font is
+ // complete and correct, it will be written unmodified.
+ void writeTTF(FoFiOutputFunc outputFunc, void *outputStream,
+ char *name = NULL, Gushort *codeToGID = NULL);
private:
FoFiOutputFunc outputFunc,
void *outputStream);
void cvtSfnts(FoFiOutputFunc outputFunc,
- void *outputStream, GString *name);
+ void *outputStream, GString *name,
+ GBool needVerticalMetrics);
void dumpString(Guchar *s, int length,
FoFiOutputFunc outputFunc,
void *outputStream);
for (line = getNextLine(line);
line && strncmp(line, "readonly def", 12);
line = getNextLine(line)) ;
+ if (line) {
+ line = getNextLine(line);
+ }
}
if (line) {
(*outputFunc)(outputStream, line, ((char *)file + len) - line);
encoding = fofiType1StandardEncoding;
} else if (!encoding &&
!strncmp(line, "/Encoding 256 array", 19)) {
- encoding = (char **)gmalloc(256 * sizeof(char *));
+ encoding = (char **)gmallocn(256, sizeof(char *));
for (j = 0; j < 256; ++j) {
encoding[j] = NULL;
}
- line = getNextLine(line);
- for (j = 0; j < 300 && line; ++j) {
- line1 = getNextLine(line);
+ for (j = 0, line = getNextLine(line);
+ j < 300 && line && (line1 = getNextLine(line));
+ ++j, line = line1) {
if ((n = line1 - line) > 255) {
n = 255;
}
}
}
} else {
- if (strtok(buf, " \t") &&
- (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) {
- break;
+ p = strtok(buf, " \t\n\r");
+ if (p)
+ {
+ if (!strcmp(p, "def")) break;
+ if (!strcmp(p, "readonly")) break;
+ // the spec does not says this but i'm mantaining old xpdf behaviour that accepts "foo def" as end of the encoding array
+ p = strtok(buf, " \t\n\r");
+ if (p && !strcmp(p, "def")) break;
}
}
- line = line1;
}
//~ check for getinterval/putinterval junk
} else {
line = getNextLine(line);
}
-
- ++i;
}
parsed = gTrue;
int paintType;
int charstringType;
double fontMatrix[6];
+ GBool hasFontMatrix; // CID fonts are allowed to put their
+ // FontMatrix in the FD instead of the
+ // top dict
int uniqueID;
double fontBBox[4];
double strokeWidth;
#define type1CMaxStemSnap 12
struct Type1CPrivateDict {
+ double fontMatrix[6];
+ GBool hasFontMatrix;
int blueValues[type1CMaxBlueValues];
int nBlueValues;
int otherBlues[type1CMaxOtherBlues];
int nOps; // number of operands
int nHints; // number of hints for the current glyph
GBool firstOp; // true if we haven't hit the first op yet
+ GBool openPath; // true if there is an unclosed path
};
#endif
SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
Stream *str;
- int nSamples, sampleBits;
+ int sampleBits;
double sampleMul;
Object obj1, obj2;
Guint buf, bitMask;
obj2.free();
}
obj1.free();
+ idxMul[0] = n;
+ for (i = 1; i < m; ++i) {
+ idxMul[i] = idxMul[i-1] * sampleSize[i-1];
+ }
//----- BitsPerSample
if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
}
}
obj1.free();
+ for (i = 0; i < m; ++i) {
+ inputMul[i] = (encode[i][1] - encode[i][0]) /
+ (domain[i][1] - domain[i][0]);
+ }
//----- Decode
if (dict->lookup("Decode", &obj1)->isArray() &&
nSamples = n;
for (i = 0; i < m; ++i)
nSamples *= sampleSize[i];
- samples = (double *)gmalloc(nSamples * sizeof(double));
+ samples = (double *)gmallocn(nSamples, sizeof(double));
buf = 0;
bits = 0;
bitMask = (1 << sampleBits) - 1;
}
SampledFunction::SampledFunction(SampledFunction *func) {
- int nSamples, i;
-
memcpy(this, func, sizeof(SampledFunction));
-
- nSamples = n;
- for (i = 0; i < m; ++i) {
- nSamples *= sampleSize[i];
- }
- samples = (double *)gmalloc(nSamples * sizeof(double));
+ samples = (double *)gmallocn(nSamples, sizeof(double));
memcpy(samples, func->samples, nSamples * sizeof(double));
}
void SampledFunction::transform(double *in, double *out) {
double x;
- int e[2][funcMaxInputs];
- double efrac[funcMaxInputs];
- double s0[1 << funcMaxInputs], s1[1 << funcMaxInputs];
- int i, j, k, idx;
+ int e[funcMaxInputs][2];
+ double efrac0[funcMaxInputs];
+ double efrac1[funcMaxInputs];
+ double s[1 << funcMaxInputs];
+ int i, j, k, idx, t;
// map input values into sample array
for (i = 0; i < m; ++i) {
- x = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
- (encode[i][1] - encode[i][0]) + encode[i][0];
+ x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0];
if (x < 0) {
x = 0;
} else if (x > sampleSize[i] - 1) {
x = sampleSize[i] - 1;
}
- e[0][i] = (int)floor(x);
- e[1][i] = (int)ceil(x);
- efrac[i] = x - e[0][i];
+ e[i][0] = (int)x;
+ if ((e[i][1] = e[i][0] + 1) >= sampleSize[i]) {
+ // this happens if in[i] = domain[i][1]
+ e[i][1] = e[i][0];
+ }
+ efrac1[i] = x - e[i][0];
+ efrac0[i] = 1 - efrac1[i];
}
// for each output, do m-linear interpolation
// pull 2^m values out of the sample array
for (j = 0; j < (1<<m); ++j) {
- idx = 0;
- for (k = m - 1; k >= 0; --k) {
- idx = idx * sampleSize[k] + e[(j >> k) & 1][k];
+ idx = i;
+ for (k = 0, t = j; k < m; ++k, t >>= 1) {
+ idx += idxMul[k] * (e[k][t & 1]);
}
- idx = idx * n + i;
- s0[j] = samples[idx];
+ s[j] = samples[idx];
}
// do m sets of interpolations
- for (j = 0; j < m; ++j) {
- for (k = 0; k < (1 << (m - j)); k += 2) {
- s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1];
+ for (j = 0, t = (1<<m); j < m; ++j, t >>= 1) {
+ for (k = 0; k < t; k += 2) {
+ s[k >> 1] = efrac0[j] * s[k] + efrac1[j] * s[k+1];
}
- memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(double));
}
// map output value to range
- out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
+ out[i] = s[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
if (out[i] < range[i][0]) {
out[i] = range[i][0];
} else if (out[i] > range[i][1]) {
goto err1;
}
k = obj1.arrayGetLength();
- funcs = (Function **)gmalloc(k * sizeof(Function *));
- bounds = (double *)gmalloc((k + 1) * sizeof(double));
- encode = (double *)gmalloc(2 * k * sizeof(double));
+ funcs = (Function **)gmallocn(k, sizeof(Function *));
+ bounds = (double *)gmallocn(k + 1, sizeof(double));
+ encode = (double *)gmallocn(2 * k, sizeof(double));
for (i = 0; i < k; ++i) {
funcs[i] = NULL;
}
int i;
k = func->k;
- funcs = (Function **)gmalloc(k * sizeof(Function *));
+ funcs = (Function **)gmallocn(k, sizeof(Function *));
for (i = 0; i < k; ++i) {
funcs[i] = func->funcs[i]->copy();
}
- bounds = (double *)gmalloc((k + 1) * sizeof(double));
+ bounds = (double *)gmallocn(k + 1, sizeof(double));
memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
- encode = (double *)gmalloc(2 * k * sizeof(double));
+ encode = (double *)gmallocn(2 * k, sizeof(double));
memcpy(encode, func->encode, 2 * k * sizeof(double));
ok = gTrue;
}
void PSStack::copy(int n) {
int i;
+ if (sp + n > psStackSize) {
+ error(-1, "Stack underflow in PostScript function");
+ return;
+ }
if (!checkOverflow(n)) {
return;
}
- for (i = sp + n - 1; i <= sp; ++i) {
+ for (i = sp + n - 1; i >= sp; --i) {
stack[i - n] = stack[i];
}
sp -= n;
str = funcObj->getStream();
//----- parse the function
+ codeString = new GString();
str->reset();
if (!(tok = getToken(str)) || tok->cmp("{")) {
error(-1, "Expected '{' at start of PostScript function");
PostScriptFunction::PostScriptFunction(PostScriptFunction *func) {
memcpy(this, func, sizeof(PostScriptFunction));
- code = (PSObject *)gmalloc(codeSize * sizeof(PSObject));
+ code = (PSObject *)gmallocn(codeSize, sizeof(PSObject));
memcpy(code, func->code, codeSize * sizeof(PSObject));
+ codeString = func->codeString->copy();
}
PostScriptFunction::~PostScriptFunction() {
gfree(code);
+ delete codeString;
}
void PostScriptFunction::transform(double *in, double *out) {
s = new GString();
do {
c = str->getChar();
+ if (c != EOF) {
+ codeString->append(c);
+ }
} while (c != EOF && isspace(c));
if (c == '{' || c == '}') {
s->append((char)c);
break;
}
str->getChar();
+ codeString->append(c);
}
} else {
while (1) {
break;
}
str->getChar();
+ codeString->append(c);
}
}
return s;
void PostScriptFunction::resizeCode(int newSize) {
if (newSize >= codeSize) {
codeSize += 64;
- code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject));
+ code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject));
}
}
virtual Function *copy() = 0;
+ // Return the function type:
+ // -1 : identity
+ // 0 : sampled
+ // 2 : exponential
+ // 3 : stitching
+ // 4 : PostScript
+ virtual int getType() = 0;
+
// Return size of input and output tuples.
int getInputSize() { return m; }
int getOutputSize() { return n; }
+ double getDomainMin(int i) { return domain[i][0]; }
+ double getDomainMax(int i) { return domain[i][1]; }
+ double getRangeMin(int i) { return range[i][0]; }
+ double getRangeMax(int i) { return range[i][1]; }
+ GBool getHasRange() { return hasRange; }
+
// Transform an input tuple into an output tuple.
virtual void transform(double *in, double *out) = 0;
IdentityFunction();
virtual ~IdentityFunction();
virtual Function *copy() { return new IdentityFunction(); }
+ virtual int getType() { return -1; }
virtual void transform(double *in, double *out);
virtual GBool isOk() { return gTrue; }
SampledFunction(Object *funcObj, Dict *dict);
virtual ~SampledFunction();
virtual Function *copy() { return new SampledFunction(this); }
+ virtual int getType() { return 0; }
virtual void transform(double *in, double *out);
virtual GBool isOk() { return ok; }
+ int getSampleSize(int i) { return sampleSize[i]; }
+ double getEncodeMin(int i) { return encode[i][0]; }
+ double getEncodeMax(int i) { return encode[i][1]; }
+ double getDecodeMin(int i) { return decode[i][0]; }
+ double getDecodeMax(int i) { return decode[i][1]; }
+ double *getSamples() { return samples; }
+
private:
SampledFunction(SampledFunction *func);
encode[funcMaxInputs][2];
double // min and max values for range decoder
decode[funcMaxOutputs][2];
+ double // input multipliers
+ inputMul[funcMaxInputs];
+ int idxMul[funcMaxInputs]; // sample array index multipliers
double *samples; // the samples
+ int nSamples; // size of the samples array
GBool ok;
};
ExponentialFunction(Object *funcObj, Dict *dict);
virtual ~ExponentialFunction();
virtual Function *copy() { return new ExponentialFunction(this); }
+ virtual int getType() { return 2; }
virtual void transform(double *in, double *out);
virtual GBool isOk() { return ok; }
+ double *getC0() { return c0; }
+ double *getC1() { return c1; }
+ double getE() { return e; }
+
private:
ExponentialFunction(ExponentialFunction *func);
StitchingFunction(Object *funcObj, Dict *dict);
virtual ~StitchingFunction();
virtual Function *copy() { return new StitchingFunction(this); }
+ virtual int getType() { return 3; }
virtual void transform(double *in, double *out);
virtual GBool isOk() { return ok; }
+ int getNumFuncs() { return k; }
+ Function *getFunc(int i) { return funcs[i]; }
+ double *getBounds() { return bounds; }
+ double *getEncode() { return encode; }
+
private:
StitchingFunction(StitchingFunction *func);
PostScriptFunction(Object *funcObj, Dict *dict);
virtual ~PostScriptFunction();
virtual Function *copy() { return new PostScriptFunction(this); }
+ virtual int getType() { return 4; }
virtual void transform(double *in, double *out);
virtual GBool isOk() { return ok; }
+ GString *getCodeString() { return codeString; }
+
private:
PostScriptFunction(PostScriptFunction *func);
void resizeCode(int newSize);
void exec(PSStack *stack, int codePtr);
+ GString *codeString;
PSObject *code;
int codeSize;
GBool ok;
deleteKeys = deleteKeysA;
size = 7;
- tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *));
+ tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *));
for (h = 0; h < size; ++h) {
tab[h] = NULL;
}
++len;
}
+void GHash::replace(GString *key, void *val) {
+ GHashBucket *p;
+ int h;
+
+ if ((p = find(key, &h))) {
+ p->val.p = val;
+ delete key;
+ } else {
+ add(key, val);
+ }
+}
+
+void GHash::replace(GString *key, int val) {
+ GHashBucket *p;
+ int h;
+
+ if ((p = find(key, &h))) {
+ p->val.i = val;
+ delete key;
+ } else {
+ add(key, val);
+ }
+}
+
void *GHash::lookup(GString *key) {
GHashBucket *p;
int h;
oldSize = size;
oldTab = tab;
size = 2*size + 1;
- tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *));
+ tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *));
for (h = 0; h < size; ++h) {
tab[h] = NULL;
}
~GHash();
void add(GString *key, void *val);
void add(GString *key, int val);
+ void replace(GString *key, void *val);
+ void replace(GString *key, int val);
void *lookup(GString *key);
int lookupInt(GString *key);
void *lookup(char *key);
#pragma implementation
#endif
+#include <stdlib.h>
#include <string.h>
#include "gmem.h"
#include "GList.h"
GList::GList() {
size = 8;
- data = (void **)gmalloc(size * sizeof(void*));
+ data = (void **)gmallocn(size, sizeof(void*));
length = 0;
inc = 0;
}
GList::GList(int sizeA) {
size = sizeA;
- data = (void **)gmalloc(size * sizeof(void*));
+ data = (void **)gmallocn(size, sizeof(void*));
length = 0;
inc = 0;
}
return p;
}
+void GList::sort(int (*cmp)(const void *obj1, const void *obj2)) {
+ qsort(data, length, sizeof(void *), cmp);
+}
+
void GList::expand() {
size += (inc > 0) ? inc : size;
- data = (void **)grealloc(data, size * sizeof(void*));
+ data = (void **)greallocn(data, size, sizeof(void*));
}
void GList::shrink() {
size -= (inc > 0) ? inc : size/2;
- data = (void **)grealloc(data, size * sizeof(void*));
+ data = (void **)greallocn(data, size, sizeof(void*));
}
// Assumes 0 <= i < length.
void *del(int i);
+ // Sort the list accoring to the given comparison function.
+ // NB: this sorts an array of pointers, so the pointer args need to
+ // be double-dereferenced.
+ void sort(int (*cmp)(const void *ptr1, const void *ptr2));
+
//----- control
// Set allocation increment to <inc>. If inc > 0, that many
s = new char[size(length1)];
} else if (size(length1) != size(length)) {
s1 = new char[size(length1)];
- memcpy(s1, s, length + 1);
+ if (length1 < length) {
+ memcpy(s1, s, length1);
+ s1[length1] = '\0';
+ } else {
+ memcpy(s1, s, length + 1);
+ }
delete[] s;
s = s1;
}
}
return this;
}
+
+int GString::cmp(GString *str) {
+ int n1, n2, i, x;
+ char *p1, *p2;
+
+ n1 = length;
+ n2 = str->length;
+ for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) {
+ x = *p1 - *p2;
+ if (x != 0) {
+ return x;
+ }
+ }
+ return n1 - n2;
+}
+
+int GString::cmpN(GString *str, int n) {
+ int n1, n2, i, x;
+ char *p1, *p2;
+
+ n1 = length;
+ n2 = str->length;
+ for (i = 0, p1 = s, p2 = str->s;
+ i < n1 && i < n2 && i < n;
+ ++i, ++p1, ++p2) {
+ x = *p1 - *p2;
+ if (x != 0) {
+ return x;
+ }
+ }
+ if (i == n) {
+ return 0;
+ }
+ return n1 - n2;
+}
+
+int GString::cmp(const char *sA) {
+ int n1, i, x;
+ const char *p1, *p2;
+
+ n1 = length;
+ for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) {
+ x = *p1 - *p2;
+ if (x != 0) {
+ return x;
+ }
+ }
+ if (i < n1) {
+ return 1;
+ }
+ if (*p2) {
+ return -1;
+ }
+ return 0;
+}
+
+int GString::cmpN(const char *sA, int n) {
+ int n1, i, x;
+ const char *p1, *p2;
+
+ n1 = length;
+ for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) {
+ x = *p1 - *p2;
+ if (x != 0) {
+ return x;
+ }
+ }
+ if (i == n) {
+ return 0;
+ }
+ if (i < n1) {
+ return 1;
+ }
+ if (*p2) {
+ return -1;
+ }
+ return 0;
+}
#pragma interface
#endif
-#include <string.h>
-
class GString {
public:
GString *lowerCase();
// Compare two strings: -1:< 0:= +1:>
- // These functions assume the strings do not contain null characters.
- int cmp(GString *str) { return strcmp(s, str->getCString()); }
- int cmpN(GString *str, int n) { return strncmp(s, str->getCString(), n); }
- int cmp(const char *sA) { return strcmp(s, sA); }
- int cmpN(const char *sA, int n) { return strncmp(s, sA, n); }
+ int cmp(GString *str);
+ int cmpN(GString *str, int n);
+ int cmp(const char *sA);
+ int cmpN(const char *sA, int n);
private:
class GfxFunctionShading;
class GfxAxialShading;
class GfxRadialShading;
+class GfxGouraudTriangleShading;
+class GfxPatchMeshShading;
+struct GfxPatch;
class GfxState;
struct GfxColor;
class Gfx;
// Constructor for regular output.
Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict,
- double hDPI, double vDPI, PDFRectangle *box, GBool crop,
+ double hDPI, double vDPI, PDFRectangle *box,
PDFRectangle *cropBox, int rotate,
GBool (*abortCheckCbkA)(void *data) = NULL,
void *abortCheckCbkDataA = NULL);
// Constructor for a sub-page object.
Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
- PDFRectangle *box, GBool crop, PDFRectangle *cropBox,
+ PDFRectangle *box, PDFRectangle *cropBox,
GBool (*abortCheckCbkA)(void *data) = NULL,
void *abortCheckCbkDataA = NULL);
// Restore graphics state.
void restoreState();
+ // Get the current graphics state object.
+ GfxState *getState() { return state; }
+
private:
XRef *xref; // the xref table for this PDF file
GfxColor *colors, int depth);
void doAxialShFill(GfxAxialShading *shading);
void doRadialShFill(GfxRadialShading *shading);
+ void doGouraudTriangleShFill(GfxGouraudTriangleShading *shading);
+ void gouraudFillTriangle(double x0, double y0, GfxColor *color0,
+ double x1, double y1, GfxColor *color1,
+ double x2, double y2, GfxColor *color2,
+ int nComps, int depth);
+ void doPatchMeshShFill(GfxPatchMeshShading *shading);
+ void fillPatch(GfxPatch *patch, int nComps, int depth);
void doEndPath();
// path clipping operators
{ "Arial-ItalicMT", "Helvetica-Oblique" },
{ "ArialMT", "Helvetica" },
{ "Courier,Bold", "Courier-Bold" },
- { "Courier,Italic", "Courier-Oblique" },
{ "Courier,BoldItalic", "Courier-BoldOblique" },
+ { "Courier,Italic", "Courier-Oblique" },
{ "CourierNew", "Courier" },
{ "CourierNew,Bold", "Courier-Bold" },
{ "CourierNew,BoldItalic", "Courier-BoldOblique" },
// look for embedded font file
if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) {
- if (type == fontType1) {
- embFontID = obj2.getRef();
- } else {
+ embFontID = obj2.getRef();
+ if (type != fontType1) {
error(-1, "Mismatch between font type and embedded font file");
+ type = fontType1;
}
}
obj2.free();
if (embFontID.num == -1 &&
obj1.dictLookupNF("FontFile2", &obj2)->isRef()) {
- if (type == fontTrueType || type == fontCIDType2) {
- embFontID = obj2.getRef();
- } else {
+ embFontID = obj2.getRef();
+ if (type != fontTrueType && type != fontCIDType2) {
error(-1, "Mismatch between font type and embedded font file");
+ type = type == fontCIDType0 ? fontCIDType2 : fontTrueType;
}
}
obj2.free();
if (obj2.fetch(xref, &obj3)->isStream()) {
obj3.streamGetDict()->lookup("Subtype", &obj4);
if (obj4.isName("Type1")) {
- if (type == fontType1) {
- embFontID = obj2.getRef();
- } else {
+ embFontID = obj2.getRef();
+ if (type != fontType1) {
error(-1, "Mismatch between font type and embedded font file");
+ type = fontType1;
}
} else if (obj4.isName("Type1C")) {
- if (type == fontType1) {
- type = fontType1C;
- embFontID = obj2.getRef();
- } else if (type == fontType1C) {
- embFontID = obj2.getRef();
- } else {
+ embFontID = obj2.getRef();
+ if (type != fontType1 && type != fontType1C) {
error(-1, "Mismatch between font type and embedded font file");
}
+ type = fontType1C;
} else if (obj4.isName("TrueType")) {
- if (type == fontTrueType) {
- embFontID = obj2.getRef();
- } else {
+ embFontID = obj2.getRef();
+ if (type != fontTrueType) {
error(-1, "Mismatch between font type and embedded font file");
+ type = fontTrueType;
}
} else if (obj4.isName("CIDFontType0C")) {
- if (type == fontCIDType0) {
- type = fontCIDType0C;
- embFontID = obj2.getRef();
- } else {
+ embFontID = obj2.getRef();
+ if (type != fontCIDType0) {
error(-1, "Mismatch between font type and embedded font file");
}
+ type = fontCIDType0C;
} else {
error(-1, "Unknown embedded font type '%s'",
obj4.isName() ? obj4.getName() : "???");
GfxFontType typeA, Dict *fontDict):
GfxFont(tagA, idA, nameA)
{
+ GString *name2;
BuiltinFont *builtinFont;
char **baseEnc;
GBool baseEncFromFontFile;
// do font name substitution for various aliases of the Base 14 font
// names
if (name) {
+ name2 = name->copy();
+ i = 0;
+ while (i < name2->getLength()) {
+ if (name2->getChar(i) == ' ') {
+ name2->del(i);
+ } else {
+ ++i;
+ }
+ }
a = 0;
b = sizeof(stdFontMap) / sizeof(StdFontMapEntry);
- // invariant: stdFontMap[a].altName <= name < stdFontMap[b].altName
+ // invariant: stdFontMap[a].altName <= name2 < stdFontMap[b].altName
while (b - a > 1) {
m = (a + b) / 2;
- if (name->cmp(stdFontMap[m].altName) >= 0) {
+ if (name2->cmp(stdFontMap[m].altName) >= 0) {
a = m;
} else {
b = m;
}
}
- if (!name->cmp(stdFontMap[a].altName)) {
+ if (!name2->cmp(stdFontMap[a].altName)) {
name = new GString(stdFontMap[a].properName);
}
+ delete name2;
}
// is it a built-in font?
// get info from font descriptor
readFontDescriptor(xref, fontDict);
+ // for non-embedded fonts, don't trust the ascent/descent/bbox
+ // values from the font descriptor
+ if (builtinFont && embFontID.num < 0) {
+ ascent = 0.001 * builtinFont->ascent;
+ descent = 0.001 * builtinFont->descent;
+ fontBBox[0] = 0.001 * builtinFont->bbox[0];
+ fontBBox[1] = 0.001 * builtinFont->bbox[1];
+ fontBBox[2] = 0.001 * builtinFont->bbox[2];
+ fontBBox[3] = 0.001 * builtinFont->bbox[3];
+ }
+
// look for an external font file
findExtFontFile();
// 2. embedded or external font file
// 3. default:
// - builtin --> builtin encoding
- // - TrueType --> MacRomanEncoding
+ // - TrueType --> WinAnsiEncoding
// - others --> StandardEncoding
// and then add a list of differences (if any) from
// FontDict.Encoding.Differences.
} else if (obj2.isName("WinAnsiEncoding")) {
hasEncoding = gTrue;
baseEnc = winAnsiEncoding;
- } else if (obj2.isName("StandardEncoding")) {
- hasEncoding = gTrue;
- baseEnc = standardEncoding;
}
obj2.free();
} else if (obj1.isName("MacRomanEncoding")) {
} else if (obj1.isName("WinAnsiEncoding")) {
hasEncoding = gTrue;
baseEnc = winAnsiEncoding;
- } else if (obj1.isName("StandardEncoding")) {
- hasEncoding = gTrue;
- baseEnc = standardEncoding;
}
// check embedded or external font file for base encoding
// get default base encoding
if (!baseEnc) {
- if (builtinFont) {
+ if (builtinFont && embFontID.num < 0) {
baseEnc = builtinFont->defaultBaseEnc;
hasEncoding = gTrue;
} else if (type == fontTrueType) {
Unicode u;
int code, i, n;
- map = (Gushort *)gmalloc(256 * sizeof(Gushort));
+ map = (Gushort *)gmallocn(256, sizeof(Gushort));
for (i = 0; i < 256; ++i) {
map[i] = 0;
}
// directly (possibly with an offset of 0xf000).
// 1d. If the TrueType font has a Macintosh Roman cmap, use it,
// as in case 1a.
- // 2. If the PDF font does not have an encoding:
+ // 2. If the PDF font does not have an encoding or the PDF font is
+ // symbolic:
// 2a. If the TrueType font has a Macintosh Roman cmap, use it,
// and use char codes directly (possibly with an offset of
// 0xf000).
useUnicode = gTrue;
} else if ((flags & fontSymbolic) && msSymbolCmap >= 0) {
cmap = msSymbolCmap;
+ } else if ((flags & fontSymbolic) && macRomanCmap >= 0) {
+ cmap = macRomanCmap;
} else if (macRomanCmap >= 0) {
cmap = macRomanCmap;
useMacRoman = gTrue;
// map Unicode through the cmap
} else if (useUnicode) {
for (i = 0; i < 256; ++i) {
- if ((n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
+ if (((charName = enc[i]) &&
+ (u = globalParams->mapNameToUnicode(charName))) ||
+ (n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
map[i] = ff->mapCodeToGID(cmap, u);
}
}
GString *collection, *cMapName;
Object desFontDictObj;
Object obj1, obj2, obj3, obj4, obj5, obj6;
+ CharCodeToUnicode *utu;
+ CharCode c;
+ Unicode uBuf[8];
int c1, c2;
- int excepsSize, i, j, k;
+ int excepsSize, i, j, k, n;
ascent = 0.95;
descent = -0.35;
if (!(ctu = globalParams->getCIDToUnicode(collection))) {
error(-1, "Unknown character collection '%s'",
collection->getCString());
- delete collection;
- goto err2;
+ // fall-through, assuming the Identity mapping -- this appears
+ // to match Adobe's behavior
+ }
+ }
+ }
+
+ // look for a Unicode-to-Unicode mapping
+ if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
+ if (ctu) {
+ for (c = 0; c < ctu->getLength(); ++c) {
+ n = ctu->mapToUnicode(c, uBuf, 8);
+ if (n >= 1) {
+ n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
+ if (n >= 1) {
+ ctu->setMapping(c, uBuf, n);
+ }
+ }
}
+ utu->decRefCnt();
+ } else {
+ ctu = utu;
}
}
if (obj1.isStream()) {
cidToGIDLen = 0;
i = 64;
- cidToGID = (Gushort *)gmalloc(i * sizeof(Gushort));
+ cidToGID = (Gushort *)gmallocn(i, sizeof(Gushort));
obj1.streamReset();
while ((c1 = obj1.streamGetChar()) != EOF &&
(c2 = obj1.streamGetChar()) != EOF) {
if (cidToGIDLen == i) {
i *= 2;
- cidToGID = (Gushort *)grealloc(cidToGID, i * sizeof(Gushort));
+ cidToGID = (Gushort *)greallocn(cidToGID, i, sizeof(Gushort));
}
cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2);
}
if (widths.nExceps == excepsSize) {
excepsSize += 16;
widths.exceps = (GfxFontCIDWidthExcep *)
- grealloc(widths.exceps,
- excepsSize * sizeof(GfxFontCIDWidthExcep));
+ greallocn(widths.exceps,
+ excepsSize, sizeof(GfxFontCIDWidthExcep));
}
widths.exceps[widths.nExceps].first = obj2.getInt();
widths.exceps[widths.nExceps].last = obj3.getInt();
if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15;
widths.exceps = (GfxFontCIDWidthExcep *)
- grealloc(widths.exceps,
- excepsSize * sizeof(GfxFontCIDWidthExcep));
+ greallocn(widths.exceps,
+ excepsSize, sizeof(GfxFontCIDWidthExcep));
}
j = obj2.getInt();
for (k = 0; k < obj3.arrayGetLength(); ++k) {
if (widths.nExcepsV == excepsSize) {
excepsSize += 16;
widths.excepsV = (GfxFontCIDWidthExcepV *)
- grealloc(widths.excepsV,
- excepsSize * sizeof(GfxFontCIDWidthExcepV));
+ greallocn(widths.excepsV,
+ excepsSize, sizeof(GfxFontCIDWidthExcepV));
}
widths.excepsV[widths.nExcepsV].first = obj2.getInt();
widths.excepsV[widths.nExcepsV].last = obj3.getInt();
excepsSize =
(widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15;
widths.excepsV = (GfxFontCIDWidthExcepV *)
- grealloc(widths.excepsV,
- excepsSize * sizeof(GfxFontCIDWidthExcepV));
+ greallocn(widths.excepsV,
+ excepsSize, sizeof(GfxFontCIDWidthExcepV));
}
j = obj2.getInt();
for (k = 0; k < obj3.arrayGetLength(); k += 3) {
Ref r;
numFonts = fontDict->getLength();
- fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *));
+ fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *));
for (i = 0; i < numFonts; ++i) {
fontDict->getValNF(i, &obj1);
obj1.fetch(xref, &obj2);
class GfxShading;
//------------------------------------------------------------------------
+// GfxBlendMode
+//------------------------------------------------------------------------
+
+enum GfxBlendMode {
+ gfxBlendNormal,
+ gfxBlendMultiply,
+ gfxBlendScreen,
+ gfxBlendOverlay,
+ gfxBlendDarken,
+ gfxBlendLighten,
+ gfxBlendColorDodge,
+ gfxBlendColorBurn,
+ gfxBlendHardLight,
+ gfxBlendSoftLight,
+ gfxBlendDifference,
+ gfxBlendExclusion,
+ gfxBlendHue,
+ gfxBlendSaturation,
+ gfxBlendColor,
+ gfxBlendLuminosity
+};
+
+//------------------------------------------------------------------------
+// GfxColorComp
+//------------------------------------------------------------------------
+
+// 16.16 fixed point color component
+typedef int GfxColorComp;
+
+#define gfxColorComp1 0x10000
+
+static inline GfxColorComp dblToCol(double x) {
+ return (GfxColorComp)(x * gfxColorComp1);
+}
+
+static inline double colToDbl(GfxColorComp x) {
+ return (double)x / (double)gfxColorComp1;
+}
+
+static inline GfxColorComp byteToCol(Guchar x) {
+ // (x / 255) << 16 = (0.0000000100000001... * x) << 16
+ // = ((x << 8) + (x) + (x >> 8) + ...) << 16
+ // = (x << 8) + (x) + (x >> 7)
+ // [for rounding]
+ return (GfxColorComp)((x << 8) + x + (x >> 7));
+}
+
+static inline Guchar colToByte(GfxColorComp x) {
+ // 255 * x + 0.5 = 256 * x - x + 0x8000
+ return (Guchar)(((x << 8) - x + 0x8000) >> 16);
+}
+
+//------------------------------------------------------------------------
// GfxColor
//------------------------------------------------------------------------
#define gfxColorMaxComps funcMaxOutputs
struct GfxColor {
- double c[gfxColorMaxComps];
+ GfxColorComp c[gfxColorMaxComps];
};
//------------------------------------------------------------------------
+// GfxGray
+//------------------------------------------------------------------------
+
+typedef GfxColorComp GfxGray;
+
+//------------------------------------------------------------------------
// GfxRGB
//------------------------------------------------------------------------
struct GfxRGB {
- double r, g, b;
+ GfxColorComp r, g, b;
};
//------------------------------------------------------------------------
//------------------------------------------------------------------------
struct GfxCMYK {
- double c, m, y, k;
+ GfxColorComp c, m, y, k;
};
//------------------------------------------------------------------------
static GfxColorSpace *parse(Object *csObj);
// Convert to gray, RGB, or CMYK.
- virtual void getGray(GfxColor *color, double *gray) = 0;
+ virtual void getGray(GfxColor *color, GfxGray *gray) = 0;
virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0;
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0;
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csDeviceGray; }
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
// Construct a CalGray color space. Returns NULL if unsuccessful.
static GfxColorSpace *parse(Array *arr);
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csDeviceRGB; }
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
// Construct a CalRGB color space. Returns NULL if unsuccessful.
static GfxColorSpace *parse(Array *arr);
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
double whiteX, whiteY, whiteZ; // white point
double blackX, blackY, blackZ; // black point
double gammaR, gammaG, gammaB; // gamma values
- double mat[9]; // ABC -> XYZ transform matrix
+ double mat[9]; // ABC -> XYZ transform matrix
};
//------------------------------------------------------------------------
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csDeviceCMYK; }
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
// Construct a Lab color space. Returns NULL if unsuccessful.
static GfxColorSpace *parse(Array *arr);
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
// Construct an ICCBased color space. Returns NULL if unsuccessful.
static GfxColorSpace *parse(Array *arr);
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
// Construct a Lab color space. Returns NULL if unsuccessful.
static GfxColorSpace *parse(Array *arr);
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
// Construct a Separation color space. Returns NULL if unsuccessful.
static GfxColorSpace *parse(Array *arr);
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
// Construct a DeviceN color space. Returns NULL if unsuccessful.
static GfxColorSpace *parse(Array *arr);
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
// Construct a Pattern color space. Returns NULL if unsuccessful.
static GfxColorSpace *parse(Array *arr);
- virtual void getGray(GfxColor *color, double *gray);
+ virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
void getDomain(double *x0A, double *y0A, double *x1A, double *y1A)
{ *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
double *getMatrix() { return matrix; }
+ int getNFuncs() { return nFuncs; }
+ Function *getFunc(int i) { return funcs[i]; }
void getColor(double x, double y, GfxColor *color);
private:
{ *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
double getDomain0() { return t0; }
double getDomain1() { return t1; }
- void getColor(double t, GfxColor *color);
GBool getExtend0() { return extend0; }
GBool getExtend1() { return extend1; }
+ int getNFuncs() { return nFuncs; }
+ Function *getFunc(int i) { return funcs[i]; }
+ void getColor(double t, GfxColor *color);
private:
{ *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; }
double getDomain0() { return t0; }
double getDomain1() { return t1; }
- void getColor(double t, GfxColor *color);
GBool getExtend0() { return extend0; }
GBool getExtend1() { return extend1; }
+ int getNFuncs() { return nFuncs; }
+ Function *getFunc(int i) { return funcs[i]; }
+ void getColor(double t, GfxColor *color);
private:
};
//------------------------------------------------------------------------
+// GfxGouraudTriangleShading
+//------------------------------------------------------------------------
+
+struct GfxGouraudVertex {
+ double x, y;
+ GfxColor color;
+};
+
+class GfxGouraudTriangleShading: public GfxShading {
+public:
+
+ GfxGouraudTriangleShading(int typeA,
+ GfxGouraudVertex *verticesA, int nVerticesA,
+ int (*trianglesA)[3], int nTrianglesA,
+ Function **funcsA, int nFuncsA);
+ GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading);
+ virtual ~GfxGouraudTriangleShading();
+
+ static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str);
+
+ virtual GfxShading *copy();
+
+ int getNTriangles() { return nTriangles; }
+ void getTriangle(int i, double *x0, double *y0, GfxColor *color0,
+ double *x1, double *y1, GfxColor *color1,
+ double *x2, double *y2, GfxColor *color2);
+
+private:
+
+ GfxGouraudVertex *vertices;
+ int nVertices;
+ int (*triangles)[3];
+ int nTriangles;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+};
+
+//------------------------------------------------------------------------
+// GfxPatchMeshShading
+//------------------------------------------------------------------------
+
+struct GfxPatch {
+ double x[4][4];
+ double y[4][4];
+ GfxColor color[2][2];
+};
+
+class GfxPatchMeshShading: public GfxShading {
+public:
+
+ GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA,
+ Function **funcsA, int nFuncsA);
+ GfxPatchMeshShading(GfxPatchMeshShading *shading);
+ virtual ~GfxPatchMeshShading();
+
+ static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str);
+
+ virtual GfxShading *copy();
+
+ int getNPatches() { return nPatches; }
+ GfxPatch *getPatch(int i) { return &patches[i]; }
+
+private:
+
+ GfxPatch *patches;
+ int nPatches;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+};
+
+//------------------------------------------------------------------------
// GfxImageColorMap
//------------------------------------------------------------------------
double getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; }
// Convert an image pixel to a color.
- void getGray(Guchar *x, double *gray);
+ void getGray(Guchar *x, GfxGray *gray);
void getRGB(Guchar *x, GfxRGB *rgb);
void getCMYK(Guchar *x, GfxCMYK *cmyk);
void getColor(Guchar *x, GfxColor *color);
int nComps; // number of components in a pixel
GfxColorSpace *colorSpace2; // secondary color space
int nComps2; // number of components in colorSpace2
- double *lookup; // lookup table
+ GfxColorComp * // lookup table
+ lookup[gfxColorMaxComps];
double // minimum values for each component
decodeLow[gfxColorMaxComps];
double // max - min value for each component
public:
// Construct a default GfxState, for a device with resolution <hDPI>
- // x <vDPI>, page box <pageBox>, page rotation <rotate>, and
+ // x <vDPI>, page box <pageBox>, page rotation <rotateA>, and
// coordinate system specified by <upsideDown>.
GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
- int rotate, GBool upsideDown);
+ int rotateA, GBool upsideDown);
// Destructor.
~GfxState();
double getY2() { return py2; }
double getPageWidth() { return pageWidth; }
double getPageHeight() { return pageHeight; }
+ int getRotate() { return rotate; }
GfxColor *getFillColor() { return &fillColor; }
GfxColor *getStrokeColor() { return &strokeColor; }
- void getFillGray(double *gray)
+ void getFillGray(GfxGray *gray)
{ fillColorSpace->getGray(&fillColor, gray); }
- void getStrokeGray(double *gray)
+ void getStrokeGray(GfxGray *gray)
{ strokeColorSpace->getGray(&strokeColor, gray); }
void getFillRGB(GfxRGB *rgb)
{ fillColorSpace->getRGB(&fillColor, rgb); }
GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; }
GfxPattern *getFillPattern() { return fillPattern; }
GfxPattern *getStrokePattern() { return strokePattern; }
+ GfxBlendMode getBlendMode() { return blendMode; }
double getFillOpacity() { return fillOpacity; }
double getStrokeOpacity() { return strokeOpacity; }
+ GBool getFillOverprint() { return fillOverprint; }
+ GBool getStrokeOverprint() { return strokeOverprint; }
double getLineWidth() { return lineWidth; }
void getLineDash(double **dash, int *length, double *start)
{ *dash = lineDash; *length = lineDashLength; *start = lineDashStart; }
void setStrokeColor(GfxColor *color) { strokeColor = *color; }
void setFillPattern(GfxPattern *pattern);
void setStrokePattern(GfxPattern *pattern);
+ void setBlendMode(GfxBlendMode mode) { blendMode = mode; }
void setFillOpacity(double opac) { fillOpacity = opac; }
void setStrokeOpacity(double opac) { strokeOpacity = opac; }
+ void setFillOverprint(GBool op) { fillOverprint = op; }
+ void setStrokeOverprint(GBool op) { strokeOverprint = op; }
void setLineWidth(double width) { lineWidth = width; }
void setLineDash(double *dash, int length, double start);
void setFlatness(int flatness1) { flatness = flatness1; }
GfxState *restore();
GBool hasSaves() { return saved != NULL; }
+ // Misc
+ GBool parseBlendMode(Object *obj, GfxBlendMode *mode);
+
private:
double ctm[6]; // coord transform matrix
double px1, py1, px2, py2; // page corners (user coords)
double pageWidth, pageHeight; // page size (pixels)
+ int rotate; // page rotation angle
GfxColorSpace *fillColorSpace; // fill color space
GfxColorSpace *strokeColorSpace; // stroke color space
GfxColor strokeColor; // stroke color
GfxPattern *fillPattern; // fill pattern
GfxPattern *strokePattern; // stroke pattern
+ GfxBlendMode blendMode; // transparency blend mode
double fillOpacity; // fill opacity
double strokeOpacity; // stroke opacity
+ GBool fillOverprint; // fill overprint
+ GBool strokeOverprint; // stroke overprint
double lineWidth; // line width
double *lineDash; // line dash
JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) {
contextSize = contextSizeA;
- cxTab = (Guchar *)gmalloc(contextSize * sizeof(Guchar));
+ cxTab = (Guchar *)gmallocn(contextSize, sizeof(Guchar));
reset();
}
JArithmeticDecoder::JArithmeticDecoder() {
str = NULL;
-}
-
-JArithmeticDecoder::~JArithmeticDecoder() {
- while (dataLen > 0) {
- readByte();
- }
+ dataLen = 0;
+ limitStream = gFalse;
}
inline Guint JArithmeticDecoder::readByte() {
- if (dataLen == 0) {
- return 0xff;
- }
- if (dataLen > 0) {
+ if (limitStream) {
--dataLen;
+ if (dataLen < 0) {
+ return 0xff;
+ }
}
return (Guint)str->getChar() & 0xff;
}
+JArithmeticDecoder::~JArithmeticDecoder() {
+ cleanup();
+}
+
void JArithmeticDecoder::start() {
buf0 = readByte();
buf1 = readByte();
a = 0x80000000;
}
+void JArithmeticDecoder::restart(int dataLenA) {
+ int oldDataLen;
+
+ oldDataLen = dataLen;
+ dataLen = dataLenA;
+ if (oldDataLen == -1) {
+ buf1 = readByte();
+ } else if (oldDataLen <= -2) {
+ buf0 = readByte();
+ buf1 = readByte();
+ }
+}
+
+void JArithmeticDecoder::cleanup() {
+ if (limitStream) {
+ while (dataLen > 0) {
+ buf0 = buf1;
+ buf1 = readByte();
+ }
+ }
+}
+
int JArithmeticDecoder::decodeBit(Guint context,
JArithmeticDecoderStats *stats) {
int bit;
JArithmeticDecoder();
~JArithmeticDecoder();
+
void setStream(Stream *strA)
- { str = strA; dataLen = -1; }
+ { str = strA; dataLen = 0; limitStream = gFalse; }
void setStream(Stream *strA, int dataLenA)
- { str = strA; dataLen = dataLenA; }
+ { str = strA; dataLen = dataLenA; limitStream = gTrue; }
+
+ // Start decoding on a new stream. This fills the byte buffers and
+ // runs INITDEC.
void start();
+
+ // Restart decoding on an interrupted stream. This refills the
+ // buffers if needed, but does not run INITDEC. (This is used in
+ // JPEG 2000 streams when codeblock data is split across multiple
+ // packets/layers.)
+ void restart(int dataLenA);
+
+ // Read any leftover data in the stream.
+ void cleanup();
+
+ // Decode one bit.
int decodeBit(Guint context, JArithmeticDecoderStats *stats);
+
+ // Decode eight bits.
int decodeByte(Guint context, JArithmeticDecoderStats *stats);
// Returns false for OOB, otherwise sets *<x> and returns true.
Stream *str;
int dataLen;
+ GBool limitStream;
};
#endif
w = wA;
h = hA;
line = (wA + 7) >> 3;
- data = (Guchar *)gmalloc(h * line);
+ // need to allocate one extra guard byte for use in combine()
+ data = (Guchar *)gmalloc(h * line + 1);
+ data[h * line] = 0;
}
JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap):
w = bitmap->w;
h = bitmap->h;
line = bitmap->line;
- data = (Guchar *)gmalloc(h * line);
+ // need to allocate one extra guard byte for use in combine()
+ data = (Guchar *)gmalloc(h * line + 1);
memcpy(data, bitmap->data, h * line);
+ data[h * line] = 0;
}
JBIG2Bitmap::~JBIG2Bitmap() {
if (newH <= h) {
return;
}
- data = (Guchar *)grealloc(data, newH * line);
+ // need to allocate one extra guard byte for use in combine()
+ data = (Guchar *)grealloc(data, newH * line + 1);
if (pixel) {
memset(data + h * line, 0xff, (newH - h) * line);
} else {
memset(data + h * line, 0x00, (newH - h) * line);
}
h = newH;
+ data[h * line] = 0;
}
void JBIG2Bitmap::clearToZero() {
}
// right-most byte
+ // note: this last byte (src1) may not actually be used, depending
+ // on the values of s1, m1, and m2 - and in fact, it may be off
+ // the edge of the source bitmap, which means we need to allocate
+ // one extra guard byte at the end of each bitmap
dest = *destPtr;
src0 = src1;
src1 = *srcPtr++;
JBIG2Segment(segNumA)
{
size = sizeA;
- bitmaps = (JBIG2Bitmap **)gmalloc(size * sizeof(JBIG2Bitmap *));
+ bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *));
genericRegionStats = NULL;
refinementRegionStats = NULL;
}
JBIG2Segment(segNumA)
{
size = sizeA;
- bitmaps = (JBIG2Bitmap **)gmalloc(size * sizeof(JBIG2Bitmap *));
+ bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *));
}
JBIG2PatternDict::~JBIG2PatternDict() {
}
// referred-to segment numbers
- refSegs = (Guint *)gmalloc(nRefSegs * sizeof(Guint));
+ refSegs = (Guint *)gmallocn(nRefSegs, sizeof(Guint));
if (segNum <= 256) {
for (i = 0; i < nRefSegs; ++i) {
if (!readUByte(&refSegs[i])) {
// read the segment data
switch (segType) {
case 0:
- readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs);
+ if (!readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs)) {
+ goto syntaxError;
+ }
break;
case 4:
readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs);
return;
+ syntaxError:
+ gfree(refSegs);
+ return;
+
eofError2:
gfree(refSegs);
eofError1:
error(getPos(), "Unexpected EOF in JBIG2 stream");
}
-void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
- Guint *refSegs, Guint nRefSegs) {
+GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
+ Guint *refSegs, Guint nRefSegs) {
JBIG2SymbolDict *symbolDict;
JBIG2HuffmanTable *huffDHTable, *huffDWTable;
JBIG2HuffmanTable *huffBMSizeTable, *huffAggInstTable;
}
// get the input symbol bitmaps
- bitmaps = (JBIG2Bitmap **)gmalloc((numInputSyms + numNewSyms) *
- sizeof(JBIG2Bitmap *));
+ bitmaps = (JBIG2Bitmap **)gmallocn(numInputSyms + numNewSyms,
+ sizeof(JBIG2Bitmap *));
+ for (i = 0; i < numInputSyms + numNewSyms; ++i) {
+ bitmaps[i] = NULL;
+ }
k = 0;
inputSymbolDict = NULL;
for (i = 0; i < nRefSegs; ++i) {
// allocate symbol widths storage
symWidths = NULL;
if (huff && !refAgg) {
- symWidths = (Guint *)gmalloc(numNewSyms * sizeof(Guint));
+ symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint));
}
symHeight = 0;
} else {
arithDecoder->decodeInt(&dh, iadhStats);
}
+ if (dh < 0 && (Guint)-dh >= symHeight) {
+ error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
symHeight += dh;
symWidth = 0;
totalWidth = 0;
break;
}
}
+ if (dw < 0 && (Guint)-dw >= symWidth) {
+ error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
symWidth += dw;
// using a collective bitmap, so don't read a bitmap here
// store the new symbol dict
segments->append(symbolDict);
- return;
+ return gTrue;
+
+ syntaxError:
+ for (i = 0; i < numNewSyms; ++i) {
+ if (bitmaps[numInputSyms + i]) {
+ delete bitmaps[numInputSyms + i];
+ }
+ }
+ gfree(bitmaps);
+ if (symWidths) {
+ gfree(symWidths);
+ }
+ return gFalse;
eofError:
error(getPos(), "Unexpected EOF in JBIG2 stream");
+ return gFalse;
}
void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
codeTables = new GList();
numSyms = 0;
for (i = 0; i < nRefSegs; ++i) {
- seg = findSegment(refSegs[i]);
- if (seg->getType() == jbig2SegSymbolDict) {
- numSyms += ((JBIG2SymbolDict *)seg)->getSize();
- } else if (seg->getType() == jbig2SegCodeTable) {
- codeTables->append(seg);
+ if ((seg = findSegment(refSegs[i]))) {
+ if (seg->getType() == jbig2SegSymbolDict) {
+ numSyms += ((JBIG2SymbolDict *)seg)->getSize();
+ } else if (seg->getType() == jbig2SegCodeTable) {
+ codeTables->append(seg);
+ }
+ } else {
+ error(getPos(), "Invalid segment reference in JBIG2 text region");
}
}
symCodeLen = 0;
}
// get the symbol bitmaps
- syms = (JBIG2Bitmap **)gmalloc(numSyms * sizeof(JBIG2Bitmap *));
+ syms = (JBIG2Bitmap **)gmallocn(numSyms, sizeof(JBIG2Bitmap *));
kk = 0;
for (i = 0; i < nRefSegs; ++i) {
- seg = findSegment(refSegs[i]);
- if (seg->getType() == jbig2SegSymbolDict) {
- symbolDict = (JBIG2SymbolDict *)seg;
- for (k = 0; k < symbolDict->getSize(); ++k) {
- syms[kk++] = symbolDict->getBitmap(k);
+ if ((seg = findSegment(refSegs[i]))) {
+ if (seg->getType() == jbig2SegSymbolDict) {
+ symbolDict = (JBIG2SymbolDict *)seg;
+ for (k = 0; k < symbolDict->getSize(); ++k) {
+ syms[kk++] = symbolDict->getBitmap(k);
+ }
}
}
}
runLengthTab[35].prefixLen = 0;
runLengthTab[35].rangeLen = jbig2HuffmanEOT;
huffDecoder->buildTable(runLengthTab, 35);
- symCodeTab = (JBIG2HuffmanTable *)gmalloc((numSyms + 1) *
- sizeof(JBIG2HuffmanTable));
+ symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1,
+ sizeof(JBIG2HuffmanTable));
for (i = 0; i < numSyms; ++i) {
symCodeTab[i].val = i;
symCodeTab[i].rangeLen = 0;
symID = arithDecoder->decodeIAID(symCodeLen, iaidStats);
}
- // get the symbol bitmap
- symbolBitmap = NULL;
- if (refine) {
- if (huff) {
- ri = (int)huffDecoder->readBit();
+ if (symID >= (Guint)numSyms) {
+ error(getPos(), "Invalid symbol number in JBIG2 text region");
+ } else {
+
+ // get the symbol bitmap
+ symbolBitmap = NULL;
+ if (refine) {
+ if (huff) {
+ ri = (int)huffDecoder->readBit();
+ } else {
+ arithDecoder->decodeInt(&ri, iariStats);
+ }
} else {
- arithDecoder->decodeInt(&ri, iariStats);
+ ri = 0;
}
- } else {
- ri = 0;
- }
- if (ri) {
- if (huff) {
- huffDecoder->decodeInt(&rdw, huffRDWTable);
- huffDecoder->decodeInt(&rdh, huffRDHTable);
- huffDecoder->decodeInt(&rdx, huffRDXTable);
- huffDecoder->decodeInt(&rdy, huffRDYTable);
- huffDecoder->decodeInt(&bmSize, huffRSizeTable);
- huffDecoder->reset();
- arithDecoder->start();
+ if (ri) {
+ if (huff) {
+ huffDecoder->decodeInt(&rdw, huffRDWTable);
+ huffDecoder->decodeInt(&rdh, huffRDHTable);
+ huffDecoder->decodeInt(&rdx, huffRDXTable);
+ huffDecoder->decodeInt(&rdy, huffRDYTable);
+ huffDecoder->decodeInt(&bmSize, huffRSizeTable);
+ huffDecoder->reset();
+ arithDecoder->start();
+ } else {
+ arithDecoder->decodeInt(&rdw, iardwStats);
+ arithDecoder->decodeInt(&rdh, iardhStats);
+ arithDecoder->decodeInt(&rdx, iardxStats);
+ arithDecoder->decodeInt(&rdy, iardyStats);
+ }
+ refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx;
+ refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy;
+
+ symbolBitmap =
+ readGenericRefinementRegion(rdw + syms[symID]->getWidth(),
+ rdh + syms[symID]->getHeight(),
+ templ, gFalse, syms[symID],
+ refDX, refDY, atx, aty);
+ //~ do we need to use the bmSize value here (in Huffman mode)?
} else {
- arithDecoder->decodeInt(&rdw, iardwStats);
- arithDecoder->decodeInt(&rdh, iardhStats);
- arithDecoder->decodeInt(&rdx, iardxStats);
- arithDecoder->decodeInt(&rdy, iardyStats);
+ symbolBitmap = syms[symID];
}
- refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx;
- refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy;
-
- symbolBitmap =
- readGenericRefinementRegion(rdw + syms[symID]->getWidth(),
- rdh + syms[symID]->getHeight(),
- templ, gFalse, syms[symID],
- refDX, refDY, atx, aty);
- //~ do we need to use the bmSize value here (in Huffman mode)?
- } else {
- symbolBitmap = syms[symID];
- }
- // combine the symbol bitmap into the region bitmap
- //~ something is wrong here - refCorner shouldn't degenerate into
- //~ two cases
- bw = symbolBitmap->getWidth() - 1;
- bh = symbolBitmap->getHeight() - 1;
- if (transposed) {
- switch (refCorner) {
- case 0: // bottom left
- bitmap->combine(symbolBitmap, tt, s, combOp);
- break;
- case 1: // top left
- bitmap->combine(symbolBitmap, tt, s, combOp);
- break;
- case 2: // bottom right
- bitmap->combine(symbolBitmap, tt - bw, s, combOp);
- break;
- case 3: // top right
- bitmap->combine(symbolBitmap, tt - bw, s, combOp);
- break;
+ // combine the symbol bitmap into the region bitmap
+ //~ something is wrong here - refCorner shouldn't degenerate into
+ //~ two cases
+ bw = symbolBitmap->getWidth() - 1;
+ bh = symbolBitmap->getHeight() - 1;
+ if (transposed) {
+ switch (refCorner) {
+ case 0: // bottom left
+ bitmap->combine(symbolBitmap, tt, s, combOp);
+ break;
+ case 1: // top left
+ bitmap->combine(symbolBitmap, tt, s, combOp);
+ break;
+ case 2: // bottom right
+ bitmap->combine(symbolBitmap, tt - bw, s, combOp);
+ break;
+ case 3: // top right
+ bitmap->combine(symbolBitmap, tt - bw, s, combOp);
+ break;
+ }
+ s += bh;
+ } else {
+ switch (refCorner) {
+ case 0: // bottom left
+ bitmap->combine(symbolBitmap, s, tt - bh, combOp);
+ break;
+ case 1: // top left
+ bitmap->combine(symbolBitmap, s, tt, combOp);
+ break;
+ case 2: // bottom right
+ bitmap->combine(symbolBitmap, s, tt - bh, combOp);
+ break;
+ case 3: // top right
+ bitmap->combine(symbolBitmap, s, tt, combOp);
+ break;
+ }
+ s += bw;
}
- s += bh;
- } else {
- switch (refCorner) {
- case 0: // bottom left
- bitmap->combine(symbolBitmap, s, tt - bh, combOp);
- break;
- case 1: // top left
- bitmap->combine(symbolBitmap, s, tt, combOp);
- break;
- case 2: // bottom right
- bitmap->combine(symbolBitmap, s, tt - bh, combOp);
- break;
- case 3: // top right
- bitmap->combine(symbolBitmap, s, tt, combOp);
- break;
+ if (ri) {
+ delete symbolBitmap;
}
- s += bw;
- }
- if (ri) {
- delete symbolBitmap;
}
// next instance
}
// read the gray-scale image
- grayImg = (Guint *)gmalloc(gridW * gridH * sizeof(Guint));
+ grayImg = (Guint *)gmallocn(gridW * gridH, sizeof(Guint));
memset(grayImg, 0, gridW * gridH * sizeof(Guint));
atx[0] = templ <= 1 ? 3 : 2; aty[0] = -1;
atx[1] = -3; aty[1] = -1;
if (mmr) {
mmrDecoder->reset();
- refLine = (int *)gmalloc((w + 2) * sizeof(int));
- codingLine = (int *)gmalloc((w + 2) * sizeof(int));
+ refLine = (int *)gmallocn(w + 2, sizeof(int));
+ codingLine = (int *)gmallocn(w + 2, sizeof(int));
codingLine[0] = codingLine[1] = w;
for (y = 0; y < h; ++y) {
huffDecoder->reset();
huffTabSize = 8;
huffTab = (JBIG2HuffmanTable *)
- gmalloc(huffTabSize * sizeof(JBIG2HuffmanTable));
+ gmallocn(huffTabSize, sizeof(JBIG2HuffmanTable));
i = 0;
val = lowVal;
while (val < highVal) {
if (i == huffTabSize) {
huffTabSize *= 2;
huffTab = (JBIG2HuffmanTable *)
- grealloc(huffTab, huffTabSize * sizeof(JBIG2HuffmanTable));
+ greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable));
}
huffTab[i].val = val;
huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
if (i + oob + 3 > huffTabSize) {
huffTabSize = i + oob + 3;
huffTab = (JBIG2HuffmanTable *)
- grealloc(huffTab, huffTabSize * sizeof(JBIG2HuffmanTable));
+ greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable));
}
huffTab[i].val = lowVal - 1;
huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
private:
void readSegments();
- void readSymbolDictSeg(Guint segNum, Guint length,
- Guint *refSegs, Guint nRefSegs);
+ GBool readSymbolDictSeg(Guint segNum, Guint length,
+ Guint *refSegs, Guint nRefSegs);
void readTextRegionSeg(Guint segNum, GBool imm,
GBool lossless, Guint length,
Guint *refSegs, Guint nRefSegs);
for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
cb = &subband->cbs[k];
gfree(cb->coeffs);
+ if (cb->arithDecoder) {
+ delete cb->arithDecoder;
+ }
if (cb->stats) {
delete cb->stats;
}
return str->isBinary(gTrue);
}
+void JPXStream::getImageParams(int *bitsPerComponent,
+ StreamColorSpaceMode *csMode) {
+ Guint boxType, boxLen, dataLen, csEnum;
+ Guint bpc1, dummy, i;
+ int csMeth, csPrec, csPrec1, dummy2;
+ StreamColorSpaceMode csMode1;
+ GBool haveBPC, haveCSMode;
+
+ csPrec = 0; // make gcc happy
+ haveBPC = haveCSMode = gFalse;
+ str->reset();
+ if (str->lookChar() == 0xff) {
+ getImageParams2(bitsPerComponent, csMode);
+ } else {
+ while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
+ if (boxType == 0x6a703268) { // JP2 header
+ // skip the superbox
+ } else if (boxType == 0x69686472) { // image header
+ if (readULong(&dummy) &&
+ readULong(&dummy) &&
+ readUWord(&dummy) &&
+ readUByte(&bpc1) &&
+ readUByte(&dummy) &&
+ readUByte(&dummy) &&
+ readUByte(&dummy)) {
+ *bitsPerComponent = bpc1 + 1;
+ haveBPC = gTrue;
+ }
+ } else if (boxType == 0x636F6C72) { // color specification
+ if (readByte(&csMeth) &&
+ readByte(&csPrec1) &&
+ readByte(&dummy2)) {
+ if (csMeth == 1) {
+ if (readULong(&csEnum)) {
+ csMode1 = streamCSNone;
+ if (csEnum == jpxCSBiLevel ||
+ csEnum == jpxCSGrayscale) {
+ csMode1 = streamCSDeviceGray;
+ } else if (csEnum == jpxCSCMYK) {
+ csMode1 = streamCSDeviceCMYK;
+ } else if (csEnum == jpxCSsRGB ||
+ csEnum == jpxCSCISesRGB ||
+ csEnum == jpxCSROMMRGB) {
+ csMode1 = streamCSDeviceRGB;
+ }
+ if (csMode1 != streamCSNone &&
+ (!haveCSMode || csPrec1 > csPrec)) {
+ *csMode = csMode1;
+ csPrec = csPrec1;
+ haveCSMode = gTrue;
+ }
+ for (i = 0; i < dataLen - 7; ++i) {
+ str->getChar();
+ }
+ }
+ } else {
+ for (i = 0; i < dataLen - 3; ++i) {
+ str->getChar();
+ }
+ }
+ }
+ } else if (boxType == 0x6A703263) { // codestream
+ if (!(haveBPC && haveCSMode)) {
+ getImageParams2(bitsPerComponent, csMode);
+ }
+ break;
+ } else {
+ for (i = 0; i < dataLen; ++i) {
+ str->getChar();
+ }
+ }
+ }
+ }
+ str->close();
+}
+
+// Get image parameters from the codestream.
+void JPXStream::getImageParams2(int *bitsPerComponent,
+ StreamColorSpaceMode *csMode) {
+ int segType;
+ Guint segLen, nComps1, bpc1, dummy, i;
+
+ while (readMarkerHdr(&segType, &segLen)) {
+ if (segType == 0x51) { // SIZ - image and tile size
+ if (readUWord(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readUWord(&nComps1) &&
+ readUByte(&bpc1)) {
+ *bitsPerComponent = (bpc1 & 0x7f) + 1;
+ // if there's no color space info, take a guess
+ if (nComps1 == 1) {
+ *csMode = streamCSDeviceGray;
+ } else if (nComps1 == 3) {
+ *csMode = streamCSDeviceRGB;
+ } else if (nComps1 == 4) {
+ *csMode = streamCSDeviceCMYK;
+ }
+ }
+ break;
+ } else {
+ if (segLen > 2) {
+ for (i = 0; i < segLen - 2; ++i) {
+ str->getChar();
+ }
+ }
+ }
+ }
+}
+
GBool JPXStream::readBoxes() {
Guint boxType, boxLen, dataLen;
Guint bpc1, compression, unknownColorspace, ipr;
error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper");
readCodestream(0);
nComps = img.nComps;
- bpc = (Guint *)gmalloc(nComps * sizeof(Guint));
+ bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
for (i = 0; i < nComps; ++i) {
bpc[i] = img.tiles[0].tileComps[i].prec;
}
error(getPos(), "Unknown compression type in JPX stream");
return gFalse;
}
- bpc = (Guint *)gmalloc(nComps * sizeof(Guint));
+ bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
for (i = 0; i < nComps; ++i) {
bpc[i] = bpc1;
}
error(getPos(), "Unexpected EOF in JPX stream");
return gFalse;
}
- palette.bpc = (Guint *)gmalloc(palette.nComps * sizeof(Guint));
+ palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint));
palette.c =
- (int *)gmalloc(palette.nEntries * palette.nComps * sizeof(int));
+ (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int));
for (i = 0; i < palette.nComps; ++i) {
if (!readUByte(&palette.bpc[i])) {
error(getPos(), "Unexpected EOF in JPX stream");
break;
case 0x636d6170: // component mapping
compMap.nChannels = dataLen / 4;
- compMap.comp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
- compMap.type = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
- compMap.pComp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
+ compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+ compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+ compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
for (i = 0; i < compMap.nChannels; ++i) {
if (!readUWord(&compMap.comp[i]) ||
!readUByte(&compMap.type[i]) ||
return gFalse;
}
channelDefn.idx =
- (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
+ (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
channelDefn.type =
- (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
+ (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
channelDefn.assoc =
- (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
+ (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
for (i = 0; i < channelDefn.nChannels; ++i) {
if (!readUWord(&channelDefn.idx[i]) ||
!readUWord(&channelDefn.type[i]) ||
case 0x6A703263: // contiguous codestream
if (!bpc) {
error(getPos(), "JPX stream is missing the image header box");
- return gFalse;
}
if (!haveCS) {
error(getPos(), "JPX stream has no supported color spec");
- return gFalse;
}
if (!readCodestream(dataLen)) {
return gFalse;
ok = gTrue;
break;
case jpxCSCIELab:
- if (dataLen == 3 + 7*4) {
+ if (dataLen == 7 + 7*4) {
if (!readULong(&newCS.enumerated.cieLab.rl) ||
!readULong(&newCS.enumerated.cieLab.ol) ||
!readULong(&newCS.enumerated.cieLab.ra) ||
!readULong(&newCS.enumerated.cieLab.il)) {
goto err;
}
- } else if (dataLen == 3) {
+ } else if (dataLen == 7) {
//~ this assumes the 8-bit case
newCS.enumerated.cieLab.rl = 100;
newCS.enumerated.cieLab.ol = 0;
int segType;
GBool haveSIZ, haveCOD, haveQCD, haveSOT;
Guint precinctSize, style;
- Guint segLen, capabilities, comp, i, j, r;
+ Guint segLen, capabilities, nTiles, comp, i, j, r;
//----- main header
haveSIZ = haveCOD = haveQCD = haveSOT = gFalse;
/ img.xTileSize;
img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1)
/ img.yTileSize;
- img.tiles = (JPXTile *)gmalloc(img.nXTiles * img.nYTiles *
- sizeof(JPXTile));
+ nTiles = img.nXTiles * img.nYTiles;
+ // check for overflow before allocating memory
+ if (nTiles == 0 || nTiles / img.nXTiles != img.nYTiles) {
+ error(getPos(), "Bad tile count in JPX SIZ marker segment");
+ return gFalse;
+ }
+ img.tiles = (JPXTile *)gmallocn(nTiles, sizeof(JPXTile));
for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
- img.tiles[i].tileComps = (JPXTileComp *)gmalloc(img.nComps *
- sizeof(JPXTileComp));
+ img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps,
+ sizeof(JPXTileComp));
for (comp = 0; comp < img.nComps; ++comp) {
img.tiles[i].tileComps[comp].quantSteps = NULL;
img.tiles[i].tileComps[comp].data = NULL;
img.tiles[0].tileComps[0].transform;
}
img.tiles[i].tileComps[comp].resLevels =
- (JPXResLevel *)gmalloc(
- (img.tiles[i].tileComps[comp].nDecompLevels + 1) *
+ (JPXResLevel *)gmallocn(
+ (img.tiles[i].tileComps[comp].nDecompLevels + 1),
sizeof(JPXResLevel));
for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
img.tiles[0].tileComps[comp].transform;
}
img.tiles[i].tileComps[comp].resLevels =
- (JPXResLevel *)grealloc(
+ (JPXResLevel *)greallocn(
img.tiles[i].tileComps[comp].resLevels,
- (img.tiles[i].tileComps[comp].nDecompLevels + 1) *
- sizeof(JPXResLevel));
+ (img.tiles[i].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
}
if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) {
img.tiles[0].tileComps[0].nQuantSteps = segLen - 3;
img.tiles[0].tileComps[0].quantSteps =
- (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
- img.tiles[0].tileComps[0].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) {
error(getPos(), "Error in JPX QCD marker segment");
} else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) {
img.tiles[0].tileComps[0].nQuantSteps = 1;
img.tiles[0].tileComps[0].quantSteps =
- (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
- img.tiles[0].tileComps[0].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) {
error(getPos(), "Error in JPX QCD marker segment");
return gFalse;
} else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) {
img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2;
img.tiles[0].tileComps[0].quantSteps =
- (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
- img.tiles[0].tileComps[0].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) {
error(getPos(), "Error in JPX QCD marker segment");
img.tiles[i].tileComps[comp].nQuantSteps =
img.tiles[0].tileComps[0].nQuantSteps;
img.tiles[i].tileComps[comp].quantSteps =
- (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps,
- img.tiles[0].tileComps[0].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) {
img.tiles[i].tileComps[comp].quantSteps[j] =
img.tiles[0].tileComps[0].quantSteps[j];
img.tiles[0].tileComps[comp].nQuantSteps =
segLen - (img.nComps > 256 ? 5 : 4);
img.tiles[0].tileComps[comp].quantSteps =
- (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
- img.tiles[0].tileComps[comp].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) {
error(getPos(), "Error in JPX QCC marker segment");
} else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) {
img.tiles[0].tileComps[comp].nQuantSteps = 1;
img.tiles[0].tileComps[comp].quantSteps =
- (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
- img.tiles[0].tileComps[comp].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) {
error(getPos(), "Error in JPX QCC marker segment");
return gFalse;
img.tiles[0].tileComps[comp].nQuantSteps =
(segLen - (img.nComps > 256 ? 5 : 4)) / 2;
img.tiles[0].tileComps[comp].quantSteps =
- (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
- img.tiles[0].tileComps[comp].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) {
error(getPos(), "Error in JPX QCD marker segment");
img.tiles[i].tileComps[comp].nQuantSteps =
img.tiles[0].tileComps[comp].nQuantSteps;
img.tiles[i].tileComps[comp].quantSteps =
- (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps,
- img.tiles[0].tileComps[comp].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) {
img.tiles[i].tileComps[comp].quantSteps[j] =
img.tiles[0].tileComps[comp].quantSteps[j];
}
#else
nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
- progs = (JPXProgOrder *)gmalloc(nProgs * sizeof(JPXProgOrder));
+ progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder));
for (i = 0; i < nProgs; ++i) {
if (!readUByte(&progs[i].startRes) ||
!(img.nComps > 256 && readUWord(&progs[i].startComp)) ||
img.tiles[tileIdx].tileComps[0].transform;
}
img.tiles[tileIdx].tileComps[comp].resLevels =
- (JPXResLevel *)grealloc(
+ (JPXResLevel *)greallocn(
img.tiles[tileIdx].tileComps[comp].resLevels,
- (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) *
- sizeof(JPXResLevel));
+ (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
for (r = 0;
r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
++r) {
img.tiles[tileIdx].tileComps[comp].codeBlockW += 2;
img.tiles[tileIdx].tileComps[comp].codeBlockH += 2;
img.tiles[tileIdx].tileComps[comp].resLevels =
- (JPXResLevel *)grealloc(
+ (JPXResLevel *)greallocn(
img.tiles[tileIdx].tileComps[comp].resLevels,
- (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) *
- sizeof(JPXResLevel));
+ (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
}
img.tiles[tileIdx].tileComps[0].nQuantSteps =
segLen - 3;
img.tiles[tileIdx].tileComps[0].quantSteps =
- (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
- img.tiles[tileIdx].tileComps[0].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
error(getPos(), "Error in JPX QCD marker segment");
} else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) {
img.tiles[tileIdx].tileComps[0].nQuantSteps = 1;
img.tiles[tileIdx].tileComps[0].quantSteps =
- (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
- img.tiles[tileIdx].tileComps[0].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) {
error(getPos(), "Error in JPX QCD marker segment");
return gFalse;
} else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) {
img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2;
img.tiles[tileIdx].tileComps[0].quantSteps =
- (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
- img.tiles[tileIdx].tileComps[0].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
error(getPos(), "Error in JPX QCD marker segment");
img.tiles[tileIdx].tileComps[comp].nQuantSteps =
img.tiles[tileIdx].tileComps[0].nQuantSteps;
img.tiles[tileIdx].tileComps[comp].quantSteps =
- (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
- img.tiles[tileIdx].tileComps[0].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) {
img.tiles[tileIdx].tileComps[comp].quantSteps[j] =
img.tiles[tileIdx].tileComps[0].quantSteps[j];
img.tiles[tileIdx].tileComps[comp].nQuantSteps =
segLen - (img.nComps > 256 ? 5 : 4);
img.tiles[tileIdx].tileComps[comp].quantSteps =
- (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
- img.tiles[tileIdx].tileComps[comp].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
error(getPos(), "Error in JPX QCC marker segment");
== 0x01) {
img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1;
img.tiles[tileIdx].tileComps[comp].quantSteps =
- (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
- img.tiles[tileIdx].tileComps[comp].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) {
error(getPos(), "Error in JPX QCC marker segment");
return gFalse;
img.tiles[tileIdx].tileComps[comp].nQuantSteps =
(segLen - (img.nComps > 256 ? 5 : 4)) / 2;
img.tiles[tileIdx].tileComps[comp].quantSteps =
- (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
- img.tiles[tileIdx].tileComps[comp].nQuantSteps *
- sizeof(Guint));
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
error(getPos(), "Error in JPX QCD marker segment");
}
#else
nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
- tileProgs = (JPXProgOrder *)gmalloc(nTileProgs * sizeof(JPXProgOrder));
+ tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder));
for (i = 0; i < nTileProgs; ++i) {
if (!readUByte(&tileProgs[i].startRes) ||
!(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) ||
tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep);
tileComp->cbW = 1 << tileComp->codeBlockW;
tileComp->cbH = 1 << tileComp->codeBlockH;
- tileComp->data = (int *)gmalloc((tileComp->x1 - tileComp->x0) *
- (tileComp->y1 - tileComp->y0) *
- sizeof(int));
+ tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) *
+ (tileComp->y1 - tileComp->y0),
+ sizeof(int));
if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
n = tileComp->x1 - tileComp->x0;
} else {
n = tileComp->y1 - tileComp->y0;
}
- tileComp->buf = (int *)gmalloc((n + 8) * sizeof(int));
+ tileComp->buf = (int *)gmallocn(n + 8, sizeof(int));
for (r = 0; r <= tileComp->nDecompLevels; ++r) {
resLevel = &tileComp->resLevels[r];
k = r == 0 ? tileComp->nDecompLevels
resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
}
- resLevel->precincts = (JPXPrecinct *)gmalloc(1 * sizeof(JPXPrecinct));
+ resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct));
for (pre = 0; pre < 1; ++pre) {
precinct = &resLevel->precincts[pre];
precinct->x0 = resLevel->x0;
precinct->y1 = resLevel->y1;
nSBs = r == 0 ? 1 : 3;
precinct->subbands =
- (JPXSubband *)gmalloc(nSBs * sizeof(JPXSubband));
+ (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband));
for (sb = 0; sb < nSBs; ++sb) {
subband = &precinct->subbands[sb];
subband->x0 = resLevel->bx0[sb];
n += nx * ny;
}
subband->inclusion =
- (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode));
+ (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
subband->zeroBitPlane =
- (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode));
+ (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
for (k = 0; k < n; ++k) {
subband->inclusion[k].finished = gFalse;
subband->inclusion[k].val = 0;
subband->zeroBitPlane[k].finished = gFalse;
subband->zeroBitPlane[k].val = 0;
}
- subband->cbs = (JPXCodeBlock *)gmalloc(subband->nXCBs *
- subband->nYCBs *
- sizeof(JPXCodeBlock));
+ subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs *
+ subband->nYCBs,
+ sizeof(JPXCodeBlock));
sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW);
sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH);
cb = subband->cbs;
cb->nextPass = jpxPassCleanup;
cb->nZeroBitPlanes = 0;
cb->coeffs =
- (JPXCoeff *)gmalloc((1 << (tileComp->codeBlockW
- + tileComp->codeBlockH))
- * sizeof(JPXCoeff));
+ (JPXCoeff *)gmallocn((1 << (tileComp->codeBlockW
+ + tileComp->codeBlockH)),
+ sizeof(JPXCoeff));
for (cbi = 0;
cbi < (Guint)(1 << (tileComp->codeBlockW
+ tileComp->codeBlockH));
cb->coeffs[cbi].len = 0;
cb->coeffs[cbi].mag = 0;
}
- cb->stats = new JArithmeticDecoderStats(jpxNContexts);
- cb->stats->setEntry(jpxContextSigProp, 4, 0);
- cb->stats->setEntry(jpxContextRunLength, 3, 0);
- cb->stats->setEntry(jpxContextUniform, 46, 0);
+ cb->arithDecoder = NULL;
+ cb->stats = NULL;
++cb;
}
}
Guint res, Guint sb,
JPXCodeBlock *cb) {
JPXCoeff *coeff0, *coeff1, *coeff;
- JArithmeticDecoder *arithDecoder;
Guint horiz, vert, diag, all, cx, xorBit;
int horizSign, vertSign;
Guint i, x, y0, y1, y2;
- arithDecoder = new JArithmeticDecoder();
- arithDecoder->setStream(str, cb->dataLen);
- arithDecoder->start();
+ if (cb->arithDecoder) {
+ cb->arithDecoder->restart(cb->dataLen);
+ } else {
+ cb->arithDecoder = new JArithmeticDecoder();
+ cb->arithDecoder->setStream(str, cb->dataLen);
+ cb->arithDecoder->start();
+ cb->stats = new JArithmeticDecoderStats(jpxNContexts);
+ cb->stats->setEntry(jpxContextSigProp, 4, 0);
+ cb->stats->setEntry(jpxContextRunLength, 3, 0);
+ cb->stats->setEntry(jpxContextUniform, 46, 0);
+ }
for (i = 0; i < cb->nCodingPasses; ++i) {
switch (cb->nextPass) {
horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
}
if (y0+y1 > cb->y0) {
- diag += (coeff[-tileComp->cbW - 1].flags
+ diag += (coeff[-(int)tileComp->cbW - 1].flags
>> jpxCoeffSignificantB) & 1;
}
if (y0+y1 < cb->y1 - 1) {
horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
}
if (y0+y1 > cb->y0) {
- diag += (coeff[-tileComp->cbW + 1].flags
+ diag += (coeff[-(int)tileComp->cbW + 1].flags
>> jpxCoeffSignificantB) & 1;
}
if (y0+y1 < cb->y1 - 1) {
}
}
if (y0+y1 > cb->y0) {
- if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) {
+ if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) {
++vert;
- vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign)
+ vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign)
? -1 : 1;
}
}
}
cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
if (cx != 0) {
- if (arithDecoder->decodeBit(cx, cb->stats)) {
+ if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
coeff->mag = (coeff->mag << 1) | 1;
cx = signContext[horizSign][vertSign][0];
xorBit = signContext[horizSign][vertSign][1];
- if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+ if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
coeff->flags |= jpxCoeffSign;
}
}
if (x > cb->x0) {
all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1;
if (y0+y1 > cb->y0) {
- all += (coeff[-tileComp->cbW - 1].flags
+ all += (coeff[-(int)tileComp->cbW - 1].flags
>> jpxCoeffSignificantB) & 1;
}
if (y0+y1 < cb->y1 - 1) {
if (x < cb->x1 - 1) {
all += (coeff[1].flags >> jpxCoeffSignificantB) & 1;
if (y0+y1 > cb->y0) {
- all += (coeff[-tileComp->cbW + 1].flags
+ all += (coeff[-(int)tileComp->cbW + 1].flags
>> jpxCoeffSignificantB) & 1;
}
if (y0+y1 < cb->y1 - 1) {
}
}
if (y0+y1 > cb->y0) {
- all += (coeff[-tileComp->cbW].flags
+ all += (coeff[-(int)tileComp->cbW].flags
>> jpxCoeffSignificantB) & 1;
}
if (y0+y1 < cb->y1 - 1) {
cx = 16;
}
coeff->mag = (coeff->mag << 1) |
- arithDecoder->decodeBit(cx, cb->stats);
+ cb->arithDecoder->decodeBit(cx, cb->stats);
++coeff->len;
coeff->flags |= jpxCoeffTouched;
coeff->flags &= ~jpxCoeffFirstMagRef;
!(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) &&
!(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) &&
(x == cb->x0 || y0 == cb->y0 ||
- !(coeff1[-tileComp->cbW - 1].flags
+ !(coeff1[-(int)tileComp->cbW - 1].flags
& jpxCoeffSignificant)) &&
(y0 == cb->y0 ||
- !(coeff1[-tileComp->cbW].flags & jpxCoeffSignificant)) &&
+ !(coeff1[-(int)tileComp->cbW].flags
+ & jpxCoeffSignificant)) &&
(x == cb->x1 - 1 || y0 == cb->y0 ||
- !(coeff1[-tileComp->cbW + 1].flags & jpxCoeffSignificant)) &&
+ !(coeff1[-(int)tileComp->cbW + 1].flags
+ & jpxCoeffSignificant)) &&
(x == cb->x0 ||
(!(coeff1[-1].flags & jpxCoeffSignificant) &&
!(coeff1[tileComp->cbW - 1].flags
(x == cb->x1 - 1 || y0+4 == cb->y1 ||
!(coeff1[4 * tileComp->cbW + 1].flags
& jpxCoeffSignificant))) {
- if (arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
- y1 = arithDecoder->decodeBit(jpxContextUniform, cb->stats);
+ if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
+ y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
y1 = (y1 << 1) |
- arithDecoder->decodeBit(jpxContextUniform, cb->stats);
+ cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
for (y2 = 0, coeff = coeff1;
y2 < y1;
++y2, coeff += tileComp->cbW) {
++coeff->len;
cx = signContext[2][2][0];
xorBit = signContext[2][2][1];
- if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+ if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
coeff->flags |= jpxCoeffSign;
}
++y1;
horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
}
if (y0+y1 > cb->y0) {
- diag += (coeff[-tileComp->cbW - 1].flags
+ diag += (coeff[-(int)tileComp->cbW - 1].flags
>> jpxCoeffSignificantB) & 1;
}
if (y0+y1 < cb->y1 - 1) {
horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
}
if (y0+y1 > cb->y0) {
- diag += (coeff[-tileComp->cbW + 1].flags
+ diag += (coeff[-(int)tileComp->cbW + 1].flags
>> jpxCoeffSignificantB) & 1;
}
if (y0+y1 < cb->y1 - 1) {
}
}
if (y0+y1 > cb->y0) {
- if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) {
+ if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) {
++vert;
- vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign)
+ vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign)
? -1 : 1;
}
}
}
}
cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
- if (arithDecoder->decodeBit(cx, cb->stats)) {
+ if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
coeff->mag = (coeff->mag << 1) | 1;
cx = signContext[horizSign][vertSign][0];
xorBit = signContext[horizSign][vertSign][1];
- if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+ if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
coeff->flags |= jpxCoeffSign;
}
}
}
}
- delete arithDecoder;
+ cb->arithDecoder->cleanup();
return gTrue;
}
JPXSubband *subband;
JPXCodeBlock *cb;
JPXCoeff *coeff0, *coeff;
- Guint qStyle, guard, eps, shift, shift2;
+ Guint qStyle, guard, eps, shift;
+ int shift2;
double mu;
int val;
int *dataPtr;
JPXSubband *subband;
JPXCodeBlock *cb;
JPXCoeff *coeff0, *coeff;
- Guint qStyle, guard, eps, shift, shift2, t;
+ Guint qStyle, guard, eps, shift, t;
+ int shift2;
double mu;
int val;
int *dataPtr;
// converts fixed point samples back to integers.
GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
JPXTileComp *tileComp;
- int coeff, d0, d1, d2, minVal, maxVal, zeroVal;
+ int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal;
int *dataPtr;
Guint j, comp, x, y;
d0 = tile->tileComps[0].data[j];
d1 = tile->tileComps[1].data[j];
d2 = tile->tileComps[2].data[j];
- tile->tileComps[0].data[j] = d0 - ((d2 + d1) >> 2);
- tile->tileComps[1].data[j] = d2 - d1;
- tile->tileComps[2].data[j] = d0 - d1;
+ tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2);
+ tile->tileComps[0].data[j] = d2 + t;
+ tile->tileComps[2].data[j] = d1 + t;
++j;
}
}
jpxCSYPbPr1250 = 24
};
+struct JPXColorSpecCIELab {
+ Guint rl, ol, ra, oa, rb, ob, il;
+};
+
+struct JPXColorSpecEnumerated {
+ JPXColorSpaceType type; // color space type
+ union {
+ JPXColorSpecCIELab cieLab;
+ };
+};
+
struct JPXColorSpec {
Guint meth; // method
int prec; // precedence
union {
- struct {
- JPXColorSpaceType type; // color space type
- union {
- struct {
- Guint rl, ol, ra, oa, rb, ob, il;
- } cieLab;
- };
- } enumerated;
+ JPXColorSpecEnumerated enumerated;
};
};
//----- coefficient data
JPXCoeff *coeffs; // the coefficients
+ JArithmeticDecoder // arithmetic decoder
+ *arithDecoder;
JArithmeticDecoderStats // arithmetic decoder stats
*stats;
};
virtual int lookChar();
virtual GString *getPSFilter(int psLevel, char *indent);
virtual GBool isBinary(GBool last = gTrue);
+ virtual void getImageParams(int *bitsPerComponent,
+ StreamColorSpaceMode *csMode);
private:
void fillReadBuf();
+ void getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode);
GBool readBoxes();
GBool readColorSpecBox(Guint dataLen);
GBool readCodestream(Guint len);
scale = 0.1;
while (1) {
c = lookChar();
+ if (c == '-') {
+ // ignore minus signs in the middle of numbers to match
+ // Adobe's behavior
+ error(getPos(), "Badly formatted number");
+ getChar();
+ continue;
+ }
if (!isdigit(c)) {
break;
}
}
}
}
+
+GBool Lexer::isSpace(int c) {
+ return c >= 0 && c <= 0xff && specialChars[c] == 1;
+}
void setPos(Guint pos, int dir = 0)
{ if (!curStr.isNone()) curStr.streamSetPos(pos, dir); }
+ // Returns true if <c> is a whitespace character.
+ static GBool isSpace(int c);
+
private:
int getChar();
// dictionary
} else if (fileSpecObj->isDict()) {
+#ifdef WIN32
+ if (!fileSpecObj->dictLookup("DOS", &obj1)->isString()) {
+#else
if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
+#endif
obj1.free();
fileSpecObj->dictLookup("F", &obj1);
}
- if (obj1.isString())
+ if (obj1.isString()) {
name = obj1.getString()->copy();
- else
+ } else {
error(-1, "Illegal file spec in link");
+ }
obj1.free();
// error
error(-1, "Illegal file spec in link");
}
+ // system-dependent path manipulation
+ if (name) {
+#ifdef WIN32
+ int i, j;
+
+ // "//...." --> "\...."
+ // "/x/...." --> "x:\...."
+ // "/server/share/...." --> "\\server\share\...."
+ // convert escaped slashes to slashes and unescaped slashes to backslashes
+ i = 0;
+ if (name->getChar(0) == '/') {
+ if (name->getLength() >= 2 && name->getChar(1) == '/') {
+ name->del(0);
+ i = 0;
+ } else if (name->getLength() >= 2 &&
+ ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') ||
+ (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) &&
+ (name->getLength() == 2 || name->getChar(2) == '/')) {
+ name->setChar(0, name->getChar(1));
+ name->setChar(1, ':');
+ i = 2;
+ } else {
+ for (j = 2; j < name->getLength(); ++j) {
+ if (name->getChar(j-1) != '\\' &&
+ name->getChar(j) == '/') {
+ break;
+ }
+ }
+ if (j < name->getLength()) {
+ name->setChar(0, '\\');
+ name->insert(0, '\\');
+ i = 2;
+ }
+ }
+ }
+ for (; i < name->getLength(); ++i) {
+ if (name->getChar(i) == '/') {
+ name->setChar(i, '\\');
+ } else if (name->getChar(i) == '\\' &&
+ i+1 < name->getLength() &&
+ name->getChar(i+1) == '/') {
+ name->del(i);
+ }
+ }
+#else
+ // no manipulation needed for Unix
+#endif
+ }
+
return name;
}
uri = NULL;
if (uriObj->isString()) {
uri2 = uriObj->getString()->copy();
- if (baseURI) {
+ if (baseURI && baseURI->getLength() > 0) {
n = strcspn(uri2->getCString(), "/:");
if (n == uri2->getLength() || uri2->getChar(n) == '/') {
uri = baseURI->copy();
obj2.free();
if (obj1.dictLookup("D", &obj2)->isArray()) {
borderDashLength = obj2.arrayGetLength();
- borderDash = (double *)gmalloc(borderDashLength * sizeof(double));
+ borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
for (i = 0; i < borderDashLength; ++i) {
if (obj2.arrayGet(i, &obj3)->isNum()) {
borderDash[i] = obj3.getNum();
if (obj1.arrayGet(3, &obj2)->isArray()) {
borderType = linkBorderDashed;
borderDashLength = obj2.arrayGetLength();
- borderDash = (double *)gmalloc(borderDashLength * sizeof(double));
+ borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
for (i = 0; i < borderDashLength; ++i) {
if (obj2.arrayGet(i, &obj3)->isNum()) {
borderDash[i] = obj3.getNum();
}
obj3.free();
}
+ } else {
+ // Adobe draws no border at all if the last element is of
+ // the wrong type.
+ borderWidth = 0;
}
obj2.free();
}
if (link->isOk()) {
if (numLinks >= size) {
size += 16;
- links = (Link **)grealloc(links, size * sizeof(Link *));
+ links = (Link **)greallocn(links, size, sizeof(Link *));
}
links[numLinks++] = link;
} else {
size = 31;
len = 0;
- tab = (NameToCharCodeEntry *)gmalloc(size * sizeof(NameToCharCodeEntry));
+ tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry));
for (i = 0; i < size; ++i) {
tab[i].name = NULL;
}
oldSize = size;
oldTab = tab;
size = 2*size + 1;
- tab = (NameToCharCodeEntry *)gmalloc(size * sizeof(NameToCharCodeEntry));
+ tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry));
for (h = 0; h < size; ++h) {
tab[h].name = NULL;
}
//
// NameToUnicodeTable.h
//
-// Copyright 2001-2003 Glyph & Cog, LLC
+// Copyright 2001-2004 Glyph & Cog, LLC
//
//========================================================================
{0x0041, "A"},
{0x00c6, "AE"},
{0x01fc, "AEacute"},
- {0x00c6, "AEsmall"},
+ {0xf7e6, "AEsmall"},
{0x00c1, "Aacute"},
- {0x00c1, "Aacutesmall"},
+ {0xf7e1, "Aacutesmall"},
{0x0102, "Abreve"},
{0x00c2, "Acircumflex"},
- {0x00c2, "Acircumflexsmall"},
+ {0xf7e2, "Acircumflexsmall"},
{0xf6c9, "Acute"},
- {0xf6c9, "Acutesmall"},
+ {0xf7b4, "Acutesmall"},
{0x00c4, "Adieresis"},
- {0x00c4, "Adieresissmall"},
+ {0xf7e4, "Adieresissmall"},
{0x00c0, "Agrave"},
- {0x00c0, "Agravesmall"},
+ {0xf7e0, "Agravesmall"},
{0x0391, "Alpha"},
{0x0386, "Alphatonos"},
{0x0100, "Amacron"},
{0x0104, "Aogonek"},
{0x00c5, "Aring"},
{0x01fa, "Aringacute"},
- {0x00c5, "Aringsmall"},
- {0x0041, "Asmall"},
+ {0xf7e5, "Aringsmall"},
+ {0xf761, "Asmall"},
{0x00c3, "Atilde"},
- {0x00c3, "Atildesmall"},
+ {0xf7e3, "Atildesmall"},
{0x0042, "B"},
{0x0392, "Beta"},
{0xf6f4, "Brevesmall"},
- {0x0042, "Bsmall"},
+ {0xf762, "Bsmall"},
{0x0043, "C"},
{0x0106, "Cacute"},
{0xf6ca, "Caron"},
- {0xf6ca, "Caronsmall"},
+ {0xf6f5, "Caronsmall"},
{0x010c, "Ccaron"},
{0x00c7, "Ccedilla"},
- {0x00c7, "Ccedillasmall"},
+ {0xf7e7, "Ccedillasmall"},
{0x0108, "Ccircumflex"},
{0x010a, "Cdotaccent"},
{0xf7b8, "Cedillasmall"},
{0x03a7, "Chi"},
{0xf6f6, "Circumflexsmall"},
- {0x0043, "Csmall"},
+ {0xf763, "Csmall"},
{0x0044, "D"},
{0x010e, "Dcaron"},
{0x0110, "Dcroat"},
{0xf6cb, "Dieresis"},
{0xf6cc, "DieresisAcute"},
{0xf6cd, "DieresisGrave"},
- {0xf6cb, "Dieresissmall"},
+ {0xf7a8, "Dieresissmall"},
{0xf6f7, "Dotaccentsmall"},
- {0x0044, "Dsmall"},
+ {0xf764, "Dsmall"},
{0x0045, "E"},
{0x00c9, "Eacute"},
- {0x00c9, "Eacutesmall"},
+ {0xf7e9, "Eacutesmall"},
{0x0114, "Ebreve"},
{0x011a, "Ecaron"},
{0x00ca, "Ecircumflex"},
- {0x00ca, "Ecircumflexsmall"},
+ {0xf7ea, "Ecircumflexsmall"},
{0x00cb, "Edieresis"},
- {0x00cb, "Edieresissmall"},
+ {0xf7eb, "Edieresissmall"},
{0x0116, "Edotaccent"},
{0x00c8, "Egrave"},
- {0x00c8, "Egravesmall"},
+ {0xf7e8, "Egravesmall"},
{0x0112, "Emacron"},
{0x014a, "Eng"},
{0x0118, "Eogonek"},
{0x0395, "Epsilon"},
{0x0388, "Epsilontonos"},
- {0x0045, "Esmall"},
+ {0xf765, "Esmall"},
{0x0397, "Eta"},
{0x0389, "Etatonos"},
{0x00d0, "Eth"},
- {0x00d0, "Ethsmall"},
+ {0xf7f0, "Ethsmall"},
{0x20ac, "Euro"},
{0x0046, "F"},
- {0x0046, "Fsmall"},
+ {0xf766, "Fsmall"},
{0x0047, "G"},
{0x0393, "Gamma"},
{0x011e, "Gbreve"},
{0x0122, "Gcommaaccent"},
{0x0120, "Gdotaccent"},
{0xf6ce, "Grave"},
- {0xf6ce, "Gravesmall"},
- {0x0047, "Gsmall"},
+ {0xf760, "Gravesmall"},
+ {0xf767, "Gsmall"},
{0x0048, "H"},
{0x25cf, "H18533"},
{0x25aa, "H18543"},
{0x25a1, "H22073"},
{0x0126, "Hbar"},
{0x0124, "Hcircumflex"},
- {0x0048, "Hsmall"},
+ {0xf768, "Hsmall"},
{0xf6cf, "Hungarumlaut"},
- {0xf6cf, "Hungarumlautsmall"},
+ {0xf6f8, "Hungarumlautsmall"},
{0x0049, "I"},
{0x0132, "IJ"},
{0x00cd, "Iacute"},
- {0x00cd, "Iacutesmall"},
+ {0xf7ed, "Iacutesmall"},
{0x012c, "Ibreve"},
{0x00ce, "Icircumflex"},
- {0x00ce, "Icircumflexsmall"},
+ {0xf7ee, "Icircumflexsmall"},
{0x00cf, "Idieresis"},
- {0x00cf, "Idieresissmall"},
+ {0xf7ef, "Idieresissmall"},
{0x0130, "Idotaccent"},
{0x2111, "Ifraktur"},
{0x00cc, "Igrave"},
- {0x00cc, "Igravesmall"},
+ {0xf7ec, "Igravesmall"},
{0x012a, "Imacron"},
{0x012e, "Iogonek"},
{0x0399, "Iota"},
{0x03aa, "Iotadieresis"},
{0x038a, "Iotatonos"},
- {0x0049, "Ismall"},
+ {0xf769, "Ismall"},
{0x0128, "Itilde"},
{0x004a, "J"},
{0x0134, "Jcircumflex"},
- {0x004a, "Jsmall"},
+ {0xf76a, "Jsmall"},
{0x004b, "K"},
{0x039a, "Kappa"},
{0x0136, "Kcommaaccent"},
- {0x004b, "Ksmall"},
+ {0xf76b, "Ksmall"},
{0x004c, "L"},
{0xf6bf, "LL"},
{0x0139, "Lacute"},
{0x013b, "Lcommaaccent"},
{0x013f, "Ldot"},
{0x0141, "Lslash"},
- {0x0141, "Lslashsmall"},
- {0x004c, "Lsmall"},
+ {0xf6f9, "Lslashsmall"},
+ {0xf76c, "Lsmall"},
{0x004d, "M"},
{0xf6d0, "Macron"},
- {0xf6d0, "Macronsmall"},
- {0x004d, "Msmall"},
+ {0xf7af, "Macronsmall"},
+ {0xf76d, "Msmall"},
{0x039c, "Mu"},
{0x004e, "N"},
{0x0143, "Nacute"},
{0x0147, "Ncaron"},
{0x0145, "Ncommaaccent"},
- {0x004e, "Nsmall"},
+ {0xf76e, "Nsmall"},
{0x00d1, "Ntilde"},
- {0x00d1, "Ntildesmall"},
+ {0xf7f1, "Ntildesmall"},
{0x039d, "Nu"},
{0x004f, "O"},
{0x0152, "OE"},
- {0x0152, "OEsmall"},
+ {0xf6fa, "OEsmall"},
{0x00d3, "Oacute"},
- {0x00d3, "Oacutesmall"},
+ {0xf7f3, "Oacutesmall"},
{0x014e, "Obreve"},
{0x00d4, "Ocircumflex"},
- {0x00d4, "Ocircumflexsmall"},
+ {0xf7f4, "Ocircumflexsmall"},
{0x00d6, "Odieresis"},
- {0x00d6, "Odieresissmall"},
+ {0xf7f6, "Odieresissmall"},
{0xf6fb, "Ogoneksmall"},
{0x00d2, "Ograve"},
- {0x00d2, "Ogravesmall"},
+ {0xf7f2, "Ogravesmall"},
{0x01a0, "Ohorn"},
{0x0150, "Ohungarumlaut"},
{0x014c, "Omacron"},
{0x038c, "Omicrontonos"},
{0x00d8, "Oslash"},
{0x01fe, "Oslashacute"},
- {0x00d8, "Oslashsmall"},
- {0x004f, "Osmall"},
+ {0xf7f8, "Oslashsmall"},
+ {0xf76f, "Osmall"},
{0x00d5, "Otilde"},
- {0x00d5, "Otildesmall"},
+ {0xf7f5, "Otildesmall"},
{0x0050, "P"},
{0x03a6, "Phi"},
{0x03a0, "Pi"},
{0x03a8, "Psi"},
- {0x0050, "Psmall"},
+ {0xf770, "Psmall"},
{0x0051, "Q"},
- {0x0051, "Qsmall"},
+ {0xf771, "Qsmall"},
{0x0052, "R"},
{0x0154, "Racute"},
{0x0158, "Rcaron"},
{0x211c, "Rfraktur"},
{0x03a1, "Rho"},
{0xf6fc, "Ringsmall"},
- {0x0052, "Rsmall"},
+ {0xf772, "Rsmall"},
{0x0053, "S"},
{0x250c, "SF010000"},
{0x2514, "SF020000"},
{0x256a, "SF540000"},
{0x015a, "Sacute"},
{0x0160, "Scaron"},
- {0x0160, "Scaronsmall"},
+ {0xf6fd, "Scaronsmall"},
{0x015e, "Scedilla"},
{0x015c, "Scircumflex"},
{0x0218, "Scommaaccent"},
{0x03a3, "Sigma"},
- {0x0053, "Ssmall"},
+ {0xf773, "Ssmall"},
{0x0054, "T"},
{0x03a4, "Tau"},
{0x0166, "Tbar"},
{0x0162, "Tcommaaccent"},
{0x0398, "Theta"},
{0x00de, "Thorn"},
- {0x00de, "Thornsmall"},
+ {0xf7fe, "Thornsmall"},
{0xf6fe, "Tildesmall"},
- {0x0054, "Tsmall"},
+ {0xf774, "Tsmall"},
{0x0055, "U"},
{0x00da, "Uacute"},
- {0x00da, "Uacutesmall"},
+ {0xf7fa, "Uacutesmall"},
{0x016c, "Ubreve"},
{0x00db, "Ucircumflex"},
- {0x00db, "Ucircumflexsmall"},
+ {0xf7fb, "Ucircumflexsmall"},
{0x00dc, "Udieresis"},
- {0x00dc, "Udieresissmall"},
+ {0xf7fc, "Udieresissmall"},
{0x00d9, "Ugrave"},
- {0x00d9, "Ugravesmall"},
+ {0xf7f9, "Ugravesmall"},
{0x01af, "Uhorn"},
{0x0170, "Uhungarumlaut"},
{0x016a, "Umacron"},
{0x03ab, "Upsilondieresis"},
{0x038e, "Upsilontonos"},
{0x016e, "Uring"},
- {0x0055, "Usmall"},
+ {0xf775, "Usmall"},
{0x0168, "Utilde"},
{0x0056, "V"},
- {0x0056, "Vsmall"},
+ {0xf776, "Vsmall"},
{0x0057, "W"},
{0x1e82, "Wacute"},
{0x0174, "Wcircumflex"},
{0x1e84, "Wdieresis"},
{0x1e80, "Wgrave"},
- {0x0057, "Wsmall"},
+ {0xf777, "Wsmall"},
{0x0058, "X"},
{0x039e, "Xi"},
- {0x0058, "Xsmall"},
+ {0xf778, "Xsmall"},
{0x0059, "Y"},
{0x00dd, "Yacute"},
- {0x00dd, "Yacutesmall"},
+ {0xf7fd, "Yacutesmall"},
{0x0176, "Ycircumflex"},
{0x0178, "Ydieresis"},
- {0x0178, "Ydieresissmall"},
+ {0xf7ff, "Ydieresissmall"},
{0x1ef2, "Ygrave"},
- {0x0059, "Ysmall"},
+ {0xf779, "Ysmall"},
{0x005a, "Z"},
{0x0179, "Zacute"},
{0x017d, "Zcaron"},
- {0x017d, "Zcaronsmall"},
+ {0xf6ff, "Zcaronsmall"},
{0x017b, "Zdotaccent"},
{0x0396, "Zeta"},
- {0x005a, "Zsmall"},
+ {0xf77a, "Zsmall"},
{0x0022, "\""},
{0x005c, "\\"},
{0x005d, "]"},
{0x03ac, "alphatonos"},
{0x0101, "amacron"},
{0x0026, "ampersand"},
- {0x0026, "ampersandsmall"},
+ {0xf726, "ampersandsmall"},
{0x2220, "angle"},
{0x2329, "angleleft"},
{0x232a, "angleright"},
{0x00b8, "cedilla"},
{0x00a2, "cent"},
{0xf6df, "centinferior"},
- {0x00a2, "centoldstyle"},
+ {0xf7a2, "centoldstyle"},
{0xf6e0, "centsuperior"},
{0x03c7, "chi"},
{0x25cb, "circle"},
{0x2584, "dnblock"},
{0x0024, "dollar"},
{0xf6e3, "dollarinferior"},
- {0x0024, "dollaroldstyle"},
+ {0xf724, "dollaroldstyle"},
{0xf6e4, "dollarsuperior"},
{0x20ab, "dong"},
{0x02d9, "dotaccent"},
{0x00e8, "egrave"},
{0x0038, "eight"},
{0x2088, "eightinferior"},
- {0x0038, "eightoldstyle"},
+ {0xf738, "eightoldstyle"},
{0x2078, "eightsuperior"},
{0x2208, "element"},
{0x2026, "ellipsis"},
{0x0021, "exclam"},
{0x203c, "exclamdbl"},
{0x00a1, "exclamdown"},
- {0x00a1, "exclamdownsmall"},
+ {0xf7a1, "exclamdownsmall"},
{0x0021, "exclamleft"},
- {0x0021, "exclamsmall"},
+ {0xf721, "exclamsmall"},
{0x2203, "existential"},
{0x0066, "f"},
{0x2640, "female"},
{0x0035, "five"},
{0x215d, "fiveeighths"},
{0x2085, "fiveinferior"},
- {0x0035, "fiveoldstyle"},
+ {0xf735, "fiveoldstyle"},
{0x2075, "fivesuperior"},
{0xfb02, "fl"},
{0x0192, "florin"},
{0x0034, "four"},
{0x2084, "fourinferior"},
- {0x0034, "fouroldstyle"},
+ {0xf734, "fouroldstyle"},
{0x2074, "foursuperior"},
{0x2044, "fraction"},
{0x20a3, "franc"},
{0x0146, "ncommaaccent"},
{0x0039, "nine"},
{0x2089, "nineinferior"},
- {0x0039, "nineoldstyle"},
+ {0xf739, "nineoldstyle"},
{0x2079, "ninesuperior"},
{0x00a0, "nonbreakingspace"},
{0x2209, "notelement"},
{0xf6dc, "onefitted"},
{0x00bd, "onehalf"},
{0x2081, "oneinferior"},
- {0x0031, "oneoldstyle"},
+ {0xf731, "oneoldstyle"},
{0x00bc, "onequarter"},
{0x00b9, "onesuperior"},
{0x2153, "onethird"},
{0x0071, "q"},
{0x003f, "question"},
{0x00bf, "questiondown"},
- {0x00bf, "questiondownsmall"},
- {0x003f, "questionsmall"},
+ {0xf7bf, "questiondownsmall"},
+ {0xf73f, "questionsmall"},
{0x0022, "quotedbl"},
{0x201e, "quotedblbase"},
{0x201c, "quotedblleft"},
{0x0037, "seven"},
{0x215e, "seveneighths"},
{0x2087, "seveninferior"},
- {0x0037, "sevenoldstyle"},
+ {0xf737, "sevenoldstyle"},
{0x2077, "sevensuperior"},
{0x2592, "shade"},
{0x03c3, "sigma"},
{0x223c, "similar"},
{0x0036, "six"},
{0x2086, "sixinferior"},
- {0x0036, "sixoldstyle"},
+ {0xf736, "sixoldstyle"},
{0x2076, "sixsuperior"},
{0x002f, "slash"},
{0x263a, "smileface"},
{0x0033, "three"},
{0x215c, "threeeighths"},
{0x2083, "threeinferior"},
- {0x0033, "threeoldstyle"},
+ {0xf733, "threeoldstyle"},
{0x00be, "threequarters"},
{0xf6de, "threequartersemdash"},
{0x00b3, "threesuperior"},
{0x0032, "two"},
{0x2025, "twodotenleader"},
{0x2082, "twoinferior"},
- {0x0032, "twooldstyle"},
+ {0xf732, "twooldstyle"},
{0x00b2, "twosuperior"},
{0x2154, "twothirds"},
{0x0075, "u"},
{0x017c, "zdotaccent"},
{0x0030, "zero"},
{0x2080, "zeroinferior"},
- {0x0030, "zerooldstyle"},
+ {0xf730, "zerooldstyle"},
{0x2070, "zerosuperior"},
{0x03b6, "zeta"},
{0x007b, "{"},
break;
case objString:
fprintf(f, "(");
- fwrite(string->getCString(), 1, string->getLength(), stdout);
+ fwrite(string->getCString(), 1, string->getLength(), f);
fprintf(f, ")");
break;
case objName:
if ((s->getChar(0) & 0xff) == 0xfe &&
(s->getChar(1) & 0xff) == 0xff) {
titleLen = (s->getLength() - 2) / 2;
- title = (Unicode *)gmalloc(titleLen * sizeof(Unicode));
+ title = (Unicode *)gmallocn(titleLen, sizeof(Unicode));
for (i = 0; i < titleLen; ++i) {
title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) |
(s->getChar(3 + 2*i) & 0xff);
}
} else {
titleLen = s->getLength();
- title = (Unicode *)gmalloc(titleLen * sizeof(Unicode));
+ title = (Unicode *)gmallocn(titleLen, sizeof(Unicode));
for (i = 0; i < titleLen; ++i) {
title[i] = pdfDocEncoding[s->getChar(i) & 0xff];
}
action = LinkAction::parseDest(&obj1);
} else {
obj1.free();
- if (dict->lookup("A", &obj1)) {
+ if (!dict->lookup("A", &obj1)->isNull()) {
action = LinkAction::parseAction(&obj1);
}
}
updateLineCap(state);
updateMiterLimit(state);
updateLineWidth(state);
+ updateFillColorSpace(state);
updateFillColor(state);
+ updateStrokeColorSpace(state);
updateStrokeColor(state);
+ updateBlendMode(state);
+ updateFillOpacity(state);
+ updateStrokeOpacity(state);
+ updateFillOverprint(state);
+ updateStrokeOverprint(state);
updateFont(state);
}
}
}
+void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GBool maskInvert) {
+ drawImage(state, ref, str, width, height, colorMap, NULL, gFalse);
+}
+
+void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap) {
+ drawImage(state, ref, str, width, height, colorMap, NULL, gFalse);
+}
+
#if OPI_SUPPORT
void OutputDev::opiBegin(GfxState *state, Dict *opiDict) {
}
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
+#ifdef WIN32
+# include <windows.h>
+#endif
#include "GString.h"
#include "config.h"
#include "GlobalParams.h"
#include "ErrorCodes.h"
#include "Lexer.h"
#include "Parser.h"
+#include "SecurityHandler.h"
#ifndef DISABLE_OUTLINE
#include "Outline.h"
#endif
//------------------------------------------------------------------------
PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword,
- GString *userPassword) {
+ GString *userPassword, void *guiDataA) {
Object obj;
GString *fileName1, *fileName2;
ok = gFalse;
errCode = errNone;
+ guiData = guiDataA;
+
file = NULL;
str = NULL;
xref = NULL;
ok = setup(ownerPassword, userPassword);
}
+#ifdef WIN32
+PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword,
+ GString *userPassword, void *guiDataA) {
+ OSVERSIONINFO version;
+ wchar_t fileName2[_MAX_PATH + 1];
+ Object obj;
+ int i;
+
+ ok = gFalse;
+ errCode = errNone;
+
+ guiData = guiDataA;
+
+ file = NULL;
+ str = NULL;
+ xref = NULL;
+ catalog = NULL;
+ links = NULL;
+#ifndef DISABLE_OUTLINE
+ outline = NULL;
+#endif
+
+ //~ file name should be stored in Unicode (?)
+ fileName = new GString();
+ for (i = 0; i < fileNameLen; ++i) {
+ fileName->append((char)fileNameA[i]);
+ }
+
+ // zero-terminate the file name string
+ for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) {
+ fileName2[i] = fileNameA[i];
+ }
+ fileName2[i] = 0;
+
+ // try to open file
+ // NB: _wfopen is only available in NT
+ version.dwOSVersionInfoSize = sizeof(version);
+ GetVersionEx(&version);
+ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+ file = _wfopen(fileName2, L"rb");
+ } else {
+ file = fopen(fileName->getCString(), "rb");
+ }
+ if (!file) {
+ error(-1, "Couldn't open file '%s'", fileName->getCString());
+ errCode = errOpenFile;
+ return;
+ }
+
+ // create stream
+ obj.initNull();
+ str = new FileStream(file, 0, gFalse, 0, &obj);
+
+ ok = setup(ownerPassword, userPassword);
+}
+#endif
+
PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword,
- GString *userPassword) {
+ GString *userPassword, void *guiDataA) {
ok = gFalse;
errCode = errNone;
+ guiData = guiDataA;
fileName = NULL;
file = NULL;
str = strA;
checkHeader();
// read xref table
- xref = new XRef(str, ownerPassword, userPassword);
+ xref = new XRef(str);
if (!xref->isOk()) {
error(-1, "Couldn't read xref table");
errCode = xref->getErrorCode();
return gFalse;
}
+ // check for encryption
+ if (!checkEncryption(ownerPassword, userPassword)) {
+ errCode = errEncrypted;
+ return gFalse;
+ }
+
// read catalog
catalog = new Catalog(xref);
if (!catalog->isOk()) {
return;
}
str->moveStart(i);
- p = strtok(&hdrBuf[i+5], " \t\n\r");
+ if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) {
+ error(-1, "May not be a PDF file (continuing anyway)");
+ return;
+ }
pdfVersion = atof(p);
if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') ||
pdfVersion > supportedPDFVersionNum + 0.0001) {
}
}
+GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) {
+ Object encrypt;
+ GBool encrypted;
+ SecurityHandler *secHdlr;
+ GBool ret;
+
+ xref->getTrailerDict()->dictLookup("Encrypt", &encrypt);
+ if ((encrypted = encrypt.isDict())) {
+ if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
+ if (secHdlr->checkEncryption(ownerPassword, userPassword)) {
+ // authorization succeeded
+ xref->setEncryption(secHdlr->getPermissionFlags(),
+ secHdlr->getOwnerPasswordOk(),
+ secHdlr->getFileKey(),
+ secHdlr->getFileKeyLength(),
+ secHdlr->getEncVersion());
+ ret = gTrue;
+ } else {
+ // authorization failed
+ ret = gFalse;
+ }
+ delete secHdlr;
+ } else {
+ // couldn't find the matching security handler
+ ret = gFalse;
+ }
+ } else {
+ // document is not encrypted
+ ret = gTrue;
+ }
+ encrypt.free();
+ return ret;
+}
+
void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI,
- int rotate, GBool crop, GBool doLinks,
+ int rotate, GBool useMediaBox, GBool crop,
+ GBool doLinks,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData) {
Page *p;
delete links;
}
getLinks(p);
- p->display(out, hDPI, vDPI, rotate, crop, links, catalog,
+ p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog,
abortCheckCbk, abortCheckCbkData);
} else {
- p->display(out, hDPI, vDPI, rotate, crop, NULL, catalog,
+ p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog,
abortCheckCbk, abortCheckCbkData);
}
}
void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
double hDPI, double vDPI, int rotate,
- GBool crop, GBool doLinks,
+ GBool useMediaBox, GBool crop, GBool doLinks,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData) {
int page;
for (page = firstPage; page <= lastPage; ++page) {
- displayPage(out, page, hDPI, vDPI, rotate, crop, doLinks,
+ displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, doLinks,
abortCheckCbk, abortCheckCbkData);
}
}
void PDFDoc::displayPageSlice(OutputDev *out, int page,
- double hDPI, double vDPI,
- int rotate, GBool crop,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool doLinks,
int sliceX, int sliceY, int sliceW, int sliceH,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData) {
Page *p;
p = catalog->getPage(page);
- p->displaySlice(out, hDPI, vDPI, rotate, crop,
- sliceX, sliceY, sliceW, sliceH,
- NULL, catalog, abortCheckCbk, abortCheckCbkData);
+ if (doLinks) {
+ if (links) {
+ delete links;
+ }
+ getLinks(p);
+ p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
+ sliceX, sliceY, sliceW, sliceH,
+ links, catalog, abortCheckCbk, abortCheckCbkData);
+ } else {
+ p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
+ sliceX, sliceY, sliceW, sliceH,
+ NULL, catalog, abortCheckCbk, abortCheckCbkData);
+ }
+}
+
+Links *PDFDoc::takeLinks() {
+ Links *ret;
+
+ ret = links;
+ links = NULL;
+ return ret;
}
GBool PDFDoc::isLinearized() {
#include <stdio.h>
#include "XRef.h"
-#include "Link.h"
#include "Catalog.h"
#include "Page.h"
public:
PDFDoc(GString *fileNameA, GString *ownerPassword = NULL,
- GString *userPassword = NULL);
+ GString *userPassword = NULL, void *guiDataA = NULL);
+#ifdef WIN32
+ PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword = NULL,
+ GString *userPassword = NULL, void *guiDataA = NULL);
+#endif
PDFDoc(BaseStream *strA, GString *ownerPassword = NULL,
- GString *userPassword = NULL);
+ GString *userPassword = NULL, void *guiDataA = NULL);
~PDFDoc();
// Was PDF document successfully opened?
BaseStream *getBaseStream() { return str; }
// Get page parameters.
- double getPageWidth(int page)
- { return catalog->getPage(page)->getWidth(); }
- double getPageHeight(int page)
- { return catalog->getPage(page)->getHeight(); }
+ double getPageMediaWidth(int page)
+ { return catalog->getPage(page)->getMediaWidth(); }
+ double getPageMediaHeight(int page)
+ { return catalog->getPage(page)->getMediaHeight(); }
+ double getPageCropWidth(int page)
+ { return catalog->getPage(page)->getCropWidth(); }
+ double getPageCropHeight(int page)
+ { return catalog->getPage(page)->getCropHeight(); }
int getPageRotate(int page)
{ return catalog->getPage(page)->getRotate(); }
// Display a page.
void displayPage(OutputDev *out, int page, double hDPI, double vDPI,
- int rotate, GBool crop, GBool doLinks,
+ int rotate, GBool useMediaBox, GBool crop,
+ GBool doLinks,
GBool (*abortCheckCbk)(void *data) = NULL,
void *abortCheckCbkData = NULL);
// Display a range of pages.
void displayPages(OutputDev *out, int firstPage, int lastPage,
double hDPI, double vDPI, int rotate,
- GBool crop, GBool doLinks,
+ GBool useMediaBox, GBool crop, GBool doLinks,
GBool (*abortCheckCbk)(void *data) = NULL,
void *abortCheckCbkData = NULL);
// Display part of a page.
void displayPageSlice(OutputDev *out, int page,
- double hDPI, double vDPI,
- int rotate, GBool crop,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool doLinks,
int sliceX, int sliceY, int sliceW, int sliceH,
GBool (*abortCheckCbk)(void *data) = NULL,
void *abortCheckCbkData = NULL);
// not found.
int findPage(int num, int gen) { return catalog->findPage(num, gen); }
- // If point <x>,<y> is in a link, return the associated action;
- // else return NULL.
- LinkAction *findLink(double x, double y)
- { return links ? links->find(x, y) : (LinkAction *)NULL; }
-
- // Return true if <x>,<y> is in a link.
- GBool onLink(double x, double y) { return links->onLink(x, y); }
+ // Returns the links for the current page, transferring ownership to
+ // the caller.
+ Links *takeLinks();
// Find a named destination. Returns the link destination, or
// NULL if <name> is not a destination.
// Save this file with another name.
GBool saveAs(GString *name);
+ // Return a pointer to the GUI (XPDFCore or WinPDFCore object).
+ void *getGUIData() { return guiData; }
+
private:
GBool setup(GString *ownerPassword, GString *userPassword);
void checkHeader();
+ GBool checkEncryption(GString *ownerPassword, GString *userPassword);
void getLinks(Page *page);
GString *fileName;
FILE *file;
BaseStream *str;
+ void *guiData;
double pdfVersion;
XRef *xref;
Catalog *catalog;
~PageAttrs();
// Accessors.
- PDFRectangle *getBox() { return limitToCropBox ? &cropBox : &mediaBox; }
PDFRectangle *getMediaBox() { return &mediaBox; }
PDFRectangle *getCropBox() { return &cropBox; }
GBool isCropped() { return haveCropBox; }
PDFRectangle mediaBox;
PDFRectangle cropBox;
GBool haveCropBox;
- GBool limitToCropBox;
PDFRectangle bleedBox;
PDFRectangle trimBox;
PDFRectangle artBox;
GBool isOk() { return ok; }
// Get page parameters.
- PDFRectangle *getBox() { return attrs->getBox(); }
PDFRectangle *getMediaBox() { return attrs->getMediaBox(); }
PDFRectangle *getCropBox() { return attrs->getCropBox(); }
GBool isCropped() { return attrs->isCropped(); }
- double getWidth() { return attrs->getBox()->x2 - attrs->getBox()->x1; }
- double getHeight() { return attrs->getBox()->y2 - attrs->getBox()->y1; }
+ double getMediaWidth()
+ { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; }
+ double getMediaHeight()
+ { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; }
+ double getCropWidth()
+ { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; }
+ double getCropHeight()
+ { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; }
PDFRectangle *getBleedBox() { return attrs->getBleedBox(); }
PDFRectangle *getTrimBox() { return attrs->getTrimBox(); }
PDFRectangle *getArtBox() { return attrs->getArtBox(); }
// Display a page.
void display(OutputDev *out, double hDPI, double vDPI,
- int rotate, GBool crop,
+ int rotate, GBool useMediaBox, GBool crop,
Links *links, Catalog *catalog,
GBool (*abortCheckCbk)(void *data) = NULL,
void *abortCheckCbkData = NULL);
// Display part of a page.
void displaySlice(OutputDev *out, double hDPI, double vDPI,
- int rotate, GBool crop,
+ int rotate, GBool useMediaBox, GBool crop,
int sliceX, int sliceY, int sliceW, int sliceH,
Links *links, Catalog *catalog,
GBool (*abortCheckCbk)(void *data) = NULL,
void *abortCheckCbkData = NULL);
+ // Get the page's default CTM.
+ void getDefaultCTM(double *ctm, double hDPI, double vDPI,
+ int rotate, GBool upsideDown);
+
private:
XRef *xref; // the xref table for this PDF file
#include "Parser.h"
#include "XRef.h"
#include "Error.h"
-#ifndef NO_DECRYPTION
#include "Decrypt.h"
-#endif
Parser::Parser(XRef *xrefA, Lexer *lexerA) {
xref = xrefA;
delete lexer;
}
-#ifndef NO_DECRYPTION
Object *Parser::getObj(Object *obj,
Guchar *fileKey, int keyLength,
int objNum, int objGen) {
-#else
-Object *Parser::getObj(Object *obj) {
-#endif
char *key;
Stream *str;
Object obj2;
int num;
-#ifndef NO_DECRYPTION
Decrypt *decrypt;
GString *s;
char *p;
int i;
-#endif
// refill buffer after inline image data
if (inlineImg == 2) {
shift();
obj->initArray(xref);
while (!buf1.isCmd("]") && !buf1.isEOF())
-#ifndef NO_DECRYPTION
obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen));
-#else
- obj->arrayAdd(getObj(&obj2));
-#endif
if (buf1.isEOF())
error(getPos(), "End of file inside array");
shift();
gfree(key);
break;
}
-#ifndef NO_DECRYPTION
obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen));
-#else
- obj->dictAdd(key, getObj(&obj2));
-#endif
}
}
if (buf1.isEOF())
if (buf2.isCmd("stream")) {
if ((str = makeStream(obj))) {
obj->initStream(str);
-#ifndef NO_DECRYPTION
if (fileKey) {
str->getBaseStream()->doDecryption(fileKey, keyLength,
objNum, objGen);
}
-#endif
} else {
obj->free();
obj->initError();
obj->initInt(num);
}
-#ifndef NO_DECRYPTION
// string
} else if (buf1.isString() && fileKey) {
buf1.copy(obj);
}
delete decrypt;
shift();
-#endif
// simple object
} else {
Stream *Parser::makeStream(Object *dict) {
Object obj;
+ BaseStream *baseStr;
Stream *str;
Guint pos, endPos, length;
if (!lexer->getStream()) {
return NULL;
}
-
- // make base stream
- str = lexer->getStream()->getBaseStream()->makeSubStream(pos, gTrue,
- length, dict);
-
- // get filters
- str = str->addFilters(dict);
+ baseStr = lexer->getStream()->getBaseStream();
// skip over stream data
lexer->setPos(pos + length);
shift();
} else {
error(getPos(), "Missing 'endstream'");
- str->ignoreLength();
+ // kludge for broken PDF files: just add 5k to the length, and
+ // hope its enough
+ length += 5000;
}
+ // make base stream
+ str = baseStr->makeSubStream(pos, gTrue, length, dict);
+
+ // get filters
+ str = str->addFilters(dict);
+
return str;
}
~Parser();
// Get the next object from the input stream.
-#ifndef NO_DECRYPTION
Object *getObj(Object *obj,
Guchar *fileKey = NULL, int keyLength = 0,
int objNum = 0, int objGen = 0);
-#else
- Object *getObj(Object *obj);
-#endif
// Get stream.
Stream *getStream() { return lexer->getStream(); }
--- /dev/null
+//========================================================================
+//
+// SecurityHandler.cc
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "GString.h"
+#include "PDFDoc.h"
+#include "Decrypt.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#if HAVE_XPDFCORE
+# include "XPDFCore.h"
+#elif HAVE_WINPDFCORE
+# include "WinPDFCore.h"
+#endif
+#ifdef ENABLE_PLUGINS
+# include "XpdfPluginAPI.h"
+#endif
+#include "SecurityHandler.h"
+
+//------------------------------------------------------------------------
+// SecurityHandler
+//------------------------------------------------------------------------
+
+SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
+ Object filterObj;
+ SecurityHandler *secHdlr;
+ XpdfSecurityHandler *xsh;
+
+ encryptDictA->dictLookup("Filter", &filterObj);
+ if (filterObj.isName("Standard")) {
+ secHdlr = new StandardSecurityHandler(docA, encryptDictA);
+ } else if (filterObj.isName()) {
+#ifdef ENABLE_PLUGINS
+ if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) {
+ secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh);
+ } else {
+#endif
+ error(-1, "Couldn't find the '%s' security handler",
+ filterObj.getName());
+ secHdlr = NULL;
+#ifdef ENABLE_PLUGINS
+ }
+#endif
+ } else {
+ error(-1, "Missing or invalid 'Filter' entry in encryption dictionary");
+ secHdlr = NULL;
+ }
+ filterObj.free();
+ return secHdlr;
+}
+
+SecurityHandler::SecurityHandler(PDFDoc *docA) {
+ doc = docA;
+}
+
+SecurityHandler::~SecurityHandler() {
+}
+
+GBool SecurityHandler::checkEncryption(GString *ownerPassword,
+ GString *userPassword) {
+ void *authData;
+ GBool ok;
+ int i;
+
+ if (ownerPassword || userPassword) {
+ authData = makeAuthData(ownerPassword, userPassword);
+ } else {
+ authData = NULL;
+ }
+ ok = authorize(authData);
+ if (authData) {
+ freeAuthData(authData);
+ }
+ for (i = 0; !ok && i < 3; ++i) {
+ if (!(authData = getAuthData())) {
+ break;
+ }
+ ok = authorize(authData);
+ if (authData) {
+ freeAuthData(authData);
+ }
+ }
+ if (!ok) {
+ error(-1, "Incorrect password");
+ }
+ return ok;
+}
+
+//------------------------------------------------------------------------
+// StandardSecurityHandler
+//------------------------------------------------------------------------
+
+class StandardAuthData {
+public:
+
+ StandardAuthData(GString *ownerPasswordA, GString *userPasswordA) {
+ ownerPassword = ownerPasswordA;
+ userPassword = userPasswordA;
+ }
+
+ ~StandardAuthData() {
+ if (ownerPassword) {
+ delete ownerPassword;
+ }
+ if (userPassword) {
+ delete userPassword;
+ }
+ }
+
+ GString *ownerPassword;
+ GString *userPassword;
+};
+
+StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
+ Object *encryptDictA):
+ SecurityHandler(docA)
+{
+ Object versionObj, revisionObj, lengthObj;
+ Object ownerKeyObj, userKeyObj, permObj, fileIDObj;
+ Object fileIDObj1;
+ Object cryptFiltersObj, streamFilterObj, stringFilterObj;
+ Object cryptFilterObj, cfmObj, cfLengthObj;
+ Object encryptMetadataObj;
+
+ ok = gFalse;
+ fileID = NULL;
+ ownerKey = NULL;
+ userKey = NULL;
+
+ encryptDictA->dictLookup("V", &versionObj);
+ encryptDictA->dictLookup("R", &revisionObj);
+ encryptDictA->dictLookup("Length", &lengthObj);
+ encryptDictA->dictLookup("O", &ownerKeyObj);
+ encryptDictA->dictLookup("U", &userKeyObj);
+ encryptDictA->dictLookup("P", &permObj);
+ doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj);
+ if (versionObj.isInt() &&
+ revisionObj.isInt() &&
+ ownerKeyObj.isString() && ownerKeyObj.getString()->getLength() == 32 &&
+ userKeyObj.isString() && userKeyObj.getString()->getLength() == 32 &&
+ permObj.isInt()) {
+ encVersion = versionObj.getInt();
+ encRevision = revisionObj.getInt();
+ // revision 2 forces a 40-bit key - some buggy PDF generators
+ // set the Length value incorrectly
+ if (encRevision == 2 || !lengthObj.isInt()) {
+ fileKeyLength = 5;
+ } else {
+ fileKeyLength = lengthObj.getInt() / 8;
+ }
+ encryptMetadata = gTrue;
+ //~ this currently only handles a subset of crypt filter functionality
+ if (encVersion == 4 && encRevision == 4) {
+ encryptDictA->dictLookup("CF", &cryptFiltersObj);
+ encryptDictA->dictLookup("StmF", &streamFilterObj);
+ encryptDictA->dictLookup("StrF", &stringFilterObj);
+ if (cryptFiltersObj.isDict() &&
+ streamFilterObj.isName() &&
+ stringFilterObj.isName() &&
+ !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) {
+ if (cryptFiltersObj.dictLookup(streamFilterObj.getName(),
+ &cryptFilterObj)->isDict()) {
+ if (cryptFilterObj.dictLookup("CFM", &cfmObj)->isName("V2")) {
+ encVersion = 2;
+ encRevision = 3;
+ if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) {
+ //~ according to the spec, this should be cfLengthObj / 8
+ fileKeyLength = cfLengthObj.getInt();
+ }
+ cfLengthObj.free();
+ }
+ cfmObj.free();
+ }
+ cryptFilterObj.free();
+ }
+ stringFilterObj.free();
+ streamFilterObj.free();
+ cryptFiltersObj.free();
+ if (encryptDictA->dictLookup("EncryptMetadata",
+ &encryptMetadataObj)->isBool()) {
+ encryptMetadata = encryptMetadataObj.getBool();
+ }
+ encryptMetadataObj.free();
+ }
+ permFlags = permObj.getInt();
+ ownerKey = ownerKeyObj.getString()->copy();
+ userKey = userKeyObj.getString()->copy();
+ if (encVersion >= 1 && encVersion <= 2 &&
+ encRevision >= 2 && encRevision <= 3) {
+ if (fileIDObj.isArray()) {
+ if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) {
+ fileID = fileIDObj1.getString()->copy();
+ } else {
+ fileID = new GString();
+ }
+ fileIDObj1.free();
+ } else {
+ fileID = new GString();
+ }
+ ok = gTrue;
+ } else {
+ error(-1, "Unsupported version/revision (%d/%d) of Standard security handler",
+ encVersion, encRevision);
+ }
+ } else {
+ error(-1, "Weird encryption info");
+ }
+ if (fileKeyLength > 16) {
+ fileKeyLength = 16;
+ }
+ fileIDObj.free();
+ permObj.free();
+ userKeyObj.free();
+ ownerKeyObj.free();
+ lengthObj.free();
+ revisionObj.free();
+ versionObj.free();
+}
+
+StandardSecurityHandler::~StandardSecurityHandler() {
+ if (fileID) {
+ delete fileID;
+ }
+ if (ownerKey) {
+ delete ownerKey;
+ }
+ if (userKey) {
+ delete userKey;
+ }
+}
+
+void *StandardSecurityHandler::makeAuthData(GString *ownerPassword,
+ GString *userPassword) {
+ return new StandardAuthData(ownerPassword ? ownerPassword->copy()
+ : (GString *)NULL,
+ userPassword ? userPassword->copy()
+ : (GString *)NULL);
+}
+
+void *StandardSecurityHandler::getAuthData() {
+#if HAVE_XPDFCORE
+ XPDFCore *core;
+ GString *password;
+
+ if (!(core = (XPDFCore *)doc->getGUIData()) ||
+ !(password = core->getPassword())) {
+ return NULL;
+ }
+ return new StandardAuthData(password, password->copy());
+#elif HAVE_WINPDFCORE
+ WinPDFCore *core;
+ GString *password;
+
+ if (!(core = (WinPDFCore *)doc->getGUIData()) ||
+ !(password = core->getPassword())) {
+ return NULL;
+ }
+ return new StandardAuthData(password, password->copy());
+#else
+ return NULL;
+#endif
+}
+
+void StandardSecurityHandler::freeAuthData(void *authData) {
+ delete (StandardAuthData *)authData;
+}
+
+GBool StandardSecurityHandler::authorize(void *authData) {
+ GString *ownerPassword, *userPassword;
+
+ if (!ok) {
+ return gFalse;
+ }
+ if (authData) {
+ ownerPassword = ((StandardAuthData *)authData)->ownerPassword;
+ userPassword = ((StandardAuthData *)authData)->userPassword;
+ } else {
+ ownerPassword = NULL;
+ userPassword = NULL;
+ }
+ if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength,
+ ownerKey, userKey, permFlags, fileID,
+ ownerPassword, userPassword, fileKey,
+ encryptMetadata, &ownerPasswordOk)) {
+ return gFalse;
+ }
+ return gTrue;
+}
+
+#ifdef ENABLE_PLUGINS
+
+//------------------------------------------------------------------------
+// ExternalSecurityHandler
+//------------------------------------------------------------------------
+
+ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA,
+ Object *encryptDictA,
+ XpdfSecurityHandler *xshA):
+ SecurityHandler(docA)
+{
+ encryptDictA->copy(&encryptDict);
+ xsh = xshA;
+ ok = gFalse;
+
+ if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA,
+ (XpdfObject)encryptDictA, &docData)) {
+ return;
+ }
+
+ ok = gTrue;
+}
+
+ExternalSecurityHandler::~ExternalSecurityHandler() {
+ (*xsh->freeDoc)(xsh->handlerData, docData);
+ encryptDict.free();
+}
+
+void *ExternalSecurityHandler::makeAuthData(GString *ownerPassword,
+ GString *userPassword) {
+ char *opw, *upw;
+ void *authData;
+
+ opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL;
+ upw = userPassword ? userPassword->getCString() : (char *)NULL;
+ if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) {
+ return NULL;
+ }
+ return authData;
+}
+
+void *ExternalSecurityHandler::getAuthData() {
+ void *authData;
+
+ if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) {
+ return NULL;
+ }
+ return authData;
+}
+
+void ExternalSecurityHandler::freeAuthData(void *authData) {
+ (*xsh->freeAuthData)(xsh->handlerData, docData, authData);
+}
+
+GBool ExternalSecurityHandler::authorize(void *authData) {
+ char *key;
+ int length;
+
+ if (!ok) {
+ return gFalse;
+ }
+ permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData);
+ if (!(permFlags & xpdfPermissionOpen)) {
+ return gFalse;
+ }
+ if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion)) {
+ return gFalse;
+ }
+ if ((fileKeyLength = length) > 16) {
+ fileKeyLength = 16;
+ }
+ memcpy(fileKey, key, fileKeyLength);
+ (*xsh->freeKey)(xsh->handlerData, docData, key, length);
+ return gTrue;
+}
+
+#endif // ENABLE_PLUGINS
--- /dev/null
+//========================================================================
+//
+// SecurityHandler.h
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef SECURITYHANDLER_H
+#define SECURITYHANDLER_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+
+class GString;
+class PDFDoc;
+struct XpdfSecurityHandler;
+
+//------------------------------------------------------------------------
+// SecurityHandler
+//------------------------------------------------------------------------
+
+class SecurityHandler {
+public:
+
+ static SecurityHandler *make(PDFDoc *docA, Object *encryptDictA);
+
+ SecurityHandler(PDFDoc *docA);
+ virtual ~SecurityHandler();
+
+ // Check the document's encryption. If the document is encrypted,
+ // this will first try <ownerPassword> and <userPassword> (in
+ // "batch" mode), and if those fail, it will attempt to request a
+ // password from the user. This is the high-level function that
+ // calls the lower level functions for the specific security handler
+ // (requesting a password three times, etc.). Returns true if the
+ // document can be opened (if it's unencrypted, or if a correct
+ // password is obtained); false otherwise (encrypted and no correct
+ // password).
+ GBool checkEncryption(GString *ownerPassword,
+ GString *userPassword);
+
+ // Create authorization data for the specified owner and user
+ // passwords. If the security handler doesn't support "batch" mode,
+ // this function should return NULL.
+ virtual void *makeAuthData(GString *ownerPassword,
+ GString *userPassword) = 0;
+
+ // Construct authorization data, typically by prompting the user for
+ // a password. Returns an authorization data object, or NULL to
+ // cancel.
+ virtual void *getAuthData() = 0;
+
+ // Free the authorization data returned by makeAuthData or
+ // getAuthData.
+ virtual void freeAuthData(void *authData) = 0;
+
+ // Attempt to authorize the document, using the supplied
+ // authorization data (which may be NULL). Returns true if
+ // successful (i.e., if at least the right to open the document was
+ // granted).
+ virtual GBool authorize(void *authData) = 0;
+
+ // Return the various authorization parameters. These are only
+ // valid after authorize has returned true.
+ virtual int getPermissionFlags() = 0;
+ virtual GBool getOwnerPasswordOk() = 0;
+ virtual Guchar *getFileKey() = 0;
+ virtual int getFileKeyLength() = 0;
+ virtual int getEncVersion() = 0;
+
+protected:
+
+ PDFDoc *doc;
+};
+
+//------------------------------------------------------------------------
+// StandardSecurityHandler
+//------------------------------------------------------------------------
+
+class StandardSecurityHandler: public SecurityHandler {
+public:
+
+ StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA);
+ virtual ~StandardSecurityHandler();
+
+ virtual void *makeAuthData(GString *ownerPassword,
+ GString *userPassword);
+ virtual void *getAuthData();
+ virtual void freeAuthData(void *authData);
+ virtual GBool authorize(void *authData);
+ virtual int getPermissionFlags() { return permFlags; }
+ virtual GBool getOwnerPasswordOk() { return ownerPasswordOk; }
+ virtual Guchar *getFileKey() { return fileKey; }
+ virtual int getFileKeyLength() { return fileKeyLength; }
+ virtual int getEncVersion() { return encVersion; }
+
+private:
+
+ int permFlags;
+ GBool ownerPasswordOk;
+ Guchar fileKey[16];
+ int fileKeyLength;
+ int encVersion;
+ int encRevision;
+ GBool encryptMetadata;
+
+ GString *ownerKey, *userKey;
+ GString *fileID;
+ GBool ok;
+};
+
+#ifdef ENABLE_PLUGINS
+//------------------------------------------------------------------------
+// ExternalSecurityHandler
+//------------------------------------------------------------------------
+
+class ExternalSecurityHandler: public SecurityHandler {
+public:
+
+ ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA,
+ XpdfSecurityHandler *xshA);
+ virtual ~ExternalSecurityHandler();
+
+ virtual void *makeAuthData(GString *ownerPassword,
+ GString *userPassword);
+ virtual void *getAuthData();
+ virtual void freeAuthData(void *authData);
+ virtual GBool authorize(void *authData);
+ virtual int getPermissionFlags() { return permFlags; }
+ virtual GBool getOwnerPasswordOk() { return gFalse; }
+ virtual Guchar *getFileKey() { return fileKey; }
+ virtual int getFileKeyLength() { return fileKeyLength; }
+ virtual int getEncVersion() { return encVersion; }
+
+private:
+
+ Object encryptDict;
+ XpdfSecurityHandler *xsh;
+ void *docData;
+ int permFlags;
+ Guchar fileKey[16];
+ int fileKeyLength;
+ int encVersion;
+ GBool ok;
+};
+#endif // ENABLE_PLUGINS
+
+#endif
#include "gtypes.h"
#include "Object.h"
-#ifndef NO_DECRYPTION
class Decrypt;
-#endif
class BaseStream;
//------------------------------------------------------------------------
strWeird // internal-use stream types
};
+enum StreamColorSpaceMode {
+ streamCSNone,
+ streamCSDeviceGray,
+ streamCSDeviceRGB,
+ streamCSDeviceCMYK
+};
+
//------------------------------------------------------------------------
// Stream (base class)
//------------------------------------------------------------------------
// Is this an encoding filter?
virtual GBool isEncoder() { return gFalse; }
+ // Get image parameters which are defined by the stream contents.
+ virtual void getImageParams(int *bitsPerComponent,
+ StreamColorSpaceMode *csMode) {}
+
// Add filters to this stream according to the parameters in <dict>.
// Returns the new stream.
Stream *addFilters(Object *dict);
- // Tell this stream to ignore any length limitation -- this only
- // applies to BaseStream subclasses, and is used as a hack to work
- // around broken PDF files with incorrect stream lengths.
- virtual void ignoreLength() {}
-
private:
Stream *makeFilter(char *name, Stream *str, Object *params);
virtual Guint getStart() = 0;
virtual void moveStart(int delta) = 0;
-#ifndef NO_DECRYPTION
// Set decryption for this stream.
virtual void doDecryption(Guchar *fileKey, int keyLength,
int objNum, int objGen);
-#endif
-#ifndef NO_DECRYPTION
protected:
Decrypt *decrypt;
-#endif
private:
virtual void setPos(Guint pos, int dir = 0);
virtual BaseStream *getBaseStream() { return str->getBaseStream(); }
virtual Dict *getDict() { return str->getDict(); }
- virtual void ignoreLength() { str->ignoreLength(); }
protected:
~StreamPredictor();
+ GBool isOk() { return ok; }
+
int lookChar();
int getChar();
int rowBytes; // bytes per line
Guchar *predLine; // line buffer
int predIdx; // current index in predLine
+ GBool ok;
};
//------------------------------------------------------------------------
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
virtual int getPos() { return bufPos + (bufPtr - buf); }
virtual void setPos(Guint pos, int dir = 0);
- virtual void ignoreLength() { limited = gFalse; }
virtual Guint getStart() { return start; }
virtual void moveStart(int delta);
virtual void setPos(Guint pos, int dir = 0);
virtual Guint getStart() { return start; }
virtual void moveStart(int delta);
-#ifndef NO_DECRYPTION
virtual void doDecryption(Guchar *fileKey, int keyLength,
int objNum, int objGen);
-#endif
private:
GBool gotJFIFMarker; // set if APP0 JFIF marker was present
GBool gotAdobeMarker; // set if APP14 Adobe marker was present
int restartInterval; // restart interval, in MCUs
- Guchar quantTables[4][64]; // quantization tables
+ Gushort quantTables[4][64]; // quantization tables
int numQuantTables; // number of quantization tables
DCTHuffTable dcHuffTables[4]; // DC Huffman tables
DCTHuffTable acHuffTables[4]; // AC Huffman tables
DCTHuffTable *acHuffTable,
int *prevDC, int data[64]);
void decodeImage();
- void transformDataUnit(Guchar *quantTable,
+ void transformDataUnit(Gushort *quantTable,
int dataIn[64], Guchar dataOut[64]);
int readHuffSym(DCTHuffTable *table);
int readAmp(int size);
lengthDecode[flateMaxLitCodes-257];
static FlateDecode // distance decoding info
distDecode[flateMaxDistCodes];
+ static FlateHuffmanTab // fixed literal code table
+ fixedLitCodeTab;
+ static FlateHuffmanTab // fixed distance code table
+ fixedDistCodeTab;
void readSome();
GBool startBlock();
map = new UnicodeMap(encodingNameA->copy());
size = 8;
- map->ranges = (UnicodeMapRange *)gmalloc(size * sizeof(UnicodeMapRange));
+ map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange));
eMapsSize = 0;
line = 1;
if (map->len == size) {
size *= 2;
map->ranges = (UnicodeMapRange *)
- grealloc(map->ranges, size * sizeof(UnicodeMapRange));
+ greallocn(map->ranges, size, sizeof(UnicodeMapRange));
}
range = &map->ranges[map->len];
sscanf(tok1, "%x", &range->start);
if (map->eMapsLen == eMapsSize) {
eMapsSize += 16;
map->eMaps = (UnicodeMapExt *)
- grealloc(map->eMaps, eMapsSize * sizeof(UnicodeMapExt));
+ greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt));
}
eMap = &map->eMaps[map->eMapsLen];
sscanf(tok1, "%x", &eMap->u);
UnicodeMapExt *eMaps; // (user)
int eMapsLen; // (user)
int refCnt;
-#ifdef MULTITHREADED
+#if MULTITHREADED
GMutex mutex;
#endif
};
#include "Lexer.h"
#include "Parser.h"
#include "Dict.h"
-#ifndef NO_DECRYPTION
-#include "Decrypt.h"
-#endif
#include "Error.h"
#include "ErrorCodes.h"
#include "XRef.h"
#define xrefSearchSize 1024 // read this many bytes at end of file
// to look for 'startxref'
-#ifndef NO_DECRYPTION
//------------------------------------------------------------------------
// Permission bits
//------------------------------------------------------------------------
#define permCopy (1<<4)
#define permNotes (1<<5)
#define defPermFlags 0xfffc
-#endif
//------------------------------------------------------------------------
// ObjectStream
}
nObjects = obj1.getInt();
obj1.free();
- if (nObjects == 0) {
+ if (nObjects <= 0) {
goto err1;
}
}
first = obj1.getInt();
obj1.free();
+ if (first < 0) {
+ goto err1;
+ }
objs = new Object[nObjects];
- objNums = (int *)gmalloc(nObjects * sizeof(int));
- offsets = (int *)gmalloc(nObjects * sizeof(int));
+ objNums = (int *)gmallocn(nObjects, sizeof(int));
+ offsets = (int *)gmallocn(nObjects, sizeof(int));
// parse the header: object numbers and offsets
objStr.streamReset();
offsets[i] = obj2.getInt();
obj1.free();
obj2.free();
+ if (objNums[i] < 0 || offsets[i] < 0 ||
+ (i > 0 && offsets[i] < offsets[i-1])) {
+ delete parser;
+ gfree(offsets);
+ goto err1;
+ }
}
while (str->getChar() != EOF) ;
delete parser;
// XRef
//------------------------------------------------------------------------
-XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) {
+XRef::XRef(BaseStream *strA) {
Guint pos;
Object obj;
streamEndsLen = 0;
objStr = NULL;
+ encrypted = gFalse;
+ permFlags = defPermFlags;
+ ownerPasswordOk = gFalse;
+
// read the trailer
str = strA;
start = str->getStart();
// now set the trailer dictionary's xref pointer so we can fetch
// indirect objects from it
trailerDict.getDict()->setXRef(this);
-
- // check for encryption
-#ifndef NO_DECRYPTION
- encrypted = gFalse;
-#endif
- if (checkEncrypted(ownerPassword, userPassword)) {
- ok = gFalse;
- errCode = errEncrypted;
- return;
- }
}
XRef::~XRef() {
}
n = obj.getInt();
obj.free();
+ if (first < 0 || n < 0 || first + n < 0) {
+ goto err1;
+ }
if (first + n > size) {
for (newSize = size ? 2 * size : 1024;
- first + n > newSize;
+ first + n > newSize && newSize > 0;
newSize <<= 1) ;
- entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
+ if (newSize < 0) {
+ goto err1;
+ }
+ entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
for (i = size; i < newSize; ++i) {
entries[i].offset = 0xffffffff;
entries[i].type = xrefEntryFree;
// check for an 'XRefStm' key
if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) {
- pos2 = obj2.getInt();
+ pos2 = (Guint)obj2.getInt();
readXRef(&pos2);
if (!ok) {
+ obj2.free();
goto err1;
}
}
}
newSize = obj.getInt();
obj.free();
+ if (newSize < 0) {
+ goto err1;
+ }
if (newSize > size) {
- entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
+ entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
for (i = size; i < newSize; ++i) {
entries[i].offset = 0xffffffff;
entries[i].type = xrefEntryFree;
}
w[i] = obj2.getInt();
obj2.free();
+ if (w[i] < 0 || w[i] > 4) {
+ goto err1;
+ }
}
obj.free();
}
n = obj.getInt();
obj.free();
- if (!readXRefStreamSection(xrefStr, w, first, n)) {
+ if (first < 0 || n < 0 ||
+ !readXRefStreamSection(xrefStr, w, first, n)) {
idx.free();
goto err0;
}
}
} else {
- if (!readXRefStreamSection(xrefStr, w, 0, size)) {
+ if (!readXRefStreamSection(xrefStr, w, 0, newSize)) {
idx.free();
goto err0;
}
Guint offset;
int type, gen, c, newSize, i, j;
+ if (first + n < 0) {
+ return gFalse;
+ }
if (first + n > size) {
for (newSize = size ? 2 * size : 1024;
- first + n > newSize;
+ first + n > newSize && newSize > 0;
newSize <<= 1) ;
- entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
+ if (newSize < 0) {
+ return gFalse;
+ }
+ entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
for (i = size; i < newSize; ++i) {
entries[i].offset = 0xffffffff;
entries[i].type = xrefEntryFree;
}
gen = (gen << 8) + c;
}
- switch (type) {
- case 0:
- entries[i].offset = offset;
- entries[i].gen = gen;
- entries[i].type = xrefEntryFree;
- break;
- case 1:
- entries[i].offset = offset;
- entries[i].gen = gen;
- entries[i].type = xrefEntryUncompressed;
- break;
- case 2:
- entries[i].offset = offset;
- entries[i].gen = gen;
- entries[i].type = xrefEntryCompressed;
- break;
- default:
- return gFalse;
+ if (entries[i].offset == 0xffffffff) {
+ switch (type) {
+ case 0:
+ entries[i].offset = offset;
+ entries[i].gen = gen;
+ entries[i].type = xrefEntryFree;
+ break;
+ case 1:
+ entries[i].offset = offset;
+ entries[i].gen = gen;
+ entries[i].type = xrefEntryUncompressed;
+ break;
+ case 2:
+ entries[i].offset = offset;
+ entries[i].gen = gen;
+ entries[i].type = xrefEntryCompressed;
+ break;
+ default:
+ return gFalse;
+ }
}
}
obj.initNull();
parser = new Parser(NULL,
new Lexer(NULL,
- str->makeSubStream(start + pos + 7, gFalse, 0, &obj)));
+ str->makeSubStream(pos + 7, gFalse, 0, &obj)));
parser->getObj(&newTrailerDict);
if (newTrailerDict.isDict()) {
newTrailerDict.dictLookupNF("Root", &obj);
// look for object
} else if (isdigit(*p)) {
num = atoi(p);
- do {
- ++p;
- } while (*p && isdigit(*p));
- if (isspace(*p)) {
+ if (num > 0) {
do {
++p;
- } while (*p && isspace(*p));
- if (isdigit(*p)) {
- gen = atoi(p);
+ } while (*p && isdigit(*p));
+ if (isspace(*p)) {
do {
++p;
- } while (*p && isdigit(*p));
- if (isspace(*p)) {
+ } while (*p && isspace(*p));
+ if (isdigit(*p)) {
+ gen = atoi(p);
do {
++p;
- } while (*p && isspace(*p));
- if (!strncmp(p, "obj", 3)) {
- if (num >= size) {
- newSize = (num + 1 + 255) & ~255;
- entries = (XRefEntry *)
- grealloc(entries, newSize * sizeof(XRefEntry));
- for (i = size; i < newSize; ++i) {
- entries[i].offset = 0xffffffff;
- entries[i].type = xrefEntryFree;
+ } while (*p && isdigit(*p));
+ if (isspace(*p)) {
+ do {
+ ++p;
+ } while (*p && isspace(*p));
+ if (!strncmp(p, "obj", 3)) {
+ if (num >= size) {
+ newSize = (num + 1 + 255) & ~255;
+ if (newSize < 0) {
+ error(-1, "Bad object number");
+ return gFalse;
+ }
+ entries = (XRefEntry *)
+ greallocn(entries, newSize, sizeof(XRefEntry));
+ for (i = size; i < newSize; ++i) {
+ entries[i].offset = 0xffffffff;
+ entries[i].type = xrefEntryFree;
+ }
+ size = newSize;
+ }
+ if (entries[num].type == xrefEntryFree ||
+ gen >= entries[num].gen) {
+ entries[num].offset = pos - start;
+ entries[num].gen = gen;
+ entries[num].type = xrefEntryUncompressed;
}
- size = newSize;
- }
- if (entries[num].type == xrefEntryFree ||
- gen >= entries[num].gen) {
- entries[num].offset = pos - start;
- entries[num].gen = gen;
- entries[num].type = xrefEntryUncompressed;
}
}
}
} else if (!strncmp(p, "endstream", 9)) {
if (streamEndsLen == streamEndsSize) {
streamEndsSize += 64;
- streamEnds = (Guint *)grealloc(streamEnds,
- streamEndsSize * sizeof(int));
+ streamEnds = (Guint *)greallocn(streamEnds,
+ streamEndsSize, sizeof(int));
}
streamEnds[streamEndsLen++] = pos;
}
return gFalse;
}
-#ifndef NO_DECRYPTION
-GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) {
- Object encrypt, filterObj, versionObj, revisionObj, lengthObj;
- Object ownerKey, userKey, permissions, fileID, fileID1;
- GBool encrypted1;
- GBool ret;
-
- keyLength = 0;
- encVersion = encRevision = 0;
- ret = gFalse;
+void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA,
+ Guchar *fileKeyA, int keyLengthA, int encVersionA) {
+ int i;
- permFlags = defPermFlags;
- ownerPasswordOk = gFalse;
- trailerDict.dictLookup("Encrypt", &encrypt);
- if ((encrypted1 = encrypt.isDict())) {
- ret = gTrue;
- encrypt.dictLookup("Filter", &filterObj);
- if (filterObj.isName("Standard")) {
- encrypt.dictLookup("V", &versionObj);
- encrypt.dictLookup("R", &revisionObj);
- encrypt.dictLookup("Length", &lengthObj);
- encrypt.dictLookup("O", &ownerKey);
- encrypt.dictLookup("U", &userKey);
- encrypt.dictLookup("P", &permissions);
- trailerDict.dictLookup("ID", &fileID);
- if (versionObj.isInt() &&
- revisionObj.isInt() &&
- ownerKey.isString() && ownerKey.getString()->getLength() == 32 &&
- userKey.isString() && userKey.getString()->getLength() == 32 &&
- permissions.isInt() &&
- fileID.isArray()) {
- encVersion = versionObj.getInt();
- encRevision = revisionObj.getInt();
- if (lengthObj.isInt()) {
- keyLength = lengthObj.getInt() / 8;
- } else {
- keyLength = 5;
- }
- permFlags = permissions.getInt();
- if (encVersion >= 1 && encVersion <= 2 &&
- encRevision >= 2 && encRevision <= 3) {
- fileID.arrayGet(0, &fileID1);
- if (fileID1.isString()) {
- if (Decrypt::makeFileKey(encVersion, encRevision, keyLength,
- ownerKey.getString(), userKey.getString(),
- permFlags, fileID1.getString(),
- ownerPassword, userPassword, fileKey,
- &ownerPasswordOk)) {
- if (ownerPassword && !ownerPasswordOk) {
- error(-1, "Incorrect owner password");
- }
- ret = gFalse;
- } else {
- error(-1, "Incorrect password");
- }
- } else {
- error(-1, "Weird encryption info");
- }
- fileID1.free();
- } else {
- error(-1, "Unsupported version/revision (%d/%d) of Standard security handler",
- encVersion, encRevision);
- }
- } else {
- error(-1, "Weird encryption info");
- }
- fileID.free();
- permissions.free();
- userKey.free();
- ownerKey.free();
- lengthObj.free();
- revisionObj.free();
- versionObj.free();
- } else {
- error(-1, "Unknown security handler '%s'",
- filterObj.isName() ? filterObj.getName() : "???");
- }
- filterObj.free();
+ encrypted = gTrue;
+ permFlags = permFlagsA;
+ ownerPasswordOk = ownerPasswordOkA;
+ if (keyLengthA <= 16) {
+ keyLength = keyLengthA;
+ } else {
+ keyLength = 16;
}
- encrypt.free();
-
- // this flag has to be set *after* we read the O/U/P strings
- encrypted = encrypted1;
-
- return ret;
-}
-#else
-GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) {
- Object obj;
- GBool encrypted;
-
- trailerDict.dictLookup("Encrypt", &obj);
- if ((encrypted = !obj.isNull())) {
- error(-1, "PDF file is encrypted and this version of the Xpdf tools");
- error(-1, "was built without decryption support.");
+ for (i = 0; i < keyLength; ++i) {
+ fileKey[i] = fileKeyA[i];
}
- obj.free();
- return encrypted;
+ encVersion = encVersionA;
}
-#endif
GBool XRef::okToPrint(GBool ignoreOwnerPW) {
-#ifndef NO_DECRYPTION
return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint);
-#else
- return gTrue;
-#endif
}
GBool XRef::okToChange(GBool ignoreOwnerPW) {
-#ifndef NO_DECRYPTION
return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange);
-#else
- return gTrue;
-#endif
}
GBool XRef::okToCopy(GBool ignoreOwnerPW) {
-#ifndef NO_DECRYPTION
return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy);
-#else
- return gTrue;
-#endif
}
GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
-#ifndef NO_DECRYPTION
return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes);
-#else
- return gTrue;
-#endif
}
Object *XRef::fetch(int num, int gen, Object *obj) {
if (!obj1.isInt() || obj1.getInt() != num ||
!obj2.isInt() || obj2.getInt() != gen ||
!obj3.isCmd("obj")) {
+ obj1.free();
+ obj2.free();
+ obj3.free();
+ delete parser;
goto err;
}
-#ifndef NO_DECRYPTION
parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength,
num, gen);
-#else
- parser->getObj(obj);
-#endif
obj1.free();
obj2.free();
obj3.free();
public:
// Constructor. Read xref table from stream.
- XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword);
+ XRef(BaseStream *strA);
// Destructor.
~XRef();
// Get the error code (if isOk() returns false).
int getErrorCode() { return errCode; }
+ // Set the encryption parameters.
+ void setEncryption(int permFlagsA, GBool ownerPasswordOkA,
+ Guchar *fileKeyA, int keyLengthA, int encVersionA);
+
// Is the file encrypted?
-#ifndef NO_DECRYPTION
GBool isEncrypted() { return encrypted; }
-#else
- GBool isEncrypted() { return gFalse; }
-#endif
// Check various permissions.
GBool okToPrint(GBool ignoreOwnerPW = gFalse);
// damaged files
int streamEndsLen; // number of valid entries in streamEnds
ObjectStream *objStr; // cached object stream
-#ifndef NO_DECRYPTION
GBool encrypted; // true if file is encrypted
- int encVersion; // encryption algorithm
- int encRevision; // security handler revision
- int keyLength; // length of key, in bytes
int permFlags; // permission bits
- Guchar fileKey[16]; // file decryption key
GBool ownerPasswordOk; // true if owner password is correct
-#endif
+ Guchar fileKey[16]; // file decryption key
+ int keyLength; // length of key, in bytes
+ int encVersion; // encryption algorithm
Guint getStartXref();
GBool readXRef(Guint *pos);
GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n);
GBool readXRefStream(Stream *xrefStr, Guint *pos);
GBool constructXRef();
- GBool checkEncrypted(GString *ownerPassword, GString *userPassword);
Guint strToUnsigned(char *s);
};
static int gMemIndex = 0;
static int gMemAlloc = 0;
+static int gMemInUse = 0;
#endif /* DEBUG_MEM */
hdr->next = gMemList[lst];
gMemList[lst] = hdr;
++gMemAlloc;
+ gMemInUse += size;
for (p = (unsigned long *)data; p <= trl; ++p)
*p = gMemDeadVal;
return data;
#endif
}
+void *gmallocn(int nObjs, int objSize) {
+ int n;
+
+ n = nObjs * objSize;
+ if (objSize == 0 || n / objSize != nObjs) {
+ fprintf(stderr, "Bogus memory allocation size\n");
+ exit(1);
+ }
+ return gmalloc(n);
+}
+
+void *greallocn(void *p, int nObjs, int objSize) {
+ int n;
+
+ n = nObjs * objSize;
+ if (objSize == 0 || n / objSize != nObjs) {
+ fprintf(stderr, "Bogus memory allocation size\n");
+ exit(1);
+ }
+ return grealloc(p, n);
+}
+
void gfree(void *p) {
#ifdef DEBUG_MEM
int size;
else
gMemList[lst] = hdr->next;
--gMemAlloc;
+ gMemInUse -= hdr->size;
size = gMemDataSize(hdr->size);
trl = (unsigned long *)((char *)hdr + gMemHdrSize + size);
if (*trl != gMemDeadVal) {
extern void *grealloc(void *p, int size);
/*
+ * These are similar to gmalloc and grealloc, but take an object count
+ * and size. The result is similar to allocating nObjs * objSize
+ * bytes, but there is an additional error check that the total size
+ * doesn't overflow an int.
+ */
+extern void *gmallocn(int nObjs, int objSize);
+extern void *greallocn(void *p, int nObjs, int objSize);
+
+/*
* Same as free, but checks for and ignores NULL pointers.
*/
extern void gfree(void *p);