From 6708c12fd4acdd4b9e863a63efea29205f472eaf Mon Sep 17 00:00:00 2001 From: Fabio D'Urso Date: Mon, 23 Apr 2012 11:55:46 +0200 Subject: [PATCH] saveIncrementalUpdate: Output a xref stream if there was a xref stream already --- poppler/PDFDoc.cc | 45 +++++++++++++++++++++++++++++++----------- poppler/PDFDoc.h | 4 +- poppler/XRef.cc | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ poppler/XRef.h | 3 ++ 4 files changed, 94 insertions(+), 14 deletions(-) diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index 898bcbb..23896ce 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -721,7 +721,7 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) Ref ref; ref.num = rootNum; ref.gen = 0; - writeTrailer(uxrefOffset, objectsCount, outStr, gFalse, 0, &ref, getXRef(), name->getCString(), outStr->getPos()); + writeTrailer(uxrefOffset, objectsCount, outStr, gFalse, 0, &ref, getXRef(), name->getCString(), outStr->getPos(), NULL); outStr->close(); fclose(f); @@ -862,9 +862,18 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) } Guint uxrefOffset = outStr->getPos(); - uxref->writeToFile(outStr, gFalse /* do not write unnecessary entries */); - - writeTrailer(uxrefOffset, xref->getNumObjects(), outStr, gTrue); + int numobjects = xref->getNumObjects(); + + // Output a xref stream if and only if there was a xref stream already + if (xref->isXRefStream()) { + // Append an entry for the xref stream itself and write its ref + outStr->printf("%d 0 obj ", numobjects); + uxref->add(numobjects++, 0, uxrefOffset, gTrue); + writeTrailer(uxrefOffset, numobjects, outStr, gTrue, uxref /* Output XRef stream */ ); + } else { + uxref->writeToFile(outStr, gFalse /* do not write unnecessary entries */); + writeTrailer(uxrefOffset, numobjects, outStr, gTrue, NULL); + } delete uxref; } @@ -904,8 +913,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) Guint uxrefOffset = outStr->getPos(); uxref->writeToFile(outStr, gTrue /* write all entries */); - writeTrailer(uxrefOffset, uxref->getNumObjects(), outStr, gFalse); - + writeTrailer(uxrefOffset, uxref->getNumObjects(), outStr, gFalse, NULL); delete uxref; @@ -1112,7 +1120,7 @@ Guint PDFDoc::writeObject (Object* obj, Ref* ref, OutStream* outStr, XRef *xRef, void PDFDoc::writeTrailer(Guint uxrefOffset, int uxrefSize, OutStream* outStr, GBool incrUpdate, Guint startxRef, Ref *root, XRef *xRef, const char *fileName, - Guint fileSize) + Guint fileSize, XRef *uxrefStm) { Dict *trailerDict = new Dict(xRef); Object obj1; @@ -1195,16 +1203,29 @@ void PDFDoc::writeTrailer(Guint uxrefOffset, int uxrefSize, } } - outStr->printf( "trailer\r\n"); - writeDictionnary(trailerDict, outStr, xRef, 0); - outStr->printf( "\r\nstartxref\r\n"); + // A NULL uxrefStm means that we're writing a classic XRef table + if (uxrefStm) { + /* Object ref (ie: " 0 obj\r\n") was already written by the caller */ + GooString stmData; + uxrefStm->outputXRefStm(&stmData, trailerDict, xRef); + MemStream *mStream = new MemStream( stmData.getCString(), 0, + stmData.getLength(), obj1.initDict(trailerDict) ); + writeObject(obj1.initStream(mStream), NULL, outStr, xRef, 0); + obj1.free(); + } else { + /* XRef table was already written by the caller */ + outStr->printf( "trailer\r\n"); + writeDictionnary(trailerDict, outStr, xRef, 0); + outStr->printf( "\r\n"); + } + outStr->printf( "startxref\r\n"); outStr->printf( "%i\r\n", uxrefOffset); outStr->printf( "%%%%EOF\r\n"); delete trailerDict; } -void PDFDoc::writeTrailer(Guint uxrefOffset, int uxrefSize, OutStream* outStr, GBool incrUpdate) +void PDFDoc::writeTrailer(Guint uxrefOffset, int uxrefSize, OutStream* outStr, GBool incrUpdate, XRef *uxrefStm) { const char *fileNameA; if (fileName) @@ -1222,7 +1243,7 @@ void PDFDoc::writeTrailer(Guint uxrefOffset, int uxrefSize, OutStream* outStr, G Ref ref; ref.num = getXRef()->getRootNum(); ref.gen = getXRef()->getRootGen(); - writeTrailer(uxrefOffset, uxrefSize, outStr, incrUpdate, getStartXRef(), &ref, getXRef(), fileNameA, fileSize); + writeTrailer(uxrefOffset, uxrefSize, outStr, incrUpdate, getStartXRef(), &ref, getXRef(), fileNameA, fileSize, uxrefStm); } void PDFDoc::writeHeader(OutStream *outStr, int major, int minor) diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index ccb1b22..b8aeb86 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -245,7 +245,7 @@ public: static Guint writeObject (Object *obj, Ref *ref, OutStream* outStr, XRef *xref, Guint numOffset); static void writeHeader(OutStream *outStr, int major, int minor); static void writeTrailer (Guint uxrefOffset, int uxrefSize, OutStream* outStr, GBool incrUpdate, - Guint startxRef, Ref *root, XRef *xRef, const char *fileName, Guint fileSize); + Guint startxRef, Ref *root, XRef *xRef, const char *fileName, Guint fileSize, XRef *uxref); private: // insert referenced objects in XRef @@ -260,7 +260,7 @@ private: { writeDictionnary(dict, outStr, getXRef(), 0); } static void writeStream (Stream* str, OutStream* outStr); static void writeRawStream (Stream* str, OutStream* outStr); - void writeTrailer (Guint uxrefOffset, int uxrefSize, OutStream* outStr, GBool incrUpdate); + void writeTrailer (Guint uxrefOffset, int uxrefSize, OutStream* outStr, GBool incrUpdate, XRef *uxrefStm); static void writeString (GooString* s, OutStream* outStr); void saveIncrementalUpdate (OutStream* outStr); void saveCompleteRewrite (OutStream* outStr); diff --git a/poppler/XRef.cc b/poppler/XRef.cc index dfc6d73..9c120fb 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -1288,6 +1288,62 @@ void XRef::writeToFile(OutStream* outStr, GBool writeAllEntries) { } } +void XRef::outputXRefStm(GooString *stmBuf, Dict *xrefDict, XRef *xref) { + //create free entries linked-list + if (getEntry(0)->gen != 65535) { + error(errInternal, -1, "XRef::outputXRefStm, entry 0 of the XRef is invalid (gen != 65535)\n"); + } + int lastFreeEntry = 0; + for (int i=0; itype == xrefEntryFree) { + getEntry(lastFreeEntry)->offset = i; + lastFreeEntry = i; + } + } + + Object index; + index.initArray(xref); + stmBuf->clear(); + int i = 0; + while (i < size) { + int j; + for(j=i; jtype == xrefEntryFree) && (getEntry(j)->gen == 0)) + break; + } + if (j-i != 0) + { + Object obj; + index.arrayAdd( obj.initInt(i) ); + index.arrayAdd( obj.initInt(j-i) ); + for (int k=i; kgen > 65535) e->gen = 65535; //cap generation number to 65535 (required by PDFReference) + char data[7]; + data[0] = (e->type==xrefEntryFree) ? 0 : 1; + data[1] = (e->offset >> 24) & 0xff; + data[2] = (e->offset >> 16) & 0xff; + data[3] = (e->offset >> 8) & 0xff; + data[4] = e->offset & 0xff; + data[5] = (e->gen >> 8) & 0xff; + data[6] = e->gen & 0xff; + stmBuf->append(data, sizeof(data)); + } + i = j; + } + else ++i; + } + + Object obj1, obj2; + xrefDict->set("Type", obj1.initName("XRef")); + xrefDict->set("Index", &index); + obj2.initArray(xref); + obj2.arrayAdd( obj1.initInt(1) ); + obj2.arrayAdd( obj1.initInt(4) ); + obj2.arrayAdd( obj1.initInt(2) ); + xrefDict->set("W", &obj2); +} + GBool XRef::parseEntry(Guint offset, XRefEntry *entry) { GBool r; diff --git a/poppler/XRef.h b/poppler/XRef.h index 4cba474..15d0937 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -79,6 +79,8 @@ public: // Is xref table valid? GBool isOk() { return ok; } + GBool isXRefStream() { return xRefStream; } + // Get the error code (if isOk() returns false). int getErrorCode() { return errCode; } @@ -136,6 +138,7 @@ public: void removeIndirectObject(Ref r); void add(int num, int gen, Guint offs, GBool used); void writeToFile(OutStream* outStr, GBool writeAllEntries); + void outputXRefStm(GooString *stmBuf, Dict *xrefDict, XRef *xref); private: -- 1.7.6.5