poppler/PDFDoc.cc | 96 ++++++++++++++++++++++++++++++++++++++---------------- poppler/PDFDoc.h | 14 ++++++- poppler/XRef.cc | 76 ++++++++++++++++++++++++++++++++++++------ poppler/XRef.h | 36 +++++++++++++++++++- utils/pdfunite.cc | 10 +++-- 5 files changed, 185 insertions(+), 47 deletions(-)
New commits: commit b1d5c6c0a20a4a24b42de66db23e0f63d10ca52d Author: Fabio D'Urso <[email protected]> Date: Tue Apr 24 21:00:11 2012 +0200 Output XRef stream when incrementally updating if there's already a XRef stream diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index 9c977a6..2dc1ac8 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -864,8 +864,30 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) } Guint uxrefOffset = outStr->getPos(); - writeXRefTableTrailer(uxrefOffset, uxref, gFalse /* do not write unnecessary entries */, - xref->getNumObjects(), outStr, gTrue /* incremental update */); + int numobjects = xref->getNumObjects(); + const char *fileNameA = fileName ? fileName->getCString() : NULL; + Ref rootRef, uxrefStreamRef; + rootRef.num = getXRef()->getRootNum(); + rootRef.gen = getXRef()->getRootGen(); + + // Output a xref stream if there is a xref stream already + GBool xRefStream = xref->isXRefStream(); + + if (xRefStream) { + // Append an entry for the xref stream itself + uxrefStreamRef.num = numobjects++; + uxrefStreamRef.gen = 0; + uxref->add(uxrefStreamRef.num, uxrefStreamRef.gen, uxrefOffset, gTrue); + } + + Dict *trailerDict = createTrailerDict(numobjects, gTrue, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset); + if (xRefStream) { + writeXRefStreamTrailer(trailerDict, uxref, &uxrefStreamRef, uxrefOffset, outStr, getXRef()); + } else { + writeXRefTableTrailer(trailerDict, uxref, gFalse, uxrefOffset, outStr, getXRef()); + } + + delete trailerDict; delete uxref; } @@ -1203,6 +1225,25 @@ void PDFDoc::writeXRefTableTrailer(Dict *trailerDict, XRef *uxref, GBool writeAl outStr->printf( "%%%%EOF\r\n"); } +void PDFDoc::writeXRefStreamTrailer (Dict *trailerDict, XRef *uxref, Ref *uxrefStreamRef, Guint uxrefOffset, OutStream* outStr, XRef *xRef) +{ + GooString stmData; + + // Fill stmData and some trailerDict fields + uxref->writeStreamToBuffer(&stmData, trailerDict, xRef); + + // Create XRef stream object and write it + Object obj1; + MemStream *mStream = new MemStream( stmData.getCString(), 0, + stmData.getLength(), obj1.initDict(trailerDict) ); + writeObject(obj1.initStream(mStream), uxrefStreamRef, outStr, xRef, 0); + obj1.free(); + + outStr->printf( "startxref\r\n"); + outStr->printf( "%i\r\n", uxrefOffset); + outStr->printf( "%%%%EOF\r\n"); +} + void PDFDoc::writeXRefTableTrailer(Guint uxrefOffset, XRef *uxref, GBool writeAllEntries, int uxrefSize, OutStream* outStr, GBool incrUpdate) { diff --git a/poppler/XRef.cc b/poppler/XRef.cc index 3b0d7f8..1574371 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -1240,10 +1240,10 @@ void XRef::removeIndirectObject(Ref r) { e->updated = true; } -void XRef::writeTableToFile(OutStream* outStr, GBool writeAllEntries) { +void XRef::writeXRef(XRef::XRefWriter *writer, GBool writeAllEntries) { //create free entries linked-list if (getEntry(0)->gen != 65535) { - error(errInternal, -1, "XRef::writeToFile, entry 0 of the XRef is invalid (gen != 65535)\n"); + error(errInternal, -1, "XRef::writeXRef, entry 0 of the XRef is invalid (gen != 65535)\n"); } int lastFreeEntry = 0; for (int i=0; i<size; i++) { @@ -1254,18 +1254,13 @@ void XRef::writeTableToFile(OutStream* outStr, GBool writeAllEntries) { } if (writeAllEntries) { - //write the new xref - outStr->printf("xref\r\n"); - outStr->printf("%i %i\r\n", 0, size); + writer->startSection(0, size); for (int i=0; i<size; i++) { XRefEntry *e = getEntry(i); - if(e->gen > 65535) e->gen = 65535; //cap generation number to 65535 (required by PDFReference) - outStr->printf("%010i %05i %c\r\n", e->offset, e->gen, (e->type==xrefEntryFree)?'f':'n'); + writer->writeEntry(e->offset, e->gen, e->type); } } else { - //write the new xref - outStr->printf("xref\r\n"); int i = 0; while (i < size) { int j; @@ -1275,11 +1270,11 @@ void XRef::writeTableToFile(OutStream* outStr, GBool writeAllEntries) { } if (j-i != 0) { - outStr->printf("%i %i\r\n", i, j-i); + writer->startSection(i, j-i); for (int k=i; k<j; k++) { XRefEntry *e = getEntry(k); if(e->gen > 65535) e->gen = 65535; //cap generation number to 65535 (required by PDFReference) - outStr->printf("%010i %05i %c\r\n", e->offset, e->gen, (e->type==xrefEntryFree)?'f':'n'); + writer->writeEntry(e->offset, e->gen, e->type); } i = j; } @@ -1288,6 +1283,65 @@ void XRef::writeTableToFile(OutStream* outStr, GBool writeAllEntries) { } } +XRef::XRefTableWriter::XRefTableWriter(OutStream* outStrA) { + outStr = outStrA; +} + +void XRef::XRefTableWriter::startSection(int first, int count) { + outStr->printf("%i %i\r\n", first, count); +} + +void XRef::XRefTableWriter::writeEntry(Guint offset, int gen, XRefEntryType type) { + outStr->printf("%010i %05i %c\r\n", offset, gen, (type==xrefEntryFree)?'f':'n'); +} + +void XRef::writeTableToFile(OutStream* outStr, GBool writeAllEntries) { + XRefTableWriter writer(outStr); + outStr->printf("xref\r\n"); + writeXRef(&writer, writeAllEntries); +} + +XRef::XRefStreamWriter::XRefStreamWriter(Object *indexA, GooString *stmBufA) { + index = indexA; + stmBuf = stmBufA; +} + +void XRef::XRefStreamWriter::startSection(int first, int count) { + Object obj; + index->arrayAdd( obj.initInt(first) ); + index->arrayAdd( obj.initInt(count) ); +} + +void XRef::XRefStreamWriter::writeEntry(Guint offset, int gen, XRefEntryType type) { + char data[7]; + data[0] = (type==xrefEntryFree) ? 0 : 1; + data[1] = (offset >> 24) & 0xff; + data[2] = (offset >> 16) & 0xff; + data[3] = (offset >> 8) & 0xff; + data[4] = offset & 0xff; + data[5] = (gen >> 8) & 0xff; + data[6] = gen & 0xff; + stmBuf->append(data, 7); +} + +void XRef::writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref) { + Object index; + index.initArray(xref); + stmBuf->clear(); + + XRefStreamWriter writer(&index, stmBuf); + writeXRef(&writer, gFalse); + + 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 ab8047c..148a5ce 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -79,6 +79,9 @@ public: // Is xref table valid? GBool isOk() { return ok; } + // Is the last XRef section a stream or a table? + GBool isXRefStream() { return xRefStream; } + // Get the error code (if isOk() returns false). int getErrorCode() { return errCode; } @@ -135,7 +138,11 @@ public: Ref addIndirectObject (Object* o); void removeIndirectObject(Ref r); void add(int num, int gen, Guint offs, GBool used); + + // Output XRef table to stream void writeTableToFile(OutStream* outStr, GBool writeAllEntries); + // Output XRef stream contents to GooString and fill trailerDict fields accordingly + void writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref); private: @@ -176,6 +183,33 @@ private: GBool constructXRef(GBool *wasReconstructed); GBool parseEntry(Guint offset, XRefEntry *entry); + class XRefWriter { + public: + virtual void startSection(int first, int count) = 0; + virtual void writeEntry(Guint offset, int gen, XRefEntryType type) = 0; + virtual ~XRefWriter() {}; + }; + + class XRefTableWriter: public XRefWriter { + public: + XRefTableWriter(OutStream* outStrA); + void startSection(int first, int count); + void writeEntry(Guint offset, int gen, XRefEntryType type); + private: + OutStream* outStr; + }; + + class XRefStreamWriter: public XRefWriter { + public: + XRefStreamWriter(Object *index, GooString *stmBuf); + void startSection(int first, int count); + void writeEntry(Guint offset, int gen, XRefEntryType type); + private: + Object *index; + GooString *stmBuf; + }; + + void writeXRef(XRefWriter *writer, GBool writeAllEntries); }; #endif commit 2ecf3b2e49a4c35e995d25016b810592260edfeb Author: Fabio D'Urso <[email protected]> Date: Tue Apr 24 18:10:15 2012 +0200 Refactoring of XRef table write support (in preparation for XRef stream write support) - Trailer dictionary creation now lives in its own function "createTrailerDict" (that will be used by XRef stream creation too) - writeXRefTableTrailer (WAS writeTrailer) now takes care of writing the XRef table too (previously it was demanded to the caller) diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index 898bcbb..9c977a6 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -716,12 +716,14 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) page.free(); Guint uxrefOffset = outStr->getPos(); - yRef->writeToFile(outStr, gFalse /* do not write unnecessary entries */); - Ref ref; ref.num = rootNum; ref.gen = 0; - writeTrailer(uxrefOffset, objectsCount, outStr, gFalse, 0, &ref, getXRef(), name->getCString(), outStr->getPos()); + Dict *trailerDict = createTrailerDict(objectsCount, gFalse, 0, &ref, getXRef(), + name->getCString(), uxrefOffset); + writeXRefTableTrailer(trailerDict, yRef, gFalse /* do not write unnecessary entries */, + uxrefOffset, outStr, getXRef()); + delete trailerDict; outStr->close(); fclose(f); @@ -862,10 +864,8 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) } Guint uxrefOffset = outStr->getPos(); - uxref->writeToFile(outStr, gFalse /* do not write unnecessary entries */); - - writeTrailer(uxrefOffset, xref->getNumObjects(), outStr, gTrue); - + writeXRefTableTrailer(uxrefOffset, uxref, gFalse /* do not write unnecessary entries */, + xref->getNumObjects(), outStr, gTrue /* incremental update */); delete uxref; } @@ -902,13 +902,9 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) } } Guint uxrefOffset = outStr->getPos(); - uxref->writeToFile(outStr, gTrue /* write all entries */); - - writeTrailer(uxrefOffset, uxref->getNumObjects(), outStr, gFalse); - - + writeXRefTableTrailer(uxrefOffset, uxref, gTrue /* write all entries */, + uxref->getNumObjects(), outStr, gFalse /* complete rewrite */); delete uxref; - } void PDFDoc::writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset) @@ -1109,10 +1105,8 @@ Guint PDFDoc::writeObject (Object* obj, Ref* ref, OutStream* outStr, XRef *xRef, return offset; } -void PDFDoc::writeTrailer(Guint uxrefOffset, int uxrefSize, - OutStream* outStr, GBool incrUpdate, - Guint startxRef, Ref *root, XRef *xRef, const char *fileName, - Guint fileSize) +Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Guint startxRef, + Ref *root, XRef *xRef, const char *fileName, Guint fileSize) { Dict *trailerDict = new Dict(xRef); Object obj1; @@ -1120,7 +1114,6 @@ void PDFDoc::writeTrailer(Guint uxrefOffset, int uxrefSize, trailerDict->set("Size", &obj1); obj1.free(); - //build a new ID, as recommended in the reference, uses: // - current time // - file name @@ -1130,7 +1123,9 @@ void PDFDoc::writeTrailer(Guint uxrefOffset, int uxrefSize, char buffer[256]; sprintf(buffer, "%i", (int)time(NULL)); message.append(buffer); - message.append(fileName); + + if (fileName) + message.append(fileName); sprintf(buffer, "%i", fileSize); message.append(buffer); @@ -1162,7 +1157,7 @@ void PDFDoc::writeTrailer(Guint uxrefOffset, int uxrefSize, //only update the second part of the array xRef->getTrailerDict()->getDict()->lookup("ID", &obj4); if (!obj4.isArray()) { - error(errSyntaxWarning, -1, "PDFDoc::writeTrailer original file's ID entry isn't an array. Trying to continue"); + error(errSyntaxWarning, -1, "PDFDoc::createTrailerDict original file's ID entry isn't an array. Trying to continue"); } else { //Get the first part of the ID obj4.arrayGet(0,&obj3); @@ -1194,24 +1189,25 @@ void PDFDoc::writeTrailer(Guint uxrefOffset, int uxrefSize, trailerDict->set("Info", &obj5); } } - + + return trailerDict; +} + +void PDFDoc::writeXRefTableTrailer(Dict *trailerDict, XRef *uxref, GBool writeAllEntries, Guint uxrefOffset, OutStream* outStr, XRef *xRef) +{ + uxref->writeTableToFile( outStr, writeAllEntries ); outStr->printf( "trailer\r\n"); writeDictionnary(trailerDict, outStr, xRef, 0); outStr->printf( "\r\nstartxref\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::writeXRefTableTrailer(Guint uxrefOffset, XRef *uxref, GBool writeAllEntries, + int uxrefSize, OutStream* outStr, GBool incrUpdate) { - const char *fileNameA; - if (fileName) - fileNameA = fileName->getCString(); - else - fileNameA = "streamwithoutfilename.pdf"; - // file size + const char *fileNameA = fileName ? fileName->getCString() : NULL; + // file size (doesn't include the trailer) unsigned int fileSize = 0; int c; str->reset(); @@ -1222,7 +1218,10 @@ 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); + Dict * trailerDict = createTrailerDict(uxrefSize, incrUpdate, getStartXRef(), &ref, + getXRef(), fileNameA, fileSize); + writeXRefTableTrailer(trailerDict, uxref, writeAllEntries, uxrefOffset, outStr, getXRef()); + delete trailerDict; } void PDFDoc::writeHeader(OutStream *outStr, int major, int minor) diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index ccb1b22..468f698 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -23,6 +23,7 @@ // Copyright (C) 2010 Hib Eris <[email protected]> // Copyright (C) 2010 Srinivas Adicherla <[email protected]> // Copyright (C) 2011 Thomas Freitag <[email protected]> +// Copyright (C) 2012 Fabio D'Urso <[email protected]> // // 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 @@ -244,8 +245,14 @@ public: Guint writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset); 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); + + // Ownership goes to the caller + static Dict *createTrailerDict (int uxrefSize, GBool incrUpdate, Guint startxRef, + Ref *root, XRef *xRef, const char *fileName, Guint fileSize); + static void writeXRefTableTrailer (Dict *trailerDict, XRef *uxref, GBool writeAllEntries, + Guint uxrefOffset, OutStream* outStr, XRef *xRef); + static void writeXRefStreamTrailer (Dict *trailerDict, XRef *uxref, Ref *uxrefStreamRef, + Guint uxrefOffset, OutStream* outStr, XRef *xRef); private: // insert referenced objects in XRef @@ -260,7 +267,8 @@ 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 writeXRefTableTrailer (Guint uxrefOffset, XRef *uxref, GBool writeAllEntries, + int uxrefSize, OutStream* outStr, GBool incrUpdate); 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..3b0d7f8 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -1240,7 +1240,7 @@ void XRef::removeIndirectObject(Ref r) { e->updated = true; } -void XRef::writeToFile(OutStream* outStr, GBool writeAllEntries) { +void XRef::writeTableToFile(OutStream* outStr, GBool writeAllEntries) { //create free entries linked-list if (getEntry(0)->gen != 65535) { error(errInternal, -1, "XRef::writeToFile, entry 0 of the XRef is invalid (gen != 65535)\n"); diff --git a/poppler/XRef.h b/poppler/XRef.h index 4cba474..ab8047c 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -135,7 +135,7 @@ public: Ref addIndirectObject (Object* o); void removeIndirectObject(Ref r); void add(int num, int gen, Guint offs, GBool used); - void writeToFile(OutStream* outStr, GBool writeAllEntries); + void writeTableToFile(OutStream* outStr, GBool writeAllEntries); private: diff --git a/utils/pdfunite.cc b/utils/pdfunite.cc index 93850a4..212f89b 100644 --- a/utils/pdfunite.cc +++ b/utils/pdfunite.cc @@ -6,6 +6,7 @@ // // Copyright (C) 2011 Thomas Freitag <[email protected]> // Copyright (C) 2012 Arseny Solokha <[email protected]> +// Copyright (C) 2012 Fabio D'Urso <[email protected]> // //======================================================================== #include <PDFDoc.h> @@ -161,13 +162,14 @@ int main (int argc, char *argv[]) objectsCount++; } Guint uxrefOffset = outStr->getPos(); - yRef->writeToFile(outStr, gFalse /* do not write unnecessary entries */ ); - Ref ref; ref.num = rootNum; ref.gen = 0; - PDFDoc::writeTrailer(uxrefOffset, objectsCount, outStr, (GBool) gFalse, 0, - &ref, yRef, fileName, outStr->getPos()); + Dict *trailerDict = PDFDoc::createTrailerDict(objectsCount, gFalse, 0, &ref, yRef, + fileName, outStr->getPos()); + PDFDoc::writeXRefTableTrailer(trailerDict, yRef, gFalse /* do not write unnecessary entries */, + uxrefOffset, outStr, yRef); + delete trailerDict; outStr->close(); fclose(f); _______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
