diff options
Diffstat (limited to 'Build/source/libs/poppler/poppler-src/poppler/PDFDoc.cc')
-rw-r--r-- | Build/source/libs/poppler/poppler-src/poppler/PDFDoc.cc | 500 |
1 files changed, 197 insertions, 303 deletions
diff --git a/Build/source/libs/poppler/poppler-src/poppler/PDFDoc.cc b/Build/source/libs/poppler/poppler-src/poppler/PDFDoc.cc index f02f192f554..90f039d8ec8 100644 --- a/Build/source/libs/poppler/poppler-src/poppler/PDFDoc.cc +++ b/Build/source/libs/poppler/poppler-src/poppler/PDFDoc.cc @@ -28,13 +28,14 @@ // Copyright (C) 2010 Philip Lorenz <lorenzph+freedesktop@gmail.com> // Copyright (C) 2011-2016 Thomas Freitag <Thomas.Freitag@alfa.de> // Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it> -// Copyright (C) 2013, 2014 Adrian Johnson <ajohnson@redneon.com> +// Copyright (C) 2013, 2014, 2017 Adrian Johnson <ajohnson@redneon.com> // Copyright (C) 2013 Adam Reichold <adamreichold@myopera.com> // Copyright (C) 2014 Bogdan Cristea <cristeab@gmail.com> // Copyright (C) 2015 Li Junling <lijunling@sina.com> // Copyright (C) 2015 André Guerreiro <aguerreiro1985@gmail.com> // Copyright (C) 2015 André Esser <bepandre@hotmail.com> // Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com> +// Copyright (C) 2017 Jean Ghali <jghali@libertysurf.fr> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -42,6 +43,7 @@ //======================================================================== #include <config.h> +#include <poppler-config.h> #ifdef USE_GCC_PRAGMAS #pragma implementation @@ -51,11 +53,13 @@ #include <locale.h> #include <stdio.h> #include <errno.h> +#include <limits.h> #include <stdlib.h> #include <stddef.h> #include <string.h> #include <time.h> #include <sys/stat.h> +#include "goo/glibc.h" #include "goo/gstrtod.h" #include "goo/GooString.h" #include "goo/gfile.h" @@ -79,8 +83,9 @@ #endif #include "PDFDoc.h" #include "Hints.h" +#include "UTF.h" -#if MULTITHREADED +#ifdef MULTITHREADED # define pdfdocLocker() MutexLocker locker(&mutex) #else # define pdfdocLocker() @@ -105,7 +110,7 @@ void PDFDoc::init() { -#if MULTITHREADED +#ifdef MULTITHREADED gInitMutex(&mutex); #endif ok = gFalse; @@ -132,7 +137,6 @@ PDFDoc::PDFDoc() PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword, GooString *userPassword, void *guiDataA) { - Object obj; #ifdef _WIN32 int n, i; #endif @@ -151,7 +155,13 @@ PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword, #endif // try to open file - file = GooFile::open(fileName); +#ifdef _WIN32 + wchar_t *wFileName = (wchar_t*)utf8ToUtf16(fileName->getCString()); + file = GooFile::open(wFileName); + gfree(wFileName); +#else + file = GooFile::open(fileName); +#endif if (file == NULL) { // fopen() has failed. // Keep a copy of the errno returned by fopen so that it can be @@ -163,8 +173,7 @@ PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword, } // create stream - obj.initNull(); - str = new FileStream(file, 0, gFalse, file->size(), &obj); + str = new FileStream(file, 0, gFalse, file->size(), Object(objNull)); ok = setup(ownerPassword, userPassword); } @@ -173,7 +182,6 @@ PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword, PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, GooString *userPassword, void *guiDataA) { OSVERSIONINFO version; - Object obj; int i; init(); @@ -205,8 +213,7 @@ PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, } // create stream - obj.initNull(); - str = new FileStream(file, 0, gFalse, file->size(), &obj); + str = new FileStream(file, 0, gFalse, file->size(), Object(objNull)); ok = setup(ownerPassword, userPassword); } @@ -345,7 +352,7 @@ PDFDoc::~PDFDoc() { gfree(fileNameU); } #endif -#if MULTITHREADED +#ifdef MULTITHREADED gDestroyMutex(&mutex); #endif } @@ -419,11 +426,10 @@ void PDFDoc::checkHeader() { } GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword) { - Object encrypt; GBool encrypted; GBool ret; - xref->getTrailerDict()->dictLookup("Encrypt", &encrypt); + Object encrypt = xref->getTrailerDict()->dictLookup("Encrypt"); if ((encrypted = encrypt.isDict())) { if ((secHdlr = SecurityHandler::make(this, &encrypt))) { if (secHdlr->isUnencrypted()) { @@ -451,7 +457,6 @@ GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword) // document is not encrypted ret = gTrue; } - encrypt.free(); return ret; } @@ -565,7 +570,6 @@ GBool PDFDoc::checkLinearization() { return gFalse; } for (int page = 1; page <= linearization->getNumPages(); page++) { - Object obj; Ref pageRef; pageRef.num = hints->getPageObjectNum(page); @@ -581,13 +585,11 @@ GBool PDFDoc::checkLinearization() { } pageRef.gen = xref->getEntry(pageRef.num)->gen; - xref->fetch(pageRef.num, pageRef.gen, &obj); + Object obj = xref->fetch(pageRef.num, pageRef.gen); if (!obj.isDict("Page")) { - obj.free(); linearizationState = 2; return gFalse; } - obj.free(); } linearizationState = 1; return gTrue; @@ -607,10 +609,8 @@ GBool PDFDoc::isLinearized(GBool tryingToReconstruct) { void PDFDoc::setDocInfoModified(Object *infoObj) { - Object infoObjRef; - getDocInfoNF(&infoObjRef); + Object infoObjRef = getDocInfoNF(); xref->setModifiedObject(infoObj, infoObjRef.getRef()); - infoObjRef.free(); } void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value) @@ -620,25 +620,19 @@ void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value) delete value; } - Object infoObj; - getDocInfo(&infoObj); - + Object infoObj = getDocInfo(); if (infoObj.isNull() && removeEntry) { // No info dictionary, so no entry to remove. return; } - createDocInfoIfNoneExists(&infoObj); - - Object gooStrObj; + infoObj = createDocInfoIfNoneExists(); if (removeEntry) { - gooStrObj.initNull(); + infoObj.dictSet(key, Object(objNull)); } else { - gooStrObj.initString(value); + infoObj.dictSet(key, Object(value)); } - // gooStrObj is set to value or null by now. The latter will cause a removal. - infoObj.dictSet(key, &gooStrObj); if (infoObj.dictGetLength() == 0) { // Info dictionary is empty. Remove it altogether. @@ -646,19 +640,15 @@ void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value) } else { setDocInfoModified(&infoObj); } - - infoObj.free(); } GooString *PDFDoc::getDocInfoStringEntry(const char *key) { - Object infoObj; - getDocInfo(&infoObj); + Object infoObj = getDocInfo(); if (!infoObj.isDict()) { return NULL; } - Object entryObj; - infoObj.dictLookup(key, &entryObj); + Object entryObj = infoObj.dictLookup(key); GooString *result; @@ -668,9 +658,6 @@ GooString *PDFDoc::getDocInfoStringEntry(const char *key) { result = NULL; } - entryObj.free(); - infoObj.free(); - return result; } @@ -696,45 +683,35 @@ get_id (GooString *encodedidstring, GooString *id) { } GBool PDFDoc::getID(GooString *permanent_id, GooString *update_id) { - Object obj; - xref->getTrailerDict()->dictLookup ("ID", &obj); + Object obj = xref->getTrailerDict()->dictLookup ("ID"); if (obj.isArray() && obj.arrayGetLength() == 2) { - Object obj2; - if (permanent_id) { - if (obj.arrayGet(0, &obj2)->isString()) { + Object obj2 = obj.arrayGet(0); + if (obj2.isString()) { if (!get_id (obj2.getString(), permanent_id)) { - obj2.free(); return gFalse; } } else { error(errSyntaxError, -1, "Invalid permanent ID"); - obj2.free(); return gFalse; } - obj2.free(); } if (update_id) { - if (obj.arrayGet(1, &obj2)->isString()) { + Object obj2 = obj.arrayGet(1); + if (obj2.isString()) { if (!get_id (obj2.getString(), update_id)) { - obj2.free(); return gFalse; } } else { error(errSyntaxError, -1, "Invalid update ID"); - obj2.free(); return gFalse; } - obj2.free(); } - obj.free(); - return gTrue; } - obj.free(); return gFalse; } @@ -777,8 +754,7 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) getCatalog()->getPage(pageNo)->getMediaBox(), cropBox); Ref *refPage = getCatalog()->getPageRef(pageNo); - Object page; - getXRef()->fetch(refPage->num, refPage->gen, &page); + Object page = getXRef()->fetch(refPage->num, refPage->gen); if (!(f = fopen(name->getCString(), "wb"))) { error(errIO, -1, "Couldn't open file '{0:t}'", name); @@ -801,55 +777,48 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) writeHeader(outStr, getPDFMajorVersion(), getPDFMinorVersion()); // get and mark info dict - Object infoObj; - getXRef()->getDocInfo(&infoObj); + Object infoObj = getXRef()->getDocInfo(); if (infoObj.isDict()) { Dict *infoDict = infoObj.getDict(); markPageObjects(infoDict, yRef, countRef, 0, refPage->num, rootNum + 2); if (trailerObj->isDict()) { Dict *trailerDict = trailerObj->getDict(); - Object ref; - trailerDict->lookupNF("Info", &ref); + Object ref = trailerDict->lookupNF("Info"); if (ref.isRef()) { yRef->add(ref.getRef().num, ref.getRef().gen, 0, gTrue); if (getXRef()->getEntry(ref.getRef().num)->type == xrefEntryCompressed) { yRef->getEntry(ref.getRef().num)->type = xrefEntryCompressed; } } - ref.free(); } } - infoObj.free(); // get and mark output intents etc. - Object catObj, pagesObj, resourcesObj, annotsObj, afObj; - getXRef()->getCatalog(&catObj); + Object catObj = getXRef()->getCatalog(); Dict *catDict = catObj.getDict(); - catDict->lookup("Pages", &pagesObj); - catDict->lookupNF("AcroForm", &afObj); + Object pagesObj = catDict->lookup("Pages"); + Object afObj = catDict->lookupNF("AcroForm"); if (!afObj.isNull()) { markAcroForm(&afObj, yRef, countRef, 0, refPage->num, rootNum + 2); - afObj.free(); } Dict *pagesDict = pagesObj.getDict(); - pagesDict->lookup("Resources", &resourcesObj); + Object resourcesObj = pagesDict->lookup("Resources"); if (resourcesObj.isDict()) markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2); markPageObjects(catDict, yRef, countRef, 0, refPage->num, rootNum + 2); Dict *pageDict = page.getDict(); if (resourcesObj.isNull() && !pageDict->hasKey("Resources")) { - Dict *resourceDict = getCatalog()->getPage(pageNo)->getResourceDict(); - if (resourceDict != NULL) { - resourcesObj.initDict(resourceDict); + Object *resourceDictObject = getCatalog()->getPage(pageNo)->getResourceDictObject(); + if (resourceDictObject->isDict()) { + resourcesObj = resourceDictObject->copy(); markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2); } } markPageObjects(pageDict, yRef, countRef, 0, refPage->num, rootNum + 2); - pageDict->lookupNF("Annots", &annotsObj); + Object annotsObj = pageDict->lookupNF("Annots"); if (!annotsObj.isNull()) { markAnnotations(&annotsObj, yRef, countRef, 0, refPage->num, rootNum + 2); - annotsObj.free(); } yRef->markUnencrypted(); writePageObjects(outStr, yRef, 0); @@ -864,14 +833,11 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) strcmp(key, "Pages") != 0) { if (j > 0) outStr->printf(" "); - Object value; catDict->getValNF(j, &value); + Object value = catDict->getValNF(j); outStr->printf("/%s ", key); writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0); - value.free(); } } - catObj.free(); - pagesObj.free(); outStr->printf(">>\nendobj\n"); yRef->add(rootNum + 1,0,outStr->getPos(),gTrue); @@ -880,7 +846,6 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) if (resourcesObj.isDict()) { outStr->printf("/Resources "); writeObject(&resourcesObj, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0); - resourcesObj.free(); } outStr->printf(">>\n"); outStr->printf("endobj\n"); @@ -891,27 +856,24 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) for (int n = 0; n < pageDict->getLength(); n++) { if (n > 0) outStr->printf(" "); const char *key = pageDict->getKey(n); - Object value; pageDict->getValNF(n, &value); + Object value = pageDict->getValNF(n); if (strcmp(key, "Parent") == 0) { outStr->printf("/Parent %d 0 R", rootNum + 1); } else { outStr->printf("/%s ", key); writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0); } - value.free(); } outStr->printf(" >>\nendobj\n"); - page.free(); Goffset uxrefOffset = outStr->getPos(); Ref ref; ref.num = rootNum; ref.gen = 0; - Dict *trailerDict = createTrailerDict(rootNum + 3, gFalse, 0, &ref, getXRef(), + Object trailerDict = createTrailerDict(rootNum + 3, gFalse, 0, &ref, getXRef(), name->getCString(), uxrefOffset); - writeXRefTableTrailer(trailerDict, yRef, gFalse /* do not write unnecessary entries */, + writeXRefTableTrailer(std::move(trailerDict), yRef, gFalse /* do not write unnecessary entries */, uxrefOffset, outStr, getXRef()); - delete trailerDict; outStr->close(); fclose(f); @@ -1015,13 +977,11 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) ref.num = i; ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen; if (xref->getEntry(i)->type != xrefEntryFree) { - Object obj1; - xref->fetch(ref.num, ref.gen, &obj1, 1); + Object obj1 = xref->fetch(ref.num, ref.gen, 1); Goffset offset = writeObjectHeader(&ref, outStr); writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); writeObjectFooter(outStr); uxref->add(ref.num, ref.gen, offset, gTrue); - obj1.free(); } else { uxref->add(ref.num, ref.gen, 0, gFalse); } @@ -1052,14 +1012,13 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) uxref->add(uxrefStreamRef.num, uxrefStreamRef.gen, uxrefOffset, gTrue); } - Dict *trailerDict = createTrailerDict(numobjects, gTrue, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset); + Object trailerDict = createTrailerDict(numobjects, gTrue, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset); if (xRefStream) { - writeXRefStreamTrailer(trailerDict, uxref, &uxrefStreamRef, uxrefOffset, outStr, getXRef()); + writeXRefStreamTrailer(std::move(trailerDict), uxref, &uxrefStreamRef, uxrefOffset, outStr, getXRef()); } else { - writeXRefTableTrailer(trailerDict, uxref, gFalse, uxrefOffset, outStr, getXRef()); + writeXRefTableTrailer(std::move(trailerDict), uxref, gFalse, uxrefOffset, outStr, getXRef()); } - delete trailerDict; delete uxref; } @@ -1079,7 +1038,6 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) uxref->add(0, 65535, 0, gFalse); xref->lock(); for(int i=0; i<xref->getNumObjects(); i++) { - Object obj1; Ref ref; XRefEntryType type = xref->getEntry(i)->type; if (type == xrefEntryFree) { @@ -1097,7 +1055,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) } else if (type == xrefEntryUncompressed){ ref.num = i; ref.gen = xref->getEntry(i)->gen; - xref->fetch(ref.num, ref.gen, &obj1, 1); + Object obj1 = xref->fetch(ref.num, ref.gen, 1); Goffset offset = writeObjectHeader(&ref, outStr); // Write unencrypted objects in unencrypted form if (xref->getEntry(i)->getFlag(XRefEntry::Unencrypted)) { @@ -1107,16 +1065,14 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) } writeObjectFooter(outStr); uxref->add(ref.num, ref.gen, offset, gTrue); - obj1.free(); } else if (type == xrefEntryCompressed) { ref.num = i; ref.gen = 0; //compressed entries have gen == 0 - xref->fetch(ref.num, ref.gen, &obj1, 1); + Object obj1 = xref->fetch(ref.num, ref.gen, 1); Goffset offset = writeObjectHeader(&ref, outStr); writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); writeObjectFooter(outStr); uxref->add(ref.num, ref.gen, offset, gTrue); - obj1.free(); } } xref->unlock(); @@ -1127,19 +1083,36 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) } void PDFDoc::writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey, - CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen) + CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, std::set<Dict*> *alreadyWrittenDicts) { - Object obj1; + bool deleteSet = false; + if (!alreadyWrittenDicts) { + alreadyWrittenDicts = new std::set<Dict*>; + deleteSet = true; + } + + if (alreadyWrittenDicts->find(dict) != alreadyWrittenDicts->end()) { + error(errSyntaxWarning, -1, "PDFDoc::writeDictionnary: Found recursive dicts"); + if (deleteSet) delete alreadyWrittenDicts; + return; + } else { + alreadyWrittenDicts->insert(dict); + } + outStr->printf("<<"); for (int i=0; i<dict->getLength(); i++) { GooString keyName(dict->getKey(i)); GooString *keyNameToPrint = keyName.sanitizedName(gFalse /* non ps mode */); outStr->printf("/%s ", keyNameToPrint->getCString()); delete keyNameToPrint; - writeObject(dict->getValNF(i, &obj1), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen); - obj1.free(); + Object obj1 = dict->getValNF(i); + writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); } outStr->printf(">> "); + + if (deleteSet) { + delete alreadyWrittenDicts; + } } void PDFDoc::writeStream (Stream* str, OutStream* outStr) @@ -1154,8 +1127,7 @@ void PDFDoc::writeStream (Stream* str, OutStream* outStr) void PDFDoc::writeRawStream (Stream* str, OutStream* outStr) { - Object obj1; - str->getDict()->lookup("Length", &obj1); + Object obj1 = str->getDict()->lookup("Length"); if (!obj1.isInt() && !obj1.isInt64()) { error (errSyntaxError, -1, "PDFDoc::writeRawStream, no Length in stream dict"); return; @@ -1166,7 +1138,6 @@ void PDFDoc::writeRawStream (Stream* str, OutStream* outStr) length = obj1.getInt(); else length = obj1.getInt64(); - obj1.free(); outStr->printf("stream\r\n"); str->unfilteredReset(); @@ -1188,8 +1159,7 @@ void PDFDoc::writeString (GooString* s, OutStream* outStr, Guchar *fileKey, // Encrypt string if encryption is enabled GooString *sEnc = NULL; if (fileKey) { - Object obj; - EncryptStream *enc = new EncryptStream(new MemStream(s->getCString(), 0, s->getLength(), obj.initNull()), + EncryptStream *enc = new EncryptStream(new MemStream(s->getCString(), 0, s->getLength(), Object(objNull)), fileKey, encAlgorithm, keyLength, objNum, objGen); sEnc = new GooString(); int c; @@ -1246,11 +1216,9 @@ Goffset PDFDoc::writeObjectHeader (Ref *ref, OutStream* outStr) } void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey, - CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen) + CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, std::set<Dict*> *alreadyWrittenDicts) { Array *array; - Object obj1; - Goffset tmp; switch (obj->getType()) { case objBool: @@ -1287,13 +1255,13 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO array = obj->getArray(); outStr->printf("["); for (int i=0; i<array->getLength(); i++) { - writeObject(array->getNF(i, &obj1), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen); - obj1.free(); + Object obj1 = array->getNF(i); + writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen); } outStr->printf("] "); break; case objDict: - writeDictionnary (obj->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen); + writeDictionnary (obj->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); break; case objStream: { @@ -1307,19 +1275,15 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO EncryptStream *encStream = NULL; GBool removeFilter = gTrue; if (stream->getKind() == strWeird && fileKey) { - Object filter; - stream->getDict()->lookup("Filter", &filter); + Object filter = stream->getDict()->lookup("Filter"); if (!filter.isName("Crypt")) { if (filter.isArray()) { for (int i = 0; i < filter.arrayGetLength(); i++) { - Object filterEle; - filter.arrayGet(i, &filterEle); + Object filterEle = filter.arrayGet(i); if (filterEle.isName("Crypt")) { - filterEle.free(); removeFilter = gFalse; break; } - filterEle.free(); } if (removeFilter) { encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen); @@ -1334,7 +1298,6 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO } else { removeFilter = gFalse; } - filter.free(); } else if (fileKey != NULL) { // Encrypt stream encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen); encStream->setAutoDelete(gFalse); @@ -1343,12 +1306,11 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO stream->reset(); //recalculate stream length - tmp = 0; + Goffset tmp = 0; for (int c=stream->getChar(); c!=EOF; c=stream->getChar()) { tmp++; } - obj1.initInt64(tmp); - stream->getDict()->set("Length", &obj1); + stream->getDict()->set("Length", Object(tmp)); //Remove Stream encoding if (removeFilter) { @@ -1356,10 +1318,9 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO } stream->getDict()->remove("DecodeParms"); - writeDictionnary (stream->getDict(),outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen); + writeDictionnary (stream->getDict(),outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); writeStream (stream,outStr); delete encStream; - obj1.free(); } else { //raw stream copy FilterStream *fs = dynamic_cast<FilterStream*>(stream); @@ -1368,13 +1329,12 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO if (bs) { Goffset streamEnd; if (xRef->getStreamEnd(bs->getStart(), &streamEnd)) { - Object val; - val.initInt64(streamEnd - bs->getStart()); - stream->getDict()->set("Length", &val); + Goffset val = streamEnd - bs->getStart(); + stream->getDict()->set("Length", Object(val)); } } } - writeDictionnary (stream->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen); + writeDictionnary (stream->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); writeRawStream (stream, outStr); } break; @@ -1405,14 +1365,11 @@ void PDFDoc::writeObjectFooter (OutStream* outStr) outStr->printf("endobj\r\n"); } -Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxRef, +Object PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxRef, Ref *root, XRef *xRef, const char *fileName, Goffset fileSize) { Dict *trailerDict = new Dict(xRef); - Object obj1; - obj1.initInt(uxrefSize); - trailerDict->set("Size", &obj1); - obj1.free(); + trailerDict->set("Size", Object(uxrefSize)); //build a new ID, as recommended in the reference, uses: // - current time @@ -1431,105 +1388,92 @@ Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxR message.append(buffer); //info dict -- only use text string - if (!xRef->getTrailerDict()->isNone() && xRef->getDocInfo(&obj1)->isDict()) { - for(int i=0; i<obj1.getDict()->getLength(); i++) { - Object obj2; - obj1.getDict()->getVal(i, &obj2); - if (obj2.isString()) { - message.append(obj2.getString()); + if (!xRef->getTrailerDict()->isNone()) { + Object docInfo = xRef->getDocInfo(); + if (docInfo.isDict()) { + for(int i=0; i<docInfo.getDict()->getLength(); i++) { + Object obj2 = docInfo.getDict()->getVal(i); + if (obj2.isString()) { + message.append(obj2.getString()); + } } - obj2.free(); } } - obj1.free(); GBool hasEncrypt = gFalse; if (!xRef->getTrailerDict()->isNone()) { - Object obj2; - xRef->getTrailerDict()->dictLookupNF("Encrypt", &obj2); + Object obj2 = xRef->getTrailerDict()->dictLookupNF("Encrypt"); if (!obj2.isNull()) { - trailerDict->set("Encrypt", &obj2); + trailerDict->set("Encrypt", std::move(obj2)); hasEncrypt = gTrue; - obj2.free(); } } //calculate md5 digest Guchar digest[16]; md5((Guchar*)message.getCString(), message.getLength(), digest); - obj1.initString(new GooString((const char*)digest, 16)); //create ID array - Object obj2,obj3,obj5; - obj2.initArray(xRef); - // In case of encrypted files, the ID must not be changed because it's used to calculate the key if (incrUpdate || hasEncrypt) { - Object obj4; //only update the second part of the array - xRef->getTrailerDict()->getDict()->lookup("ID", &obj4); + Object obj4 = xRef->getTrailerDict()->getDict()->lookup("ID"); if (!obj4.isArray()) { error(errSyntaxWarning, -1, "PDFDoc::createTrailerDict original file's ID entry isn't an array. Trying to continue"); } else { + Array *array = new Array(xRef); //Get the first part of the ID - obj4.arrayGet(0,&obj3); - - obj2.arrayAdd(&obj3); - obj2.arrayAdd(&obj1); - trailerDict->set("ID", &obj2); + array->add(obj4.arrayGet(0)); + array->add(Object(new GooString((const char*)digest, 16))); + trailerDict->set("ID", Object(array)); } - obj4.free(); } else { //new file => same values for the two identifiers - obj2.arrayAdd(&obj1); - obj1.initString(new GooString((const char*)digest, 16)); - obj2.arrayAdd(&obj1); - trailerDict->set("ID", &obj2); + Array *array = new Array(xRef); + array->add(Object(new GooString((const char*)digest, 16))); + array->add(Object(new GooString((const char*)digest, 16))); + trailerDict->set("ID", Object(array)); } - obj1.initRef(root->num, root->gen); - trailerDict->set("Root", &obj1); + trailerDict->set("Root", Object(root->num, root->gen)); if (incrUpdate) { - obj1.initInt64(startxRef); - trailerDict->set("Prev", &obj1); + trailerDict->set("Prev", Object(startxRef)); } if (!xRef->getTrailerDict()->isNone()) { - xRef->getDocInfoNF(&obj5); + Object obj5 = xRef->getDocInfoNF(); if (!obj5.isNull()) { - trailerDict->set("Info", &obj5); + trailerDict->set("Info", std::move(obj5)); } } - return trailerDict; + return Object(trailerDict); } -void PDFDoc::writeXRefTableTrailer(Dict *trailerDict, XRef *uxref, GBool writeAllEntries, Goffset uxrefOffset, OutStream* outStr, XRef *xRef) +void PDFDoc::writeXRefTableTrailer(Object &&trailerDict, XRef *uxref, GBool writeAllEntries, Goffset uxrefOffset, OutStream* outStr, XRef *xRef) { uxref->writeTableToFile( outStr, writeAllEntries ); outStr->printf( "trailer\r\n"); - writeDictionnary(trailerDict, outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0); + writeDictionnary(trailerDict.getDict(), outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0, nullptr); outStr->printf( "\r\nstartxref\r\n"); outStr->printf( "%lli\r\n", uxrefOffset); outStr->printf( "%%%%EOF\r\n"); } -void PDFDoc::writeXRefStreamTrailer (Dict *trailerDict, XRef *uxref, Ref *uxrefStreamRef, Goffset uxrefOffset, OutStream* outStr, XRef *xRef) +void PDFDoc::writeXRefStreamTrailer (Object &&trailerDict, XRef *uxref, Ref *uxrefStreamRef, Goffset uxrefOffset, OutStream* outStr, XRef *xRef) { GooString stmData; // Fill stmData and some trailerDict fields - uxref->writeStreamToBuffer(&stmData, trailerDict, xRef); + uxref->writeStreamToBuffer(&stmData, trailerDict.getDict(), xRef); // Create XRef stream object and write it - Object obj1; - MemStream *mStream = new MemStream( stmData.getCString(), 0, - stmData.getLength(), obj1.initDict(trailerDict) ); + MemStream *mStream = new MemStream( stmData.getCString(), 0, stmData.getLength(), std::move(trailerDict) ); writeObjectHeader(uxrefStreamRef, outStr); - writeObject(obj1.initStream(mStream), outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0); + Object obj1(static_cast<Stream*>(mStream)); + writeObject(&obj1, outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0); writeObjectFooter(outStr); - obj1.free(); outStr->printf( "startxref\r\n"); outStr->printf( "%lli\r\n", uxrefOffset); @@ -1551,10 +1495,9 @@ void PDFDoc::writeXRefTableTrailer(Goffset uxrefOffset, XRef *uxref, GBool write Ref ref; ref.num = getXRef()->getRootNum(); ref.gen = getXRef()->getRootGen(); - Dict * trailerDict = createTrailerDict(uxrefSize, incrUpdate, getStartXRef(), &ref, + Object trailerDict = createTrailerDict(uxrefSize, incrUpdate, getStartXRef(), &ref, getXRef(), fileNameA, fileSize); - writeXRefTableTrailer(trailerDict, uxref, writeAllEntries, uxrefOffset, outStr, getXRef()); - delete trailerDict; + writeXRefTableTrailer(std::move(trailerDict), uxref, writeAllEntries, uxrefOffset, outStr, getXRef()); } void PDFDoc::writeHeader(OutStream *outStr, int major, int minor) @@ -1563,45 +1506,60 @@ void PDFDoc::writeHeader(OutStream *outStr, int major, int minor) outStr->printf("%%\xE2\xE3\xCF\xD3\n"); } -void PDFDoc::markDictionnary (Dict* dict, XRef * xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum) +void PDFDoc::markDictionnary (Dict* dict, XRef * xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts) { + bool deleteSet = false; + if (!alreadyMarkedDicts) { + alreadyMarkedDicts = new std::set<Dict*>; + deleteSet = true; + } + + if (alreadyMarkedDicts->find(dict) != alreadyMarkedDicts->end()) { + error(errSyntaxWarning, -1, "PDFDoc::markDictionnary: Found recursive dicts"); + if (deleteSet) delete alreadyMarkedDicts; + return; + } else { + alreadyMarkedDicts->insert(dict); + } + Object obj1; for (int i=0; i<dict->getLength(); i++) { const char *key = dict->getKey(i); if (strcmp(key, "Annots") != 0) { - markObject(dict->getValNF(i, &obj1), xRef, countRef, numOffset, oldRefNum, newRefNum); + Object obj1 = dict->getValNF(i); + markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); } else { - Object annotsObj; - dict->getValNF(i, &annotsObj); + Object annotsObj = dict->getValNF(i); if (!annotsObj.isNull()) { - markAnnotations(&annotsObj, xRef, countRef, 0, oldRefNum, newRefNum); - annotsObj.free(); + markAnnotations(&annotsObj, xRef, countRef, 0, oldRefNum, newRefNum, alreadyMarkedDicts); } } - obj1.free(); + } + + if (deleteSet) { + delete alreadyMarkedDicts; } } -void PDFDoc::markObject (Object* obj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum) +void PDFDoc::markObject (Object* obj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts) { Array *array; - Object obj1; switch (obj->getType()) { case objArray: array = obj->getArray(); for (int i=0; i<array->getLength(); i++) { - markObject(array->getNF(i, &obj1), xRef, countRef, numOffset, oldRefNum, newRefNum); - obj1.free(); + Object obj1 = array->getNF(i); + markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum); } break; case objDict: - markDictionnary (obj->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum); + markDictionnary (obj->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); break; case objStream: { Stream *stream = obj->getStream(); - markDictionnary (stream->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum); + markDictionnary (stream->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); } break; case objRef: @@ -1625,10 +1583,8 @@ void PDFDoc::markObject (Object* obj, XRef *xRef, XRef *countRef, Guint numOffse if (entry->gen > 9) break; } - Object obj1; - getXRef()->fetch(obj->getRef().num, obj->getRef().gen, &obj1); + Object obj1 = getXRef()->fetch(obj->getRef().num, obj->getRef().gen); markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum); - obj1.free(); } break; default: @@ -1641,8 +1597,7 @@ void PDFDoc::replacePageDict(int pageNo, int rotate, PDFRectangle *cropBox) { Ref *refPage = getCatalog()->getPageRef(pageNo); - Object page; - getXRef()->fetch(refPage->num, refPage->gen, &page); + Object page = getXRef()->fetch(refPage->num, refPage->gen); Dict *pageDict = page.getDict(); pageDict->remove("MediaBoxssdf"); pageDict->remove("MediaBox"); @@ -1651,51 +1606,30 @@ void PDFDoc::replacePageDict(int pageNo, int rotate, pageDict->remove("BleedBox"); pageDict->remove("TrimBox"); pageDict->remove("Rotate"); - Object mediaBoxObj; - mediaBoxObj.initArray(getXRef()); - Object murx; - murx.initReal(mediaBox->x1); - Object mury; - mury.initReal(mediaBox->y1); - Object mllx; - mllx.initReal(mediaBox->x2); - Object mlly; - mlly.initReal(mediaBox->y2); - mediaBoxObj.arrayAdd(&murx); - mediaBoxObj.arrayAdd(&mury); - mediaBoxObj.arrayAdd(&mllx); - mediaBoxObj.arrayAdd(&mlly); - pageDict->add(copyString("MediaBox"), &mediaBoxObj); + Array *mediaBoxArray = new Array(getXRef()); + mediaBoxArray->add(Object(mediaBox->x1)); + mediaBoxArray->add(Object(mediaBox->y1)); + mediaBoxArray->add(Object(mediaBox->x2)); + mediaBoxArray->add(Object(mediaBox->y2)); + Object mediaBoxObject(mediaBoxArray); + Object trimBoxObject = mediaBoxObject.copy(); + pageDict->add(copyString("MediaBox"), std::move(mediaBoxObject)); if (cropBox != NULL) { - Object cropBoxObj; - cropBoxObj.initArray(getXRef()); - Object curx; - curx.initReal(cropBox->x1); - Object cury; - cury.initReal(cropBox->y1); - Object cllx; - cllx.initReal(cropBox->x2); - Object clly; - clly.initReal(cropBox->y2); - cropBoxObj.arrayAdd(&curx); - cropBoxObj.arrayAdd(&cury); - cropBoxObj.arrayAdd(&cllx); - cropBoxObj.arrayAdd(&clly); - pageDict->add(copyString("CropBox"), &cropBoxObj); - cropBoxObj.getArray()->incRef(); - pageDict->add(copyString("TrimBox"), &cropBoxObj); - } else { - mediaBoxObj.getArray()->incRef(); - pageDict->add(copyString("TrimBox"), &mediaBoxObj); - } - Object rotateObj; - rotateObj.initInt(rotate); - pageDict->add(copyString("Rotate"), &rotateObj); + Array *cropBoxArray = new Array(getXRef()); + cropBoxArray->add(Object(cropBox->x1)); + cropBoxArray->add(Object(cropBox->y1)); + cropBoxArray->add(Object(cropBox->x2)); + cropBoxArray->add(Object(cropBox->y2)); + Object cropBoxObject(cropBoxArray); + trimBoxObject = cropBoxObject.copy(); + pageDict->add(copyString("CropBox"), std::move(cropBoxObject)); + } + pageDict->add(copyString("TrimBox"), std::move(trimBoxObject)); + pageDict->add(copyString("Rotate"), Object(rotate)); getXRef()->setModifiedObject(&page, *refPage); - page.free(); } -void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum) +void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts) { pageDict->remove("OpenAction"); pageDict->remove("Outlines"); @@ -1703,82 +1637,57 @@ void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint n for (int n = 0; n < pageDict->getLength(); n++) { const char *key = pageDict->getKey(n); - Object value; pageDict->getValNF(n, &value); + Object value = pageDict->getValNF(n); if (strcmp(key, "Parent") != 0 && strcmp(key, "Pages") != 0 && strcmp(key, "AcroForm") != 0 && strcmp(key, "Annots") != 0 && strcmp(key, "P") != 0 && strcmp(key, "Root") != 0) { - markObject(&value, xRef, countRef, numOffset, oldRefNum, newRefNum); + markObject(&value, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); } - value.free(); } } -GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldPageNum, int newPageNum) { - Object annots; +GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldPageNum, int newPageNum, std::set<Dict*> *alreadyMarkedDicts) { GBool modified = gFalse; - annotsObj->fetch(getXRef(), &annots); + Object annots = annotsObj->fetch(getXRef()); if (annots.isArray()) { Array *array = annots.getArray(); for (int i=array->getLength() - 1; i >= 0; i--) { - Object obj1; - if (array->get(i, &obj1)->isDict()) { - Object type; + Object obj1 = array->get(i); + if (obj1.isDict()) { Dict *dict = obj1.getDict(); - dict->lookup("Type", &type); + Object type = dict->lookup("Type"); if (type.isName() && strcmp(type.getName(), "Annot") == 0) { - Object obj2; - if (dict->lookupNF("P", &obj2)->isRef()) { + Object obj2 = dict->lookupNF("P"); + if (obj2.isRef()) { if (obj2.getRef().num == oldPageNum) { - Object obj3; - array->getNF(i, &obj3); + Object obj3 = array->getNF(i); if (obj3.isRef()) { - Object newRef; - newRef.initRef(newPageNum, 0); - dict->set("P", &newRef); + dict->set("P", Object(newPageNum, 0)); getXRef()->setModifiedObject(&obj1, obj3.getRef()); } - obj3.free(); } else if (obj2.getRef().num == newPageNum) { - obj1.free(); - obj2.free(); - type.free(); continue; } else { - Object page; - getXRef()->fetch(obj2.getRef().num, obj2.getRef().gen, &page); + Object page = getXRef()->fetch(obj2.getRef().num, obj2.getRef().gen); if (page.isDict()) { - Object pagetype; Dict *dict = page.getDict(); - dict->lookup("Type", &pagetype); + Object pagetype = dict->lookup("Type"); if (!pagetype.isName() || strcmp(pagetype.getName(), "Page") != 0) { - obj1.free(); - obj2.free(); - type.free(); - page.free(); - pagetype.free(); continue; } - pagetype.free(); } - page.free(); - obj1.free(); - obj2.free(); - type.free(); array->remove(i); modified = gTrue; continue; } } - obj2.free(); } - type.free(); - markPageObjects(dict, xRef, countRef, numOffset, oldPageNum, newPageNum); + markPageObjects(dict, xRef, countRef, numOffset, oldPageNum, newPageNum, alreadyMarkedDicts); } - obj1.free(); - array->getNF(i, &obj1); + obj1 = array->getNF(i); if (obj1.isRef()) { if (obj1.getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree) { if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryFree) { @@ -1798,7 +1707,6 @@ GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Gui entry->gen++; } } - obj1.free(); } } if (annotsObj->isRef()) { @@ -1821,25 +1729,21 @@ GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Gui } getXRef()->setModifiedObject(&annots, annotsObj->getRef()); } - annots.free(); return modified; } void PDFDoc::markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum) { - Object acroform; GBool modified = gFalse; - afObj->fetch(getXRef(), &acroform); + Object acroform = afObj->fetch(getXRef()); if (acroform.isDict()) { Dict *dict = acroform.getDict(); for (int i=0; i < dict->getLength(); i++) { if (strcmp(dict->getKey(i), "Fields") == 0) { - Object fields; - modified = markAnnotations(dict->getValNF(i, &fields), xRef, countRef, numOffset, oldRefNum, newRefNum); - fields.free(); + Object fields = dict->getValNF(i); + modified = markAnnotations(&fields, xRef, countRef, numOffset, oldRefNum, newRefNum); } else { - Object obj; - markObject(dict->getValNF(i, &obj), xRef, countRef, numOffset, oldRefNum, newRefNum); - obj.free(); + Object obj = dict->getValNF(i); + markObject(&obj, xRef, countRef, numOffset, oldRefNum, newRefNum); } } } @@ -1865,7 +1769,6 @@ void PDFDoc::markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, Guint numOf getXRef()->setModifiedObject(&acroform, afObj->getRef()); } } - acroform.free(); return; } @@ -1879,12 +1782,11 @@ Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, G for (int n = numOffset; n < xRef->getNumObjects(); n++) { if (xRef->getEntry(n)->type != xrefEntryFree) { - Object obj; Ref ref; ref.num = n; ref.gen = xRef->getEntry(n)->gen; objectsCount++; - getXRef()->fetch(ref.num - numOffset, ref.gen, &obj); + Object obj = getXRef()->fetch(ref.num - numOffset, ref.gen); Goffset offset = writeObjectHeader(&ref, outStr); if (combine) { writeObject(&obj, outStr, getXRef(), numOffset, NULL, cryptRC4, 0, 0, 0); @@ -1895,7 +1797,6 @@ Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, G } writeObjectFooter(outStr); xRef->add(ref.num, ref.gen, offset, gTrue); - obj.free(); } } return objectsCount; @@ -2032,10 +1933,7 @@ int PDFDoc::getNumPages() Page *PDFDoc::parsePage(int page) { - Page *p = NULL; - Object obj; Ref pageRef; - Dict *pageDict; pageRef.num = getHints()->getPageObjectNum(page); if (!pageRef.num) { @@ -2050,19 +1948,15 @@ Page *PDFDoc::parsePage(int page) } pageRef.gen = xref->getEntry(pageRef.num)->gen; - xref->fetch(pageRef.num, pageRef.gen, &obj); + Object obj = xref->fetch(pageRef.num, pageRef.gen); if (!obj.isDict("Page")) { - obj.free(); error(errSyntaxWarning, -1, "Object ({0:d} {1:d}) is not a pageDict", pageRef.num, pageRef.gen); return NULL; } - pageDict = obj.getDict(); + Dict *pageDict = obj.getDict(); - p = new Page(this, page, pageDict, pageRef, + return new Page(this, page, &obj, pageRef, new PageAttrs(NULL, pageDict), catalog->getForm()); - obj.free(); - - return p; } Page *PDFDoc::getPage(int page) |