On Tuesday, April 24, 2012 11:01:17 PM Fabio D'Urso wrote: > In patch 0002, I feel that writeStreamToBuffer should share code with > writeTableToFile. But I can't think of a non-ugly way to do this (callbacks > or arguments used alternatively both seem ugly to me).
Eventually I created some classes to abstract writeTableToFile and share code. Final patches are: 0001 from previous post, 0002 from this post. Fabio
From 71f8fb116b9e1700b09f1975667590285709a466 Mon Sep 17 00:00:00 2001 From: Fabio D'Urso <[email protected]> Date: Tue, 24 Apr 2012 21:00:11 +0200 Subject: [PATCH 2/2] Output XRef stream when incrementally updating if there's already a XRef stream --- poppler/PDFDoc.cc | 45 ++++++++++++++++++++++++++++++- poppler/XRef.cc | 76 +++++++++++++++++++++++++++++++++++++++++++++------- poppler/XRef.h | 34 +++++++++++++++++++++++ 3 files changed, 142 insertions(+), 13 deletions(-) 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 -- 1.7.6.5
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
