From 52d6255031aef9f8144eb56d322554a7652e6fae Mon Sep 17 00:00:00 2001
From: Zack Galbreath <zack.galbreath@kitware.com>
Date: Fri, 21 Feb 2014 10:48:08 -0500
Subject: [PATCH] add option to write XML to string instead of file

This commit enables vtkXMLWriter and its subclasses to write
their output to a string instead of a file.

Change-Id: Idff93039f9536379e3ef9abad6ea4ce18b4f2a60
---
 .../Testing/Cxx/TestPhyloXMLTreeWriter.cxx    |  22 ++-
 IO/XML/vtkXMLWriter.cxx                       | 133 ++++++++++++++----
 IO/XML/vtkXMLWriter.h                         |  20 +++
 3 files changed, 146 insertions(+), 29 deletions(-)

diff --git a/IO/Infovis/Testing/Cxx/TestPhyloXMLTreeWriter.cxx b/IO/Infovis/Testing/Cxx/TestPhyloXMLTreeWriter.cxx
index cdbd9bbda2c..0f69af177db 100644
--- a/IO/Infovis/Testing/Cxx/TestPhyloXMLTreeWriter.cxx
+++ b/IO/Infovis/Testing/Cxx/TestPhyloXMLTreeWriter.cxx
@@ -54,7 +54,7 @@ int TestPhyloXMLTreeWriter(int argc, char* argv[])
   char* baselineFile = vtkTestUtilities::GetArgOrEnvOrDefault("-V", argc, argv,
                                                               "", "");
 
-  // compare the baseline to the test file & return accordingly.
+  // compare the baseline file to the test file
   int result = EXIT_SUCCESS;
   if(vtksys::SystemTools::FilesDiffer(baselineFile, testFile.c_str()))
     {
@@ -62,6 +62,26 @@ int TestPhyloXMLTreeWriter(int argc, char* argv[])
     result = EXIT_FAILURE;
     }
 
+  // also test the "write to string" capabilities of this class
+  std::ifstream inFileStream;
+  inFileStream.open(baselineFile);
+  std::string baselineStr;
+  inFileStream.seekg(0, std::ios::end);
+  baselineStr.reserve(inFileStream.tellg());
+  inFileStream.seekg(0, std::ios::beg);
+  baselineStr.assign((std::istreambuf_iterator<char>(inFileStream)),
+                      std::istreambuf_iterator<char>());
+
+  writer->SetWriteToOutputString(1);
+  writer->Update();
+  std::string testStr = writer->GetOutputString();
+
+  if (baselineStr.compare(testStr) != 0)
+    {
+    cout << "PhyloXML write to string did not yield expected results." << endl;
+    result = EXIT_FAILURE;
+    }
+
   delete [] baselineFile;
   return result;
 }
diff --git a/IO/XML/vtkXMLWriter.cxx b/IO/XML/vtkXMLWriter.cxx
index 163520b82f1..0ec69ffad28 100644
--- a/IO/XML/vtkXMLWriter.cxx
+++ b/IO/XML/vtkXMLWriter.cxx
@@ -44,7 +44,6 @@
 #include "vtkInformationStringKey.h"
 
 #include <vtksys/auto_ptr.hxx>
-#include <vtksys/ios/sstream>
 
 #include <cassert>
 #include <string>
@@ -293,6 +292,7 @@ vtkXMLWriter::vtkXMLWriter()
 {
   this->FileName = 0;
   this->Stream = 0;
+  this->WriteToOutputString = 0;
 
   // Default binary data mode is base-64 encoding.
   this->DataStream = vtkBase64OutputStream::New();
@@ -329,6 +329,7 @@ vtkXMLWriter::vtkXMLWriter()
   this->SetNumberOfInputPorts(1);
 
   this->OutFile = 0;
+  this->OutStringStream = 0;
 
   // Time support
   this->TimeStep = 0; // By default the file does not have timestep
@@ -347,7 +348,16 @@ vtkXMLWriter::~vtkXMLWriter()
   this->SetFileName(0);
   this->DataStream->Delete();
   this->SetCompressor(0);
-  delete this->OutFile;
+  if (this->OutFile)
+    {
+    delete this->OutFile;
+    this->OutFile = 0;
+    }
+  if (this->OutStringStream)
+    {
+    delete this->OutStringStream;
+    this->OutStringStream = 0;
+    }
 
   delete this->FieldDataOM;
   delete[] this->NumberOfTimeValues;
@@ -670,10 +680,10 @@ int vtkXMLWriter::Write()
   return 1;
 }
 
+
 //----------------------------------------------------------------------------
-int vtkXMLWriter::OpenFile()
+int vtkXMLWriter::OpenStream()
 {
-  this->OutFile = 0;
   if(this->Stream)
     {
     // Rewind stream to the beginning.
@@ -681,32 +691,20 @@ int vtkXMLWriter::OpenFile()
     }
   else
     {
-    // Strip trailing whitespace from the filename.
-    int len = static_cast<int>(strlen(this->FileName));
-    for (int i = len-1; i >= 0; i--)
+    if (this->WriteToOutputString)
       {
-      if (isalnum(this->FileName[i]))
+      if (!this->OpenString())
         {
-        break;
+        return 0;
         }
-      this->FileName[i] = 0;
       }
-
-    // Try to open the output file for writing.
-#ifdef _WIN32
-    this->OutFile = new ofstream(this->FileName, ios::out | ios::binary);
-#else
-    this->OutFile = new ofstream(this->FileName, ios::out);
-#endif
-    if(!this->OutFile || !*this->OutFile)
+    else
       {
-      vtkErrorMacro("Error opening output file \"" << this->FileName << "\"");
-      this->SetErrorCode(vtkErrorCode::GetLastSystemError());
-      vtkErrorMacro("Error code \""
-                    << vtkErrorCode::GetStringFromErrorCode(this->GetErrorCode()) << "\"");
-      return 0;
+      if (!this->OpenFile())
+        {
+        return 0;
+        }
       }
-    this->Stream = this->OutFile;
     }
 
   // Make sure sufficient precision is used in the ascii
@@ -720,24 +718,103 @@ int vtkXMLWriter::OpenFile()
 }
 
 //----------------------------------------------------------------------------
-void vtkXMLWriter::CloseFile()
+int vtkXMLWriter::OpenFile()
+{
+  if (this->OutFile)
+    {
+    delete this->OutFile;
+    this->OutFile = 0;
+    }
+
+  // Strip trailing whitespace from the filename.
+  int len = static_cast<int>(strlen(this->FileName));
+  for (int i = len-1; i >= 0; i--)
+    {
+    if (isalnum(this->FileName[i]))
+      {
+      break;
+      }
+    this->FileName[i] = 0;
+    }
+
+  // Try to open the output file for writing.
+#ifdef _WIN32
+  this->OutFile = new ofstream(this->FileName, ios::out | ios::binary);
+#else
+  this->OutFile = new ofstream(this->FileName, ios::out);
+#endif
+  if(!this->OutFile || !*this->OutFile)
+    {
+    vtkErrorMacro("Error opening output file \"" << this->FileName << "\"");
+    this->SetErrorCode(vtkErrorCode::GetLastSystemError());
+    vtkErrorMacro("Error code \""
+                  << vtkErrorCode::GetStringFromErrorCode(this->GetErrorCode()) << "\"");
+    return 0;
+    }
+  this->Stream = this->OutFile;
+
+  return 1;
+}
+
+//----------------------------------------------------------------------------
+int vtkXMLWriter::OpenString()
+{
+  if (this->OutStringStream)
+    {
+    delete this->OutStringStream;
+    this->OutStringStream = 0;
+    }
+
+  this->OutStringStream = new vtksys_ios::ostringstream();
+  this->Stream = this->OutStringStream;
+
+  return 1;
+}
+
+//----------------------------------------------------------------------------
+void vtkXMLWriter::CloseStream()
 {
   // Cleanup the output streams.
   this->DataStream->SetStream(0);
 
+  if (this->WriteToOutputString)
+    {
+    this->CloseString();
+    }
+  else
+    {
+    this->CloseFile();
+    }
+
+  this->Stream = 0;
+}
+
+//----------------------------------------------------------------------------
+void vtkXMLWriter::CloseFile()
+{
   if(this->OutFile)
     {
     // We opened a file.  Close it.
     delete this->OutFile;
     this->OutFile = 0;
-    this->Stream = 0;
+    }
+}
+
+//----------------------------------------------------------------------------
+void vtkXMLWriter::CloseString()
+{
+  if(this->OutStringStream)
+    {
+    this->OutputString = this->OutStringStream->str();
+    delete this->OutStringStream;
+    this->OutStringStream = 0;
     }
 }
 
 //----------------------------------------------------------------------------
 int vtkXMLWriter::WriteInternal()
 {
-  if (!this->OpenFile())
+  if (!this->OpenStream())
     {
     return 0;
     }
@@ -750,7 +827,7 @@ int vtkXMLWriter::WriteInternal()
   // if user manipulate execution don't try closing file
   if( this->UserContinueExecuting != 1 )
     {
-    this->CloseFile();
+    this->CloseStream();
     }
 
   return result;
diff --git a/IO/XML/vtkXMLWriter.h b/IO/XML/vtkXMLWriter.h
index 00c8fa9ef2f..f7b82f2ae90 100644
--- a/IO/XML/vtkXMLWriter.h
+++ b/IO/XML/vtkXMLWriter.h
@@ -24,6 +24,7 @@
 
 #include "vtkIOXMLModule.h" // For export macro
 #include "vtkAlgorithm.h"
+#include <vtksys/ios/sstream> // For ostringstream ivar
 
 class vtkAbstractArray;
 class vtkArrayIterator;
@@ -111,6 +112,13 @@ public:
   vtkSetStringMacro(FileName);
   vtkGetStringMacro(FileName);
 
+  // Description:
+  // Enable writing to an OutputString instead of the default, a file.
+  vtkSetMacro(WriteToOutputString,int);
+  vtkGetMacro(WriteToOutputString,int);
+  vtkBooleanMacro(WriteToOutputString,int);
+  std::string GetOutputString() { return this->OutputString; }
+
   // Description:
   // Get/Set the compressor used to compress binary and appended data
   // before writing to the file.  Default is a vtkZLibDataCompressor.
@@ -226,6 +234,13 @@ protected:
   // The output stream to which the XML is written.
   ostream* Stream;
 
+  // Whether this object is writing to a string or a file.
+  // Default is 0: write to file.
+  int WriteToOutputString;
+
+  // The output string.
+  std::string OutputString;
+
   // The output byte order.
   int ByteOrder;
 
@@ -428,9 +443,14 @@ protected:
   float ProgressRange[2];
 
   ofstream* OutFile;
+  vtksys_ios::ostringstream* OutStringStream;
 
+  int OpenStream();
   int OpenFile();
+  int OpenString();
+  void CloseStream();
   void CloseFile();
+  void CloseString();
 
   // The timestep currently being written
   int TimeStep;
-- 
GitLab