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 @@
   }
 
   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 @@
   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 @@
   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 @@
   }
 
   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 @@
       }
       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 @@
   }
 }
 
+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 @@
   // 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 @@
   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 @@
   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