X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=pdf2swf%2Fxpdf%2FXRef.cc;fp=pdf2swf%2Fxpdf%2FXRef.cc;h=0e1bbc9c6c620a4162cc2e7609fcad89bc1122e1;hp=d70b9f2097c48e6ce37fb9c1f12617b533be8c6b;hb=50dd339d3d6262763616efe8d7ee415ab19befb9;hpb=33b4efceb35f7582426665aba920fd950edc0602 diff --git a/pdf2swf/xpdf/XRef.cc b/pdf2swf/xpdf/XRef.cc index d70b9f2..0e1bbc9 100644 --- a/pdf2swf/xpdf/XRef.cc +++ b/pdf2swf/xpdf/XRef.cc @@ -2,7 +2,7 @@ // // XRef.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include #include @@ -24,6 +25,7 @@ #include "Decrypt.h" #endif #include "Error.h" +#include "ErrorCodes.h" #include "XRef.h" //------------------------------------------------------------------------ @@ -44,33 +46,22 @@ #endif //------------------------------------------------------------------------ -// The global xref table -//------------------------------------------------------------------------ - -XRef *xref = NULL; - -//------------------------------------------------------------------------ // XRef //------------------------------------------------------------------------ -XRef::XRef(BaseStream *str, GString *userPassword) { - XRef *oldXref; - int pos; +XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { + Guint pos; int i; ok = gTrue; + errCode = errNone; size = 0; entries = NULL; streamEnds = NULL; streamEndsLen = 0; - // get rid of old xref (otherwise it will try to fetch the Root object - // in the new document, using the old xref) - oldXref = xref; - xref = NULL; - // read the trailer - this->str = str; + str = strA; start = str->getStart(); pos = readTrailer(); @@ -78,7 +69,7 @@ XRef::XRef(BaseStream *str, GString *userPassword) { // try to reconstruct the xref table if (pos == 0) { if (!(ok = constructXRef())) { - xref = oldXref; + errCode = errDamaged; return; } @@ -86,7 +77,7 @@ XRef::XRef(BaseStream *str, GString *userPassword) { } else { entries = (XRefEntry *)gmalloc(size * sizeof(XRefEntry)); for (i = 0; i < size; ++i) { - entries[i].offset = -1; + entries[i].offset = 0xffffffff; entries[i].used = gFalse; } while (readXRef(&pos)) ; @@ -98,22 +89,23 @@ XRef::XRef(BaseStream *str, GString *userPassword) { size = 0; entries = NULL; if (!(ok = constructXRef())) { - xref = oldXref; + errCode = errDamaged; return; } } } - // set up new xref table - xref = this; + // 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(userPassword)) { + if (checkEncrypted(ownerPassword, userPassword)) { ok = gFalse; - xref = oldXref; + errCode = errEncrypted; return; } } @@ -128,17 +120,18 @@ XRef::~XRef() { // Read startxref position, xref table size, and root. Returns // first xref position. -int XRef::readTrailer() { +Guint XRef::readTrailer() { Parser *parser; Object obj; char buf[xrefSearchSize+1]; - int n, pos, pos1; + int n; + Guint pos, pos1; char *p; int c; int i; // read last xrefSearchSize bytes - str->setPos(-xrefSearchSize); + str->setPos(xrefSearchSize, -1); for (n = 0; n < xrefSearchSize; ++n) { if ((c = str->getChar()) == EOF) break; @@ -154,7 +147,7 @@ int XRef::readTrailer() { if (i < 0) return 0; for (p = &buf[i+9]; isspace(*p); ++p) ; - pos = lastXRefPos = atoi(p); + pos = lastXRefPos = strToUnsigned(p); // find trailer dict by looking after first xref table // (NB: we can't just use the trailer dict at the end of the file -- @@ -189,7 +182,9 @@ int XRef::readTrailer() { // read trailer dict obj.initNull(); - parser = new Parser(new Lexer(str->makeSubStream(start + pos1, -1, &obj))); + parser = new Parser(NULL, + new Lexer(NULL, + str->makeSubStream(start + pos1, gFalse, 0, &obj))); parser->getObj(&trailerDict); if (trailerDict.isDict()) { trailerDict.dictLookupNF("Size", &obj); @@ -216,12 +211,12 @@ int XRef::readTrailer() { } // Read an xref table and the prev pointer from the trailer. -GBool XRef::readXRef(int *pos) { +GBool XRef::readXRef(Guint *pos) { Parser *parser; Object obj, obj2; char s[20]; GBool more; - int first, n, i, j; + int first, newSize, n, i, j; int c; // seek to xref in stream @@ -233,77 +228,101 @@ GBool XRef::readXRef(int *pos) { s[1] = (char)str->getChar(); s[2] = (char)str->getChar(); s[3] = (char)str->getChar(); - if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f')) + if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f')) { goto err2; + } // read xref while (1) { - while ((c = str->lookChar()) != EOF && isspace(c)) + while ((c = str->lookChar()) != EOF && isspace(c)) { str->getChar(); - if (c == 't') + } + if (c == 't') { break; - for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) + } + for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) { s[i] = (char)c; - if (i == 0) + } + if (i == 0) { goto err2; + } s[i] = '\0'; first = atoi(s); - while ((c = str->lookChar()) != EOF && isspace(c)) + while ((c = str->lookChar()) != EOF && isspace(c)) { str->getChar(); - for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) + } + for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) { s[i] = (char)c; - if (i == 0) + } + if (i == 0) { goto err2; + } s[i] = '\0'; n = atoi(s); - while ((c = str->lookChar()) != EOF && isspace(c)) + while ((c = str->lookChar()) != EOF && isspace(c)) { str->getChar(); + } + // check for buggy PDF files with an incorrect (too small) xref + // table size + if (first + n > size) { + newSize = size + 256; + entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].used = gFalse; + } + size = newSize; + } for (i = first; i < first + n; ++i) { for (j = 0; j < 20; ++j) { - if ((c = str->getChar()) == EOF) + if ((c = str->getChar()) == EOF) { goto err2; + } s[j] = (char)c; } - if (entries[i].offset < 0) { + if (entries[i].offset == 0xffffffff) { s[10] = '\0'; - entries[i].offset = atoi(s); + entries[i].offset = strToUnsigned(s); s[16] = '\0'; entries[i].gen = atoi(&s[11]); - if (s[17] == 'n') + if (s[17] == 'n') { entries[i].used = gTrue; - else if (s[17] == 'f') + } else if (s[17] == 'f') { entries[i].used = gFalse; - else + } else { goto err2; -#if 1 //~ - //~ PDF files of patents from the IBM Intellectual Property - //~ Network have a bug: the xref table claims to start at 1 - //~ instead of 0. + } + // PDF files of patents from the IBM Intellectual Property + // Network have a bug: the xref table claims to start at 1 + // instead of 0. if (i == 1 && first == 1 && entries[1].offset == 0 && entries[1].gen == 65535 && !entries[1].used) { i = first = 0; entries[0] = entries[1]; - entries[1].offset = -1; + entries[1].offset = 0xffffffff; } -#endif } } } // read prev pointer from trailer dictionary obj.initNull(); - parser = new Parser(new Lexer(str->makeSubStream(str->getPos(), -1, &obj))); + parser = new Parser(NULL, + new Lexer(NULL, + str->makeSubStream(str->getPos(), gFalse, 0, &obj))); parser->getObj(&obj); - if (!obj.isCmd("trailer")) + if (!obj.isCmd("trailer")) { goto err1; + } obj.free(); parser->getObj(&obj); - if (!obj.isDict()) + if (!obj.isDict()) { goto err1; + } obj.getDict()->lookupNF("Prev", &obj2); if (obj2.isInt()) { - *pos = obj2.getInt(); + *pos = (Guint)obj2.getInt(); more = gTrue; } else { more = gFalse; @@ -326,7 +345,7 @@ GBool XRef::constructXRef() { Parser *parser; Object obj; char buf[256]; - int pos; + Guint pos; int num, gen; int newSize; int streamEndsSize; @@ -349,8 +368,9 @@ GBool XRef::constructXRef() { // got trailer dictionary if (!strncmp(p, "trailer", 7)) { obj.initNull(); - parser = new Parser(new Lexer( - str->makeSubStream(start + pos + 7, -1, &obj))); + parser = new Parser(NULL, + new Lexer(NULL, + str->makeSubStream(start + pos + 7, gFalse, 0, &obj))); if (!trailerDict.isNone()) trailerDict.free(); parser->getObj(&trailerDict); @@ -392,7 +412,7 @@ GBool XRef::constructXRef() { entries = (XRefEntry *) grealloc(entries, newSize * sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { - entries[i].offset = -1; + entries[i].offset = 0xffffffff; entries[i].used = gFalse; } size = newSize; @@ -410,7 +430,8 @@ GBool XRef::constructXRef() { } else if (!strncmp(p, "endstream", 9)) { if (streamEndsLen == streamEndsSize) { streamEndsSize += 64; - streamEnds = (int *)grealloc(streamEnds, streamEndsSize * sizeof(int)); + streamEnds = (Guint *)grealloc(streamEnds, + streamEndsSize * sizeof(int)); } streamEnds[streamEndsLen++] = pos; } @@ -424,8 +445,9 @@ GBool XRef::constructXRef() { } #ifndef NO_DECRYPTION -GBool XRef::checkEncrypted(GString *userPassword) { - Object encrypt, ownerKey, userKey, permissions, fileID, fileID1; +GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { + Object encrypt, filterObj, versionObj, revisionObj, lengthObj; + Object ownerKey, userKey, permissions, fileID, fileID1; GBool encrypted1; GBool ret; @@ -435,35 +457,68 @@ GBool XRef::checkEncrypted(GString *userPassword) { trailerDict.dictLookup("Encrypt", &encrypt); if ((encrypted1 = encrypt.isDict())) { ret = gTrue; - encrypt.dictLookup("O", &ownerKey); - encrypt.dictLookup("U", &userKey); - encrypt.dictLookup("P", &permissions); - trailerDict.dictLookup("ID", &fileID); - if (ownerKey.isString() && ownerKey.getString()->getLength() == 32 && - userKey.isString() && userKey.getString()->getLength() == 32 && - permissions.isInt() && - fileID.isArray()) { - permFlags = permissions.getInt(); - fileID.arrayGet(0, &fileID1); - if (fileID1.isString()) { - if (Decrypt::makeFileKey(ownerKey.getString(), userKey.getString(), - permFlags, fileID1.getString(), - userPassword, fileKey)) { - ret = gFalse; + 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 { - error(-1, "Incorrect user password"); + 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"); } - fileID1.free(); + fileID.free(); + permissions.free(); + userKey.free(); + ownerKey.free(); + lengthObj.free(); + revisionObj.free(); + versionObj.free(); } else { - error(-1, "Weird encryption info"); + error(-1, "Unknown security handler '%s'", + filterObj.isName() ? filterObj.getName() : "???"); } - ownerKey.free(); - userKey.free(); - permissions.free(); - fileID.free(); + filterObj.free(); } encrypt.free(); @@ -473,52 +528,50 @@ GBool XRef::checkEncrypted(GString *userPassword) { return ret; } #else -GBool XRef::checkEncrypted(GString *userPassword) { +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 cannot be displayed"); - error(-1, "* Decryption support is currently not included in xpdf"); - error(-1, "* due to legal restrictions: the U.S.A. still has bogus"); - error(-1, "* export controls on cryptography software."); + error(-1, "PDF file is encrypted and this version of the Xpdf tools"); + error(-1, "was built without decryption support."); } obj.free(); return encrypted; } #endif -GBool XRef::okToPrint() { +GBool XRef::okToPrint(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION - if (!(permFlags & permPrint)) { + if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permPrint)) { return gFalse; } #endif return gTrue; } -GBool XRef::okToChange() { +GBool XRef::okToChange(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION - if (!(permFlags & permChange)) { + if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permChange)) { return gFalse; } #endif return gTrue; } -GBool XRef::okToCopy() { +GBool XRef::okToCopy(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION - if (!(permFlags & permCopy)) { + if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permCopy)) { return gFalse; } #endif return gTrue; } -GBool XRef::okToAddNotes() { +GBool XRef::okToAddNotes(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION - if (!(permFlags & permNotes)) { + if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permNotes)) { return gFalse; } #endif @@ -537,10 +590,11 @@ Object *XRef::fetch(int num, int gen, Object *obj) { } e = &entries[num]; - if (e->gen == gen && e->offset >= 0) { + if (e->gen == gen && e->offset != 0xffffffff) { obj1.initNull(); - parser = new Parser(new Lexer( - str->makeSubStream(start + e->offset, -1, &obj1))); + parser = new Parser(this, + new Lexer(this, + str->makeSubStream(start + e->offset, gFalse, 0, &obj1))); parser->getObj(&obj1); parser->getObj(&obj2); parser->getObj(&obj3); @@ -548,7 +602,8 @@ Object *XRef::fetch(int num, int gen, Object *obj) { obj2.isInt() && obj2.getInt() == gen && obj3.isCmd("obj")) { #ifndef NO_DECRYPTION - parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, num, gen); + parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, + num, gen); #else parser->getObj(obj); #endif @@ -569,24 +624,42 @@ Object *XRef::getDocInfo(Object *obj) { return trailerDict.dictLookup("Info", obj); } -int XRef::getStreamEnd(int start) { +// Added for the pdftex project. +Object *XRef::getDocInfoNF(Object *obj) { + return trailerDict.dictLookupNF("Info", obj); +} + +GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) { int a, b, m; if (streamEndsLen == 0 || - start > streamEnds[streamEndsLen - 1]) { - return -1; + streamStart > streamEnds[streamEndsLen - 1]) { + return gFalse; } a = -1; b = streamEndsLen - 1; - // invariant: streamEnds[a] < start <= streamEnds[b] + // invariant: streamEnds[a] < streamStart <= streamEnds[b] while (b - a > 1) { m = (a + b) / 2; - if (start <= streamEnds[m]) { + if (streamStart <= streamEnds[m]) { b = m; } else { a = m; } } - return streamEnds[b]; + *streamEnd = streamEnds[b]; + return gTrue; +} + +Guint XRef::strToUnsigned(char *s) { + Guint x; + char *p; + int i; + + x = 0; + for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) { + x = 10 * x + (*p - '0'); + } + return x; }