diff --git a/glib/poppler-input-stream.cc b/glib/poppler-input-stream.cc index 99fcb6f..4ac3149 100644 --- a/glib/poppler-input-stream.cc +++ b/glib/poppler-input-stream.cc @@ -41,6 +41,10 @@ PopplerInputStream::~PopplerInputStream() g_object_unref(cancellable); } +BaseStream *PopplerInputStream::copy() { + return new PopplerInputStream(inputStream, cancellable, start, limited, length, &dict); +} + Stream *PopplerInputStream::makeSubStream(Guint startA, GBool limitedA, Guint lengthA, Object *dictA) { diff --git a/glib/poppler-input-stream.h b/glib/poppler-input-stream.h index 0d795f4..639ea04 100644 --- a/glib/poppler-input-stream.h +++ b/glib/poppler-input-stream.h @@ -33,6 +33,7 @@ public: PopplerInputStream(GInputStream *inputStream, GCancellable *cancellableA, Guint startA, GBool limitedA, Guint lengthA, Object *dictA); virtual ~PopplerInputStream(); + virtual BaseStream *copy(); virtual Stream *makeSubStream(Guint start, GBool limited, Guint lengthA, Object *dictA); virtual StreamKind getKind() { return strWeird; } diff --git a/poppler/Annot.cc b/poppler/Annot.cc index e55ddde..3965734 100644 --- a/poppler/Annot.cc +++ b/poppler/Annot.cc @@ -6526,7 +6526,8 @@ Annot *Annots::createAnnot(Dict* dict, Object *obj) { FormWidget *widget = form->findWidgetByRef(obj->getRef()); if (widget) { annot = widget->getWidgetAnnotation(); - annot->incRefCnt(); + if (annot) + annot->incRefCnt(); } } } diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc index c4493e8..2dd241a 100644 --- a/poppler/CairoFontEngine.cc +++ b/poppler/CairoFontEngine.cc @@ -645,7 +645,7 @@ _render_type3_glyph (cairo_scaled_font_t *scaled_font, box.y2 = mat[3]; gfx = new Gfx(info->doc, output_dev, resDict, &box, NULL); output_dev->startDoc(info->doc, info->fontEngine); - output_dev->startPage (1, gfx->getState()); + output_dev->startPage (1, gfx->getState(), gfx->getXRef()); output_dev->setInType3Char(gTrue); gfx->display(charProcs->getVal(glyph, &charProc)); diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index b70183e..751b08c 100644 --- a/poppler/CairoOutputDev.cc +++ b/poppler/CairoOutputDev.cc @@ -236,7 +236,7 @@ void CairoOutputDev::startDoc(PDFDoc *docA, } } -void CairoOutputDev::startPage(int pageNum, GfxState *state) { +void CairoOutputDev::startPage(int pageNum, GfxState *state, XRef *xref) { /* set up some per page defaults */ cairo_pattern_destroy(fill_pattern); cairo_pattern_destroy(stroke_pattern); diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h index df76975..548fab5 100644 --- a/poppler/CairoOutputDev.h +++ b/poppler/CairoOutputDev.h @@ -124,7 +124,7 @@ public: //----- initialization and control // Start a page. - virtual void startPage(int pageNum, GfxState *state); + virtual void startPage(int pageNum, GfxState *state, XRef *xref); // End a page. virtual void endPage(); diff --git a/poppler/Catalog.cc b/poppler/Catalog.cc index 664c421..dd95645 100644 --- a/poppler/Catalog.cc +++ b/poppler/Catalog.cc @@ -54,6 +54,13 @@ #include "ViewerPreferences.h" #include "FileSpec.h" +#if MULTITHREADED +# define lockCatalog gLockMutex(&mutex) +# define unlockCatalog gUnlockMutex(&mutex) +#else +# define lockCatalog +# define unlockCatalog +#endif //------------------------------------------------------------------------ // Catalog //------------------------------------------------------------------------ @@ -63,6 +70,9 @@ Catalog::Catalog(PDFDoc *docA) { Object obj, obj2; Object optContentProps; +#if MULTITHREADED + gInitMutex(&mutex); +#endif ok = gTrue; doc = docA; xref = doc->getXRef(); @@ -866,9 +876,11 @@ Form *Catalog::getForm() { if (!form) { if (acroForm.isDict()) { + lockCatalog; form = new Form(doc, &acroForm); // perform form-related loading after all widgets have been loaded form->postWidgetsLoad(); + unlockCatalog; } } diff --git a/poppler/Catalog.h b/poppler/Catalog.h index cdb1f13..89435d0 100644 --- a/poppler/Catalog.h +++ b/poppler/Catalog.h @@ -34,6 +34,7 @@ #endif #include "Object.h" +#include "goo/GooMutex.h" #include @@ -223,6 +224,9 @@ private: NameTree *getDestNameTree(); NameTree *getEmbeddedFileNameTree(); NameTree *getJSNameTree(); +#if MULTITHREADED + GooMutex mutex; +#endif }; diff --git a/poppler/Dict.cc b/poppler/Dict.cc index c4f667b..f76fee1 100644 --- a/poppler/Dict.cc +++ b/poppler/Dict.cc @@ -89,6 +89,22 @@ Dict::Dict(Dict* dictA) { } } +Dict *Dict::copy(XRef *xrefA) { + Dict *dictA = new Dict(this); + dictA->xref = xrefA; + for (int i=0; ientries[i].val.getType() == objDict) { + Dict *dict = dictA->entries[i].val.getDict(); + dict->decRef(); + Object obj; + obj.initDict(dict->copy(xrefA)); + dictA->entries[i].val = *obj.copy(&obj); + obj.free(); + } + } + return dictA; +} + Dict::~Dict() { int i; diff --git a/poppler/Dict.h b/poppler/Dict.h index 897f221..e2a11be 100644 --- a/poppler/Dict.h +++ b/poppler/Dict.h @@ -48,6 +48,7 @@ public: // Constructor. Dict(XRef *xrefA); Dict(Dict* dictA); + Dict *copy(XRef *xrefA); // Destructor. ~Dict(); diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index d7684d6..4fb6cc1 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -321,14 +321,15 @@ static inline GBool isSameGfxColor(const GfxColor &colorA, const GfxColor &color // GfxResources //------------------------------------------------------------------------ -GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) : +GfxResources::GfxResources(XRef *xref, Dict *resDictA, GfxResources *nextA) : gStateCache(2, xref) { Object obj1, obj2; Ref r; - if (resDict) { + if (resDictA) { // build font dictionary + resDict = resDictA->copy(xref); fonts = NULL; resDict->lookupNF("Font", &obj1); if (obj1.isRef()) { @@ -363,6 +364,7 @@ GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) : } else { fonts = NULL; + resDict = NULL; xObjDict.initNull(); colorSpaceDict.initNull(); patternDict.initNull(); @@ -384,6 +386,7 @@ GfxResources::~GfxResources() { shadingDict.free(); gStateDict.free(); propertiesDict.free(); + delete resDict; } GfxFont *GfxResources::lookupFont(char *name) { @@ -533,7 +536,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, double hDPI, double vDPI, PDFRectangle *box, PDFRectangle *cropBox, int rotate, GBool (*abortCheckCbkA)(void *data), - void *abortCheckCbkDataA) + void *abortCheckCbkDataA, GBool fCopy) #ifdef USE_CMS : iccColorSpaceCache(5) #endif @@ -541,7 +544,8 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, int i; doc = docA; - xref = doc->getXRef(); + xref = (fCopy) ? doc->getXRef()->copy() : doc->getXRef(); + xrefOwner = fCopy; catalog = doc->getCatalog(); subPage = gFalse; printCommands = globalParams->getPrintCommands(); @@ -560,7 +564,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, fontChanged = gFalse; clip = clipNone; ignoreUndef = 0; - out->startPage(pageNum, state); + out->startPage(pageNum, state, xref); out->setDefaultCTM(state->getCTM()); out->updateAll(state); for (i = 0; i < 6; ++i) { @@ -604,6 +608,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, profileCommands = globalParams->getProfileCommands(); mcStack = NULL; parser = NULL; + xrefOwner = gFalse; // start the resource stack res = new GfxResources(xref, resDict, NULL); @@ -658,6 +663,8 @@ Gfx::~Gfx() { while (mcStack) { popMarkedContent(); } + if (xrefOwner) + delete xref; } void Gfx::display(Object *obj, GBool topLevel) { diff --git a/poppler/Gfx.h b/poppler/Gfx.h index 37022e0..d722486 100644 --- a/poppler/Gfx.h +++ b/poppler/Gfx.h @@ -134,6 +134,7 @@ private: PopplerObjectCache gStateCache; Object propertiesDict; GfxResources *next; + Dict *resDict; }; //------------------------------------------------------------------------ @@ -148,7 +149,7 @@ public: double hDPI, double vDPI, PDFRectangle *box, PDFRectangle *cropBox, int rotate, GBool (*abortCheckCbkA)(void *data) = NULL, - void *abortCheckCbkDataA = NULL); + void *abortCheckCbkDataA = NULL, GBool fCopy = gFalse); // Constructor for a sub-page object. Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, @@ -158,6 +159,8 @@ public: ~Gfx(); + XRef *getXRef() { return xref; } + // Interpret a stream or array of streams. void display(Object *obj, GBool topLevel = gTrue); @@ -228,6 +231,7 @@ private: MarkedContentStack *mcStack; // current BMC/EMC stack Parser *parser; // parser for page content stream(s) + GBool xrefOwner; // true if xref is owned by the instance #ifdef USE_CMS PopplerCache iccColorSpaceCache; diff --git a/poppler/GlobalParamsWin.cc b/poppler/GlobalParamsWin.cc index 527f08e..20d83ab 100644 --- a/poppler/GlobalParamsWin.cc +++ b/poppler/GlobalParamsWin.cc @@ -470,7 +470,7 @@ void GlobalParams::setupBaseFonts(char * dir) obj1.initNull(); parser = new Parser(NULL, new Lexer(NULL, - new FileStream(file, 0, gFalse, size, &obj1)), + new FileStream(file, fileName->getCString(), 0, gFalse, size, &obj1)), gTrue); obj1.free(); parser->getObj(&obj1); diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h index 15af90a..9144418 100644 --- a/poppler/OutputDev.h +++ b/poppler/OutputDev.h @@ -132,7 +132,7 @@ public: { return gTrue; } // Start a page. - virtual void startPage(int pageNum, GfxState *state) {} + virtual void startPage(int pageNum, GfxState *state, XRef *xref) {} // End a page. virtual void endPage() {} diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index ce01ca3..06aa572 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -75,6 +75,14 @@ #include "PDFDoc.h" #include "Hints.h" +#if MULTITHREADED +# define lockPDFDoc gLockMutex(&mutex) +# define unlockPDFDoc gUnlockMutex(&mutex) +#else +# define lockPDFDoc +# define unlockPDFDoc +#endif + //------------------------------------------------------------------------ #define headerSearchSize 1024 // read this many bytes at beginning of @@ -94,6 +102,9 @@ void PDFDoc::init() { +#if MULTITHREADED + gInitMutex(&mutex); +#endif ok = gFalse; errCode = errNone; fileName = NULL; @@ -160,7 +171,7 @@ PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword, // create stream obj.initNull(); - str = new FileStream(file, 0, gFalse, size, &obj); + str = new FileStream(file, fileName->getCString(), 0, gFalse, size, &obj); ok = setup(ownerPassword, userPassword); } @@ -211,7 +222,7 @@ PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, // create stream obj.initNull(); - str = new FileStream(file, 0, gFalse, size, &obj); + str = new FileStream(file, fileName->getCString(), 0, gFalse, size, &obj); ok = setup(ownerPassword, userPassword); } @@ -491,14 +502,14 @@ void PDFDoc::displayPageSlice(OutputDev *out, int page, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { + void *annotDisplayDecideCbkData, GBool fMT) { if (getPage(page)) getPage(page)->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); + annotDisplayDecideCbk, annotDisplayDecideCbkData, fMT); } Links *PDFDoc::getLinks(int page) { @@ -661,7 +672,7 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) infoObj.free(); // get and mark output intents etc. - Object catObj, pagesObj, resourcesObj; + Object catObj, pagesObj, resourcesObj; getXRef()->getCatalog(&catObj); Dict *catDict = catObj.getDict(); catDict->lookup("Pages", &pagesObj); @@ -701,7 +712,7 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) outStr->printf("<< /Type /Pages /Kids [ %d 0 R ] /Count 1 ", rootNum + 2); if (resourcesObj.isDict()) { outStr->printf("/Resources "); - writeObject(&resourcesObj, NULL, outStr, getXRef(), 0); + writeObject(&resourcesObj, NULL, outStr, getXRef(), 0); resourcesObj.free(); } outStr->printf(">>\n"); @@ -1621,7 +1632,11 @@ Page *PDFDoc::parsePage(int page) Page *PDFDoc::getPage(int page) { - if ((page < 1) || page > getNumPages()) return NULL; + lockPDFDoc; + if ((page < 1) || page > getNumPages()) { + unlockPDFDoc; + return NULL; + } if (isLinearized()) { if (!pageCache) { @@ -1634,11 +1649,14 @@ Page *PDFDoc::getPage(int page) pageCache[page-1] = parsePage(page); } if (pageCache[page-1]) { + unlockPDFDoc; return pageCache[page-1]; } else { error(errSyntaxWarning, -1, "Failed parsing page {0:d} using hint tables", page); } } - return catalog->getPage(page); + Page *pageObj = catalog->getPage(page); + unlockPDFDoc; + return pageObj; } diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index 468f698..df96f6a 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -43,6 +43,7 @@ #include "Page.h" #include "Annot.h" #include "OptionalContent.h" +#include "goo/GooMutex.h" class GooString; class BaseStream; @@ -164,7 +165,7 @@ public: GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL, - void *annotDisplayDecideCbkData = NULL); + void *annotDisplayDecideCbkData = NULL, GBool fMT = gFalse); // Find a page, given its object ID. Returns page number, or 0 if // not found. @@ -317,6 +318,9 @@ private: int fopenErrno; Guint startXRefPos; // offset of last xref table +#if MULTITHREADED + GooMutex mutex; +#endif }; #endif diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc index f414897..f01cb15 100644 --- a/poppler/PSOutputDev.cc +++ b/poppler/PSOutputDev.cc @@ -3086,7 +3086,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, rotateA += 360; } state = new GfxState(dpi, dpi, &box, rotateA, gFalse); - startPage(page->getNum(), state); + startPage(page->getNum(), state, NULL); delete state; // set up the SplashOutputDev @@ -3472,7 +3472,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, #endif // HAVE_SPLASH } -void PSOutputDev::startPage(int pageNum, GfxState *state) { +void PSOutputDev::startPage(int pageNum, GfxState *state, XRef * /*xref*/) { Page *page; int x1, y1, x2, y2, width, height, t; int imgWidth, imgHeight, imgWidth2, imgHeight2; diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h index 809f058..7ee6b1d 100644 --- a/poppler/PSOutputDev.h +++ b/poppler/PSOutputDev.h @@ -85,7 +85,7 @@ enum PSOutCustomCodeLocation { typedef void (*PSOutputFunc)(void *stream, const char *data, int len); typedef GooString *(*PSOutCustomCodeCbk)(PSOutputDev *psOut, - PSOutCustomCodeLocation loc, int n, + PSOutCustomCodeLocation loc, int n, void *data); class PSOutputDev: public OutputDev { @@ -184,7 +184,7 @@ public: void *annotDisplayDecideCbkData = NULL); // Start a page. - virtual void startPage(int pageNum, GfxState *state); + virtual void startPage(int pageNum, GfxState *state, XRef *xref); // End a page. virtual void endPage(); @@ -417,7 +417,7 @@ private: void (*overlayCbk)(PSOutputDev *psOut, void *data); void *overlayCbkData; GooString *(*customCodeCbk)(PSOutputDev *psOut, - PSOutCustomCodeLocation loc, int n, + PSOutCustomCodeLocation loc, int n, void *data); void *customCodeCbkData; diff --git a/poppler/Page.cc b/poppler/Page.cc index 87bc3a4..48c7c2a 100644 --- a/poppler/Page.cc +++ b/poppler/Page.cc @@ -57,6 +57,13 @@ #include "Catalog.h" #include "Form.h" +#if MULTITHREADED +# define lockPage gLockMutex(&mutex) +# define unlockPage gUnlockMutex(&mutex) +#else +# define lockPage +# define unlockPage +#endif //------------------------------------------------------------------------ // PDFRectangle //------------------------------------------------------------------------ @@ -257,6 +264,9 @@ GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) { Page::Page(PDFDoc *docA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form) { Object tmp; +#if MULTITHREADED + gInitMutex(&mutex); +#endif ok = gTrue; doc = docA; xref = doc->getXRef(); @@ -347,9 +357,11 @@ Page::~Page() { Annots *Page::getAnnots() { if (!annots) { + lockPage; Object obj; annots = new Annots(doc, num, getAnnots(&obj)); obj.free(); + unlockPage; } return annots; @@ -456,7 +468,7 @@ Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI, int sliceX, int sliceY, int sliceW, int sliceH, GBool printing, GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { + void *abortCheckCbkData, GBool fMT) { PDFRectangle *mediaBox, *cropBox; PDFRectangle box; Gfx *gfx; @@ -483,7 +495,7 @@ Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI, gfx = new Gfx(doc, out, num, attrs->getResourceDict(), hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL, - rotate, abortCheckCbk, abortCheckCbkData); + rotate, abortCheckCbk, abortCheckCbkData, fMT); return gfx; } @@ -495,7 +507,7 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { + void *annotDisplayDecideCbkData, GBool fMT) { Gfx *gfx; Object obj; Annots *annotList; @@ -512,9 +524,9 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, - abortCheckCbk, abortCheckCbkData); + abortCheckCbk, abortCheckCbkData, fMT); - contents.fetch(xref, &obj); + contents.fetch(gfx->getXRef(), &obj); if (!obj.isNull()) { gfx->saveState(); gfx->display(&obj); diff --git a/poppler/Page.h b/poppler/Page.h index 78cedc4..1342b3c 100644 --- a/poppler/Page.h +++ b/poppler/Page.h @@ -35,6 +35,7 @@ #endif #include "Object.h" +#include "goo/GooMutex.h" class Dict; class PDFDoc; @@ -208,7 +209,7 @@ public: int sliceX, int sliceY, int sliceW, int sliceH, GBool printing, GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData); + void *abortCheckCbkData, GBool fMT = gFalse); // Display a page. void display(OutputDev *out, double hDPI, double vDPI, @@ -227,7 +228,7 @@ public: GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL, - void *annotDisplayDecideCbkData = NULL); + void *annotDisplayDecideCbkData = NULL, GBool fMT = gFalse); void display(Gfx *gfx); @@ -258,6 +259,9 @@ private: Object actions; // page addiction actions double duration; // page duration GBool ok; // true if page is valid +#if MULTITHREADED + GooMutex mutex; +#endif }; #endif diff --git a/poppler/Parser.cc b/poppler/Parser.cc index 5b80293..11f6d4a 100644 --- a/poppler/Parser.cc +++ b/poppler/Parser.cc @@ -271,7 +271,7 @@ Stream *Parser::makeStream(Object *dict, Guchar *fileKey, } // get filters - str = str->addFilters(dict); + str = str->addFilters(dict, recursion); return str; } diff --git a/poppler/PreScanOutputDev.cc b/poppler/PreScanOutputDev.cc index 3a86d52..2512cc7 100644 --- a/poppler/PreScanOutputDev.cc +++ b/poppler/PreScanOutputDev.cc @@ -52,7 +52,7 @@ PreScanOutputDev::PreScanOutputDev(PDFDoc *docA) { PreScanOutputDev::~PreScanOutputDev() { } -void PreScanOutputDev::startPage(int /*pageNum*/, GfxState * /*state*/) { +void PreScanOutputDev::startPage(int /*pageNum*/, GfxState * /*state*/, XRef * /*xref*/) { } void PreScanOutputDev::endPage() { diff --git a/poppler/PreScanOutputDev.h b/poppler/PreScanOutputDev.h index 5260a3b..6b9b6b2 100644 --- a/poppler/PreScanOutputDev.h +++ b/poppler/PreScanOutputDev.h @@ -76,7 +76,7 @@ public: //----- initialization and control // Start a page. - virtual void startPage(int pageNum, GfxState *state); + virtual void startPage(int pageNum, GfxState *state, XRef *xref); // End a page. virtual void endPage(); diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index 9e07060..75c9053 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -1238,6 +1238,7 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, textClipPath = NULL; transpGroupStack = NULL; nestCount = 0; + xref = NULL; } void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) { @@ -1333,12 +1334,13 @@ void SplashOutputDev::startDoc(PDFDoc *docA) { nT3Fonts = 0; } -void SplashOutputDev::startPage(int pageNum, GfxState *state) { +void SplashOutputDev::startPage(int pageNum, GfxState *state, XRef *xrefA) { int w, h; double *ctm; SplashCoord mat[6]; SplashColor color; + xref = xrefA; if (state) { setupScreenParams(state->getHDPI(), state->getVDPI()); w = (int)(state->getPageWidth() + 0.5); @@ -1790,7 +1792,7 @@ void SplashOutputDev::doUpdateFont(GfxState *state) { } else { - if (!(fontLoc = gfxFont->locateFont(doc->getXRef(), gFalse))) { + if (!(fontLoc = gfxFont->locateFont((xref) ? xref : doc->getXRef(), gFalse))) { error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); @@ -1800,7 +1802,7 @@ void SplashOutputDev::doUpdateFont(GfxState *state) { // embedded font if (fontLoc->locType == gfxFontLocEmbedded) { // if there is an embedded font, read it to memory - tmpBuf = gfxFont->readEmbFontFile(doc->getXRef(), &tmpBufLen); + tmpBuf = gfxFont->readEmbFontFile((xref) ? xref : doc->getXRef(), &tmpBufLen); if (! tmpBuf) goto err2; @@ -3270,7 +3272,7 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, if (maskWidth > width || maskHeight > height) { decodeLow.initInt(maskInvert ? 0 : 1); decodeHigh.initInt(maskInvert ? 1 : 0); - maskDecode.initArray(doc->getXRef()); + maskDecode.initArray((xref) ? xref : doc->getXRef()); maskDecode.arrayAdd(&decodeLow); maskDecode.arrayAdd(&decodeHigh); maskColorMap = new GfxImageColorMap(1, &maskDecode, @@ -4094,7 +4096,6 @@ GBool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *ca splash->drawImage(&tilingBitmapSrc, &imgData, colorMode, gTrue, result_width, result_height, matc, gTrue); delete tBitmap; delete gfx; - return gTrue; } GBool SplashOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading) diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h index f1c87ec..085b7a0 100644 --- a/poppler/SplashOutputDev.h +++ b/poppler/SplashOutputDev.h @@ -195,7 +195,7 @@ public: //----- initialization and control // Start a page. - virtual void startPage(int pageNum, GfxState *state); + virtual void startPage(int pageNum, GfxState *state, XRef *xref); // End a page. virtual void endPage(); @@ -396,6 +396,7 @@ private: GBool skipRotatedText; PDFDoc *doc; // the current document + XRef *xref; // the xref of the current document SplashBitmap *bitmap; Splash *splash; diff --git a/poppler/Stream.cc b/poppler/Stream.cc index 4ce6c00..de6b060 100644 --- a/poppler/Stream.cc +++ b/poppler/Stream.cc @@ -38,6 +38,9 @@ #endif #include +#ifdef _WIN32 +#include +#endif #include #include #include @@ -137,25 +140,25 @@ GooString *Stream::getPSFilter(int psLevel, const char *indent) { return new GooString(); } -Stream *Stream::addFilters(Object *dict) { +Stream *Stream::addFilters(Object *dict, int recursion) { Object obj, obj2; Object params, params2; Stream *str; int i; str = this; - dict->dictLookup("Filter", &obj); + dict->dictLookup("Filter", &obj, recursion); if (obj.isNull()) { obj.free(); dict->dictLookup("F", &obj); } - dict->dictLookup("DecodeParms", ¶ms); + dict->dictLookup("DecodeParms", ¶ms, recursion); if (params.isNull()) { params.free(); dict->dictLookup("DP", ¶ms); } if (obj.isName()) { - str = makeFilter(obj.getName(), str, ¶ms); + str = makeFilter(obj.getName(), str, ¶ms, recursion); } else if (obj.isArray()) { for (i = 0; i < obj.arrayGetLength(); ++i) { obj.arrayGet(i, &obj2); @@ -164,7 +167,7 @@ Stream *Stream::addFilters(Object *dict) { else params2.initNull(); if (obj2.isName()) { - str = makeFilter(obj2.getName(), str, ¶ms2); + str = makeFilter(obj2.getName(), str, ¶ms2, recursion); } else { error(errSyntaxError, getPos(), "Bad filter name"); str = new EOFStream(str); @@ -181,7 +184,7 @@ Stream *Stream::addFilters(Object *dict) { return str; } -Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { +Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursion) { int pred; // parameters int colors; int bits; @@ -203,23 +206,23 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { bits = 8; early = 1; if (params->isDict()) { - params->dictLookup("Predictor", &obj); + params->dictLookup("Predictor", &obj, recursion); if (obj.isInt()) pred = obj.getInt(); obj.free(); - params->dictLookup("Columns", &obj); + params->dictLookup("Columns", &obj, recursion); if (obj.isInt()) columns = obj.getInt(); obj.free(); - params->dictLookup("Colors", &obj); + params->dictLookup("Colors", &obj, recursion); if (obj.isInt()) colors = obj.getInt(); obj.free(); - params->dictLookup("BitsPerComponent", &obj); + params->dictLookup("BitsPerComponent", &obj, recursion); if (obj.isInt()) bits = obj.getInt(); obj.free(); - params->dictLookup("EarlyChange", &obj); + params->dictLookup("EarlyChange", &obj, recursion); if (obj.isInt()) early = obj.getInt(); obj.free(); @@ -236,37 +239,37 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { endOfBlock = gTrue; black = gFalse; if (params->isDict()) { - params->dictLookup("K", &obj); + params->dictLookup("K", &obj, recursion); if (obj.isInt()) { encoding = obj.getInt(); } obj.free(); - params->dictLookup("EndOfLine", &obj); + params->dictLookup("EndOfLine", &obj, recursion); if (obj.isBool()) { endOfLine = obj.getBool(); } obj.free(); - params->dictLookup("EncodedByteAlign", &obj); + params->dictLookup("EncodedByteAlign", &obj, recursion); if (obj.isBool()) { byteAlign = obj.getBool(); } obj.free(); - params->dictLookup("Columns", &obj); + params->dictLookup("Columns", &obj, recursion); if (obj.isInt()) { columns = obj.getInt(); } obj.free(); - params->dictLookup("Rows", &obj); + params->dictLookup("Rows", &obj, recursion); if (obj.isInt()) { rows = obj.getInt(); } obj.free(); - params->dictLookup("EndOfBlock", &obj); + params->dictLookup("EndOfBlock", &obj, recursion); if (obj.isBool()) { endOfBlock = obj.getBool(); } obj.free(); - params->dictLookup("BlackIs1", &obj); + params->dictLookup("BlackIs1", &obj, recursion); if (obj.isBool()) { black = obj.getBool(); } @@ -277,7 +280,7 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) { colorXform = -1; if (params->isDict()) { - if (params->dictLookup("ColorTransform", &obj)->isInt()) { + if (params->dictLookup("ColorTransform", &obj, recursion)->isInt()) { colorXform = obj.getInt(); } obj.free(); @@ -289,19 +292,19 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { colors = 1; bits = 8; if (params->isDict()) { - params->dictLookup("Predictor", &obj); + params->dictLookup("Predictor", &obj, recursion); if (obj.isInt()) pred = obj.getInt(); obj.free(); - params->dictLookup("Columns", &obj); + params->dictLookup("Columns", &obj, recursion); if (obj.isInt()) columns = obj.getInt(); obj.free(); - params->dictLookup("Colors", &obj); + params->dictLookup("Colors", &obj, recursion); if (obj.isInt()) colors = obj.getInt(); obj.free(); - params->dictLookup("BitsPerComponent", &obj); + params->dictLookup("BitsPerComponent", &obj, recursion); if (obj.isInt()) bits = obj.getInt(); obj.free(); @@ -309,7 +312,7 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { str = new FlateStream(str, pred, columns, colors, bits); } else if (!strcmp(name, "JBIG2Decode")) { if (params->isDict()) { - params->dictLookup("JBIG2Globals", &globals); + params->dictLookup("JBIG2Globals", &globals, recursion); } str = new JBIG2Stream(str, &globals); globals.free(); @@ -724,13 +727,30 @@ GBool StreamPredictor::getNextLine() { } //------------------------------------------------------------------------ +// UniqueFileStream +//------------------------------------------------------------------------ + +UniqueFileStream::UniqueFileStream(FILE *fA, char *fileNameA, Guint startA, GBool limitedA, + Guint lengthA, Object *dictA): + FileStream(fA, fileNameA, startA, limitedA, lengthA, dictA) { + f = fopen(fileName, "rb"); + reset(); +} + +UniqueFileStream::~UniqueFileStream() { + close(); + fclose(f); +} + +//------------------------------------------------------------------------ // FileStream //------------------------------------------------------------------------ -FileStream::FileStream(FILE *fA, Guint startA, GBool limitedA, +FileStream::FileStream(FILE *fA, char *fileNameA, Guint startA, GBool limitedA, Guint lengthA, Object *dictA): BaseStream(dictA, lengthA) { f = fA; + fileName = fileNameA; start = startA; limited = limitedA; length = lengthA; @@ -744,9 +764,13 @@ FileStream::~FileStream() { close(); } +BaseStream *FileStream::copy() { + return new UniqueFileStream(f, fileName, start, limited, length, &dict); +} + Stream *FileStream::makeSubStream(Guint startA, GBool limitedA, Guint lengthA, Object *dictA) { - return new FileStream(f, startA, limitedA, lengthA, dictA); + return new UniqueFileStream(f, fileName, startA, limitedA, lengthA, dictA); } void FileStream::reset() { @@ -868,6 +892,11 @@ CachedFileStream::~CachedFileStream() cc->decRefCnt(); } +BaseStream *CachedFileStream::copy() { + cc->incRefCnt(); + return new CachedFileStream(cc, start, limited, length, &dict); +} + Stream *CachedFileStream::makeSubStream(Guint startA, GBool limitedA, Guint lengthA, Object *dictA) { @@ -963,6 +992,10 @@ MemStream::~MemStream() { } } +BaseStream *MemStream::copy() { + return new MemStream(buf, start, length, &dict); +} + Stream *MemStream::makeSubStream(Guint startA, GBool limited, Guint lengthA, Object *dictA) { MemStream *subStr; @@ -1037,6 +1070,11 @@ EmbedStream::EmbedStream(Stream *strA, Object *dictA, EmbedStream::~EmbedStream() { } +BaseStream *EmbedStream::copy() { + error(errInternal, -1, "Called copy() on EmbedStream"); + return NULL; +} + Stream *EmbedStream::makeSubStream(Guint start, GBool limitedA, Guint lengthA, Object *dictA) { error(errInternal, -1, "Called makeSubStream() on EmbedStream"); diff --git a/poppler/Stream.h b/poppler/Stream.h index a270fdf..d19e9aa 100644 --- a/poppler/Stream.h +++ b/poppler/Stream.h @@ -217,13 +217,13 @@ public: // Add filters to this stream according to the parameters in . // Returns the new stream. - Stream *addFilters(Object *dict); + Stream *addFilters(Object *dict, int recursion = 0); private: virtual GBool hasGetChars() { return false; } virtual int getChars(int nChars, Guchar *buffer); - Stream *makeFilter(char *name, Stream *str, Object *params); + Stream *makeFilter(char *name, Stream *str, Object *params, int recursion = 0); int ref; // reference count }; @@ -298,6 +298,7 @@ public: BaseStream(Object *dictA, Guint lengthA); virtual ~BaseStream(); + virtual BaseStream *copy() = 0; virtual Stream *makeSubStream(Guint start, GBool limited, Guint length, Object *dict) = 0; virtual void setPos(Guint pos, int dir = 0) = 0; @@ -315,9 +316,6 @@ public: protected: Guint length; - -private: - Object dict; }; @@ -438,9 +436,10 @@ private: class FileStream: public BaseStream { public: - FileStream(FILE *fA, Guint startA, GBool limitedA, + FileStream(FILE *fA, char *fileName, Guint startA, GBool limitedA, Guint lengthA, Object *dictA); virtual ~FileStream(); + virtual BaseStream *copy(); virtual Stream *makeSubStream(Guint startA, GBool limitedA, Guint lengthA, Object *dictA); virtual StreamKind getKind() { return strFile; } @@ -485,7 +484,10 @@ private: return n; } +protected: FILE *f; + char *fileName; +private: Guint start; GBool limited; char buf[fileStreamBufSize]; @@ -496,6 +498,14 @@ private: GBool saved; }; +class UniqueFileStream: public FileStream { +public: + + UniqueFileStream(FILE *fA, char *fileNameA, Guint startA, GBool limitedA, + Guint lengthA, Object *dictA); + virtual ~UniqueFileStream(); +}; + //------------------------------------------------------------------------ // CachedFileStream //------------------------------------------------------------------------ @@ -508,6 +518,7 @@ public: CachedFileStream(CachedFile *ccA, Guint startA, GBool limitedA, Guint lengthA, Object *dictA); virtual ~CachedFileStream(); + virtual BaseStream *copy(); virtual Stream *makeSubStream(Guint startA, GBool limitedA, Guint lengthA, Object *dictA); virtual StreamKind getKind() { return strCachedFile; } @@ -550,6 +561,7 @@ public: MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA); virtual ~MemStream(); + virtual BaseStream *copy(); virtual Stream *makeSubStream(Guint start, GBool limited, Guint lengthA, Object *dictA); virtual StreamKind getKind() { return strWeird; } @@ -598,6 +610,7 @@ public: EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Guint lengthA); virtual ~EmbedStream(); + virtual BaseStream *copy(); virtual Stream *makeSubStream(Guint start, GBool limitedA, Guint lengthA, Object *dictA); virtual StreamKind getKind() { return str->getKind(); } diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc index 9af7532..3637be2 100644 --- a/poppler/TextOutputDev.cc +++ b/poppler/TextOutputDev.cc @@ -4296,7 +4296,7 @@ TextSelectionPainter::TextSelectionPainter(TextPage *page, state = new GfxState(72 * scale, 72 * scale, &box, rotation, gFalse); - out->startPage (0, state); + out->startPage (0, state, NULL); out->setDefaultCTM (state->getCTM()); state->setTextMat(1, 0, 0, -1, 0, 0); @@ -5362,7 +5362,7 @@ TextOutputDev::~TextOutputDev() { delete actualText; } -void TextOutputDev::startPage(int pageNum, GfxState *state) { +void TextOutputDev::startPage(int pageNum, GfxState *state, XRef *xref) { text->startPage(state); } diff --git a/poppler/TextOutputDev.h b/poppler/TextOutputDev.h index e31876b..0b871a3 100644 --- a/poppler/TextOutputDev.h +++ b/poppler/TextOutputDev.h @@ -717,7 +717,7 @@ public: //----- initialization and control // Start a page. - virtual void startPage(int pageNum, GfxState *state); + virtual void startPage(int pageNum, GfxState *state, XRef *xref); // End a page. virtual void endPage(); diff --git a/poppler/XRef.cc b/poppler/XRef.cc index 3564807..49bba58 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -65,6 +65,14 @@ #define permHighResPrint (1<<11) // bit 12 #define defPermFlags 0xfffc +#if MULTITHREADED +# define lockXRef gLockMutex(&mutex) +# define unlockXRef gUnlockMutex(&mutex) +#else +# define lockXRef +# define unlockXRef +#endif + //------------------------------------------------------------------------ // ObjectStream //------------------------------------------------------------------------ @@ -74,7 +82,7 @@ public: // Create an object stream, using object number , // generation 0. - ObjectStream(XRef *xref, int objStrNumA); + ObjectStream(XRef *xref, int objStrNumA, int recursion = 0); GBool isOk() { return ok; } @@ -127,7 +135,7 @@ class ObjectStreamItem : public PopplerCacheItem ObjectStream *objStream; }; -ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { +ObjectStream::ObjectStream(XRef *xref, int objStrNumA, int recursion) { Stream *str; Parser *parser; int *offsets; @@ -140,11 +148,11 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { objNums = NULL; ok = gFalse; - if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) { + if (!xref->fetch(objStrNum, 0, &objStr, recursion)->isStream()) { goto err1; } - if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) { + if (!objStr.streamGetDict()->lookup("N", &obj1, recursion)->isInt()) { obj1.free(); goto err1; } @@ -154,7 +162,7 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { goto err1; } - if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) { + if (!objStr.streamGetDict()->lookup("First", &obj1, recursion)->isInt()) { obj1.free(); goto err1; } @@ -257,6 +265,9 @@ Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { //------------------------------------------------------------------------ void XRef::init() { +#if MULTITHREADED + gInitMutex(&mutex); +#endif ok = gTrue; errCode = errNone; entries = NULL; @@ -267,6 +278,7 @@ void XRef::init() { objStrs = new PopplerCache(5); mainXRefEntriesOffset = 0; xRefStream = gFalse; + strOwner = gFalse; } XRef::XRef() { @@ -373,6 +385,53 @@ XRef::~XRef() { if (objStrs) { delete objStrs; } + if (strOwner) + delete str; +} + +XRef *XRef::copy() { + lockXRef; + XRef *xref = new XRef(); + xref->init(); + xref->str = str->copy(); + xref->strOwner = gTrue; + xref->encrypted = encrypted; + xref->permFlags = permFlags; + xref->ownerPasswordOk = ownerPasswordOk; + + xref->start = start; + xref->prevXRefOffset = prevXRefOffset; + xref->mainXRefEntriesOffset = mainXRefEntriesOffset; + xref->xRefStream = xRefStream; + xref->trailerDict.initDict(trailerDict.getDict()); + xref->encAlgorithm = encAlgorithm; + xref->encRevision = encRevision; + xref->encVersion = encVersion; + xref->permFlags = permFlags; + xref->keyLength = keyLength; + xref->permFlags = permFlags; + for (int i = 0; i < 32; i++) { + xref->fileKey[i] = fileKey[i]; + } + + xref->reserve(size); + xref->size = size; + for (int i = 0; i < size; ++i) { + xref->entries[i].offset = entries[i].offset; + xref->entries[i].type = entries[i].type; + xref->entries[i].obj.initNull (); + xref->entries[i].updated = entries[i].updated; + xref->entries[i].gen = entries[i].gen; + } + xref->streamEndsLen = streamEndsLen; + if (streamEndsLen != 0) { + xref->streamEnds = (Guint *)gmalloc(streamEndsLen * sizeof(Guint)); + for (int i = 0; i < streamEndsLen; i++) { + xref->streamEnds[i] = streamEnds[i]; + } + } + unlockXRef; + return xref; } int XRef::reserve(int newSize) @@ -991,6 +1050,7 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) { Parser *parser; Object obj1, obj2, obj3; + if (recursion == 0) lockXRef; // check for bogus ref - this can happen in corrupted PDF files if (num < 0 || num >= size) { goto err; @@ -999,9 +1059,11 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) { e = getEntry(num); if(!e->obj.isNull ()) { //check for updated object obj = e->obj.copy(obj); + if (recursion == 0) + unlockXRef; return obj; } - + switch (e->type) { case xrefEntryUncompressed: @@ -1079,7 +1141,7 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) { } if (!objStr) { - objStr = new ObjectStream(this, e->offset); + objStr = new ObjectStream(this, e->offset, recursion + 1); if (!objStr->isOk()) { delete objStr; objStr = NULL; @@ -1098,9 +1160,11 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) { goto err; } + if (recursion == 0) unlockXRef; return obj; err: + if (recursion == 0) unlockXRef; return obj->initNull(); } @@ -1415,7 +1479,7 @@ XRefEntry *XRef::getEntry(int i, GBool complainIfMissing) break; } } - + // We might have reconstructed the xref // Check again i is in bounds if (unlikely(i >= size)) { diff --git a/poppler/XRef.h b/poppler/XRef.h index 148a5ce..c0527c6 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -34,8 +34,10 @@ #pragma interface #endif +#include #include "goo/gtypes.h" #include "Object.h" +#include "goo/GooMutex.h" #include @@ -76,6 +78,9 @@ public: // Destructor. ~XRef(); + // Copy xref but with new base stream! + XRef *copy(); + // Is xref table valid? GBool isOk() { return ok; } @@ -171,6 +176,10 @@ private: Guint prevXRefOffset; // position of prev XRef section (= next to read) Guint mainXRefEntriesOffset; // offset of entries in main XRef table GBool xRefStream; // true if last XRef section is a stream + GBool strOwner; // true if str is owned by the instance +#if MULTITHREADED + GooMutex mutex; +#endif void init(); int reserve(int newSize); diff --git a/utils/HtmlOutputDev.cc b/utils/HtmlOutputDev.cc index 83f65d5..441184b 100644 --- a/utils/HtmlOutputDev.cc +++ b/utils/HtmlOutputDev.cc @@ -1236,7 +1236,7 @@ HtmlOutputDev::~HtmlOutputDev() { delete pages; } -void HtmlOutputDev::startPage(int pageNum, GfxState *state) { +void HtmlOutputDev::startPage(int pageNum, GfxState *state, XRef *xref) { #if 0 if (mode&&!xml){ if (write){ diff --git a/utils/HtmlOutputDev.h b/utils/HtmlOutputDev.h index 12b16bf..d8d2870 100644 --- a/utils/HtmlOutputDev.h +++ b/utils/HtmlOutputDev.h @@ -279,7 +279,7 @@ public: // Start a page. - virtual void startPage(int pageNum, GfxState *state); + virtual void startPage(int pageNum, GfxState *state, XRef *xref); // End a page. virtual void endPage(); diff --git a/utils/ImageOutputDev.h b/utils/ImageOutputDev.h index 6201a24..51e4645 100644 --- a/utils/ImageOutputDev.h +++ b/utils/ImageOutputDev.h @@ -78,7 +78,7 @@ public: virtual GBool needNonText() { return gTrue; } // Start a page - virtual void startPage(int pageNumA, GfxState *state) + virtual void startPage(int pageNumA, GfxState *state, XRef *xref) { pageNum = pageNumA; } //---- get info about output device