#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();