1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkXMLWriter.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkXMLWriter.h"
16 
17 #include "vtkArrayIteratorIncludes.h"
18 #include "vtkBase64OutputStream.h"
19 #include "vtkByteSwap.h"
20 #include "vtkCellData.h"
21 #include "vtkCommand.h"
22 #include "vtkDataArray.h"
23 #include "vtkDataArrayIteratorMacro.h"
24 #include "vtkDataSet.h"
25 #include "vtkErrorCode.h"
26 #include "vtkInformation.h"
27 #include "vtkInformationVector.h"
28 #include "vtkOutputStream.h"
29 #include "vtkPointData.h"
30 #include "vtkPoints.h"
31 #include "vtkStdString.h"
32 #include "vtkStreamingDemandDrivenPipeline.h"
33 #include "vtkUnsignedCharArray.h"
34 #include "vtkZLibDataCompressor.h"
35 #define vtkXMLOffsetsManager_DoNotInclude
36 #include "vtkXMLOffsetsManager.h"
37 #undef  vtkXMLOffsetsManager_DoNotInclude
38 #define vtkXMLDataHeaderPrivate_DoNotInclude
39 #include "vtkXMLDataHeaderPrivate.h"
40 #undef vtkXMLDataHeaderPrivate_DoNotInclude
41 #include "vtkXMLDataElement.h"
42 #include "vtkInformationQuadratureSchemeDefinitionVectorKey.h"
43 #include "vtkQuadratureSchemeDefinition.h"
44 #include "vtkInformationStringKey.h"
45 
46 #include <vtksys/auto_ptr.hxx>
47 
48 #include <cassert>
49 #include <string>
50 
51 #if !defined(_WIN32) || defined(__CYGWIN__)
52 # include <unistd.h> /* unlink */
53 #else
54 # include <io.h> /* unlink */
55 #endif
56 
57 #if defined(__BORLANDC__)
58 #include <ctype.h> // isalnum is defined here for some versions of Borland
59 #endif
60 
61 #include <locale> // C++ locale
62 
63 
64 //*****************************************************************************
65 // Friend class to enable access for  template functions to the protected
66 // writer methods.
67 class vtkXMLWriterHelper
68 {
69 public:
SetProgressPartial(vtkXMLWriter * writer,double progress)70  static inline void SetProgressPartial(vtkXMLWriter* writer, double progress)
71    {
72    writer->SetProgressPartial(progress);
73    }
WriteBinaryDataBlock(vtkXMLWriter * writer,unsigned char * in_data,size_t numWords,int wordType)74  static inline int WriteBinaryDataBlock(vtkXMLWriter* writer,
75    unsigned char* in_data, size_t numWords, int wordType)
76    {
77    return writer->WriteBinaryDataBlock(in_data, numWords, wordType);
78    }
GetInt32IdTypeBuffer(vtkXMLWriter * writer)79  static inline void* GetInt32IdTypeBuffer(vtkXMLWriter* writer)
80    {
81    return static_cast<void*>(writer->Int32IdTypeBuffer);
82    }
GetByteSwapBuffer(vtkXMLWriter * writer)83  static inline unsigned char* GetByteSwapBuffer(vtkXMLWriter* writer)
84    {
85    return writer->ByteSwapBuffer;
86    }
87 };
88 
89 //----------------------------------------------------------------------------
90 // Specialize for cases where IterType is ValueType* (common case for
91 // vtkDataArrayTemplate subclasses). The last arg is to help less-robust
92 // compilers decide between the various overloads by making a unfavorable
93 // int-to-long conversion in the IterType overload, making this next
94 // overload more favorable when the iterator is a ValueType*.
95 template <class ValueType>
vtkXMLWriterWriteBinaryDataBlocks(vtkXMLWriter * writer,ValueType * iter,int wordType,size_t memWordSize,size_t outWordSize,size_t numWords,int)96 int vtkXMLWriterWriteBinaryDataBlocks(vtkXMLWriter* writer,
97   ValueType* iter, int wordType, size_t memWordSize, size_t outWordSize,
98   size_t numWords, int)
99 {
100   // generic implementation for fixed component length arrays.
101   size_t blockWords = writer->GetBlockSize()/outWordSize;
102   size_t memBlockSize = blockWords*memWordSize;
103 
104   // Prepare a pointer and counter to move through the data.
105   unsigned char* ptr = reinterpret_cast<unsigned char*>(iter);
106   size_t wordsLeft = numWords;
107 
108   // Do the complete blocks.
109   vtkXMLWriterHelper::SetProgressPartial(writer, 0);
110   int result = 1;
111   while(result && (wordsLeft >= blockWords))
112     {
113     if (!vtkXMLWriterHelper::WriteBinaryDataBlock(writer, ptr, blockWords, wordType))
114       {
115       result = 0;
116       }
117     ptr += memBlockSize;
118     wordsLeft -= blockWords;
119     vtkXMLWriterHelper::SetProgressPartial(writer,
120       static_cast<float>(numWords - wordsLeft) / numWords);
121     }
122 
123   // Do the last partial block if any.
124   if (result && (wordsLeft > 0))
125     {
126     if (!vtkXMLWriterHelper::WriteBinaryDataBlock(writer, ptr, wordsLeft, wordType))
127       {
128       result = 0;
129       }
130     }
131   vtkXMLWriterHelper::SetProgressPartial(writer, 1);
132   return result;
133 }
134 
135 //----------------------------------------------------------------------------
136 // Specialize for cases where IterType is some other type with iterator
137 // semantics (e.g. vtkMappedDataArray iterators):
138 template <class ValueType, class IterType>
vtkXMLWriterWriteBinaryDataBlocks(vtkXMLWriter * writer,IterType iter,int wordType,size_t memWordSize,size_t outWordSize,size_t numWords,long)139 int vtkXMLWriterWriteBinaryDataBlocks(vtkXMLWriter* writer,
140   IterType iter, int wordType, size_t memWordSize, size_t outWordSize,
141   size_t numWords, long)
142 {
143   // generic implementation for fixed component length arrays.
144   size_t blockWords = writer->GetBlockSize()/outWordSize;
145 
146   // Prepare a buffer to move through the data.
147   std::vector<unsigned char> buffer(blockWords * memWordSize);
148   size_t wordsLeft = numWords;
149 
150   if (buffer.empty())
151     {
152     // No data -- bail here, since the calls to buffer[0] below will segfault.
153     return 1;
154     }
155 
156   // Do the complete blocks.
157   vtkXMLWriterHelper::SetProgressPartial(writer, 0);
158   int result = 1;
159   while(result && (wordsLeft >= blockWords))
160     {
161     // Copy data to contiguous buffer:
162     IterType blockEnd = iter + blockWords;
163     ValueType* bufferIter = reinterpret_cast<ValueType*>(&buffer[0]);
164     while (iter != blockEnd)
165       {
166       *bufferIter++ = *iter++;
167       }
168 
169     if (!vtkXMLWriterHelper::WriteBinaryDataBlock(writer, &buffer[0], blockWords,
170                                                  wordType))
171       {
172       result = 0;
173       }
174     wordsLeft -= blockWords;
175     vtkXMLWriterHelper::SetProgressPartial(writer,
176                                            float(numWords-wordsLeft)/numWords);
177     }
178 
179   // Do the last partial block if any.
180   if (result && (wordsLeft > 0))
181     {
182     // Copy data to contiguous buffer:
183     IterType blockEnd = iter + wordsLeft;
184     ValueType* bufferIter = reinterpret_cast<ValueType*>(&buffer[0]);
185     while (iter != blockEnd)
186       {
187       *bufferIter++ = *iter++;
188       }
189 
190     if (!vtkXMLWriterHelper::WriteBinaryDataBlock(writer, &buffer[0], wordsLeft,
191                                                  wordType))
192       {
193       result = 0;
194       }
195     }
196   vtkXMLWriterHelper::SetProgressPartial(writer, 1);
197   return result;
198 }
199 
200 //----------------------------------------------------------------------------
vtkXMLWriterWriteBinaryDataBlocks(vtkXMLWriter * writer,vtkArrayIteratorTemplate<vtkStdString> * iter,int wordType,size_t outWordSize,size_t numStrings,int)201 static int vtkXMLWriterWriteBinaryDataBlocks(
202            vtkXMLWriter* writer, vtkArrayIteratorTemplate<vtkStdString>* iter,
203            int wordType, size_t outWordSize, size_t numStrings, int)
204 {
205   vtkXMLWriterHelper::SetProgressPartial(writer, 0);
206   vtkStdString::value_type* allocated_buffer = 0;
207   vtkStdString::value_type* temp_buffer = 0;
208   if (vtkXMLWriterHelper::GetInt32IdTypeBuffer(writer))
209     {
210     temp_buffer = reinterpret_cast<vtkStdString::value_type*>(
211       vtkXMLWriterHelper::GetInt32IdTypeBuffer(writer));
212     }
213   else if (vtkXMLWriterHelper::GetByteSwapBuffer(writer))
214     {
215     temp_buffer = reinterpret_cast<vtkStdString::value_type*>(
216       vtkXMLWriterHelper::GetByteSwapBuffer(writer));
217     }
218   else
219     {
220     allocated_buffer = new vtkStdString::value_type[writer->GetBlockSize()/outWordSize];
221     temp_buffer = allocated_buffer;
222     }
223 
224   // For string arrays, writing as binary requires that the strings are written
225   // out into a contiguous block. This is essential since the compressor can
226   // only compress complete blocks of data.
227   size_t maxCharsPerBlock = writer->GetBlockSize() / outWordSize;
228 
229   size_t index = 0; // index in string array.
230   int result = 1;
231   vtkIdType stringOffset = 0; // num of chars of string written in pervious block.
232     // this is required since a string may not fit completely in a block.
233 
234   while (result && index < numStrings) // write one block at a time.
235     {
236     size_t cur_offset = 0; // offset into the temp_buffer.
237     while (index < numStrings && cur_offset < maxCharsPerBlock)
238       {
239       vtkStdString &str = iter->GetValue(index);
240       vtkStdString::size_type length = str.size();
241       const char* data = str.c_str();
242       data += stringOffset; // advance by the chars already written.
243       length -= stringOffset;
244       stringOffset = 0;
245       if (length == 0)
246         {
247         // just write the string termination char.
248         temp_buffer[cur_offset++] = 0x0;
249         }
250       else
251         {
252         size_t new_offset = cur_offset + length + 1; // (+1) for termination char.
253         if (new_offset <= maxCharsPerBlock)
254           {
255           memcpy(&temp_buffer[cur_offset], data, length);
256           cur_offset += length;
257           temp_buffer[cur_offset++] = 0x0;
258           }
259         else
260           {
261           size_t bytes_to_copy =  (maxCharsPerBlock - cur_offset);
262           stringOffset = bytes_to_copy;
263           memcpy(&temp_buffer[cur_offset], data, bytes_to_copy);
264           cur_offset += bytes_to_copy;
265           }
266         }
267       index++;
268       }
269     if (cur_offset > 0)
270       {
271       // We have a block of data to write.
272       result = vtkXMLWriterHelper::WriteBinaryDataBlock(writer,
273         reinterpret_cast<unsigned char*>(temp_buffer),
274         cur_offset, wordType);
275       vtkXMLWriterHelper::SetProgressPartial(writer,
276         static_cast<float>(index)/numStrings);
277       }
278     }
279 
280   delete [] allocated_buffer;
281   allocated_buffer = 0;
282 
283   vtkXMLWriterHelper::SetProgressPartial(writer, 1);
284   return result;
285 }
286 //*****************************************************************************
287 
288 vtkCxxSetObjectMacro(vtkXMLWriter, Compressor, vtkDataCompressor);
289 //----------------------------------------------------------------------------
vtkXMLWriter()290 vtkXMLWriter::vtkXMLWriter()
291 {
292   this->FileName = 0;
293   this->Stream = 0;
294   this->WriteToOutputString = 0;
295 
296   // Default binary data mode is base-64 encoding.
297   this->DataStream = vtkBase64OutputStream::New();
298 
299   // Byte order defaults to that of machine.
300 #ifdef VTK_WORDS_BIGENDIAN
301   this->ByteOrder = vtkXMLWriter::BigEndian;
302 #else
303   this->ByteOrder = vtkXMLWriter::LittleEndian;
304 #endif
305   this->HeaderType = vtkXMLWriter::UInt32;
306 
307   // Output vtkIdType size defaults to real size.
308 #ifdef VTK_USE_64BIT_IDS
309   this->IdType = vtkXMLWriter::Int64;
310 #else
311   this->IdType = vtkXMLWriter::Int32;
312 #endif
313 
314   // Initialize compression data.
315   this->BlockSize = 32768; //2^15
316   this->Compressor = vtkZLibDataCompressor::New();
317   this->CompressionHeader = 0;
318   this->Int32IdTypeBuffer = 0;
319   this->ByteSwapBuffer = 0;
320 
321   this->EncodeAppendedData = 1;
322   this->AppendedDataPosition = 0;
323   this->DataMode = vtkXMLWriter::Appended;
324   this->ProgressRange[0] = 0;
325   this->ProgressRange[1] = 1;
326 
327   this->SetNumberOfOutputPorts(0);
328   this->SetNumberOfInputPorts(1);
329 
330   this->OutFile = 0;
331   this->OutStringStream = 0;
332 
333   // Time support
334   this->TimeStep = 0; // By default the file does not have timestep
335   this->TimeStepRange[0] = 0;
336   this->TimeStepRange[1] = 0;
337   this->NumberOfTimeSteps = 1;
338   this->CurrentTimeIndex = 0;
339   this->UserContinueExecuting = -1; //invalid state
340   this->NumberOfTimeValues = NULL;
341   this->FieldDataOM = new OffsetsManagerGroup;
342 }
343 
344 //----------------------------------------------------------------------------
~vtkXMLWriter()345 vtkXMLWriter::~vtkXMLWriter()
346 {
347   this->SetFileName(0);
348   this->DataStream->Delete();
349   this->SetCompressor(0);
350   if (this->OutFile)
351     {
352     delete this->OutFile;
353     this->OutFile = 0;
354     }
355   if (this->OutStringStream)
356     {
357     delete this->OutStringStream;
358     this->OutStringStream = 0;
359     }
360 
361   delete this->FieldDataOM;
362   delete[] this->NumberOfTimeValues;
363 }
364 
365 //----------------------------------------------------------------------------
SetCompressorType(int compressorType)366 void vtkXMLWriter::SetCompressorType(int compressorType)
367 {
368   if (compressorType == NONE)
369     {
370     if (this->Compressor)
371       {
372       this->Compressor->Delete();
373       this->Compressor = 0;
374       this->Modified();
375       }
376     return;
377     }
378 
379   if (compressorType == ZLIB)
380     {
381     if (this->Compressor && !this->Compressor->IsTypeOf("vtkZLibDataCompressor"))
382       {
383       this->Compressor->Delete();
384       }
385 
386     this->Compressor = vtkZLibDataCompressor::New();
387     this->Modified();
388     return;
389     }
390 }
391 
392 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)393 void vtkXMLWriter::PrintSelf(ostream& os, vtkIndent indent)
394 {
395   this->Superclass::PrintSelf(os, indent);
396   os << indent << "FileName: "
397      << (this->FileName? this->FileName:"(none)") << "\n";
398   if (this->ByteOrder == vtkXMLWriter::BigEndian)
399     {
400     os << indent << "ByteOrder: BigEndian\n";
401     }
402   else
403     {
404     os << indent << "ByteOrder: LittleEndian\n";
405     }
406   if (this->IdType == vtkXMLWriter::Int32)
407     {
408     os << indent << "IdType: Int32\n";
409     }
410   else
411     {
412     os << indent << "IdType: Int64\n";
413     }
414   if (this->DataMode == vtkXMLWriter::Ascii)
415     {
416     os << indent << "DataMode: Ascii\n";
417     }
418   else if (this->DataMode == vtkXMLWriter::Binary)
419     {
420     os << indent << "DataMode: Binary\n";
421     }
422   else
423     {
424     os << indent << "DataMode: Appended\n";
425     }
426   if (this->Compressor)
427     {
428     os << indent << "Compressor: " << this->Compressor << "\n";
429     }
430   else
431     {
432     os << indent << "Compressor: (none)\n";
433     }
434   os << indent << "EncodeAppendedData: " << this->EncodeAppendedData << "\n";
435   os << indent << "BlockSize: " << this->BlockSize << "\n";
436   if (this->Stream)
437     {
438     os << indent << "Stream: " << this->Stream << "\n";
439     }
440   else
441     {
442     os << indent << "Stream: (none)\n";
443     }
444   os << indent << "TimeStep:" << this->TimeStep << "\n";
445   os << indent << "NumberOfTimeSteps:" << this->NumberOfTimeSteps << "\n";
446   os << indent << "TimeStepRange:(" << this->TimeStepRange[0] << ","
447                                     << this->TimeStepRange[1] << ")\n";
448 }
449 
450 //----------------------------------------------------------------------------
SetInputData(vtkDataObject * input)451 void vtkXMLWriter::SetInputData(vtkDataObject* input)
452 {
453   this->SetInputData(0, input);
454 }
455 
456 //----------------------------------------------------------------------------
SetInputData(int index,vtkDataObject * input)457 void vtkXMLWriter::SetInputData(int index, vtkDataObject* input)
458 {
459   this->SetInputDataInternal(index, input);
460 }
461 
462 //----------------------------------------------------------------------------
GetInput(int port)463 vtkDataObject* vtkXMLWriter::GetInput(int port)
464 {
465   if (this->GetNumberOfInputConnections(port) < 1)
466     {
467     return 0;
468     }
469   return this->GetExecutive()->GetInputData(port, 0);
470 }
471 
472 //----------------------------------------------------------------------------
SetByteOrderToBigEndian()473 void vtkXMLWriter::SetByteOrderToBigEndian()
474 {
475   this->SetByteOrder(vtkXMLWriter::BigEndian);
476 }
477 
478 //----------------------------------------------------------------------------
SetByteOrderToLittleEndian()479 void vtkXMLWriter::SetByteOrderToLittleEndian()
480 {
481   this->SetByteOrder(vtkXMLWriter::LittleEndian);
482 }
483 
484 //----------------------------------------------------------------------------
SetHeaderType(int t)485 void vtkXMLWriter::SetHeaderType(int t)
486 {
487   if (t != vtkXMLWriter::UInt32 &&
488      t != vtkXMLWriter::UInt64)
489     {
490     vtkErrorMacro(<< this->GetClassName() << " (" << this
491                   << "): cannot set HeaderType to " << t);
492     return;
493     }
494   vtkDebugMacro(<< this->GetClassName() << " (" << this
495                 << "): setting HeaderType to " << t);
496   if (this->HeaderType != t)
497     {
498     this->HeaderType = t;
499     this->Modified();
500     }
501 }
502 
503 //----------------------------------------------------------------------------
SetHeaderTypeToUInt32()504 void vtkXMLWriter::SetHeaderTypeToUInt32()
505 {
506   this->SetHeaderType(vtkXMLWriter::UInt32);
507 }
508 
509 //----------------------------------------------------------------------------
SetHeaderTypeToUInt64()510 void vtkXMLWriter::SetHeaderTypeToUInt64()
511 {
512   this->SetHeaderType(vtkXMLWriter::UInt64);
513 }
514 
515 //----------------------------------------------------------------------------
SetIdType(int t)516 void vtkXMLWriter::SetIdType(int t)
517 {
518 #if !defined(VTK_USE_64BIT_IDS)
519   if (t == vtkXMLWriter::Int64)
520     {
521     vtkErrorMacro("Support for Int64 vtkIdType not compiled in VTK.");
522     return;
523     }
524 #endif
525   vtkDebugMacro(<< this->GetClassName() << " (" << this
526                 << "): setting IdType to " << t);
527   if (this->IdType != t)
528     {
529     this->IdType = t;
530     this->Modified();
531     }
532 }
533 
534 //----------------------------------------------------------------------------
SetIdTypeToInt32()535 void vtkXMLWriter::SetIdTypeToInt32()
536 {
537   this->SetIdType(vtkXMLWriter::Int32);
538 }
539 
540 //----------------------------------------------------------------------------
SetIdTypeToInt64()541 void vtkXMLWriter::SetIdTypeToInt64()
542 {
543   this->SetIdType(vtkXMLWriter::Int64);
544 }
545 
546 //----------------------------------------------------------------------------
SetDataModeToAscii()547 void vtkXMLWriter::SetDataModeToAscii()
548 {
549   this->SetDataMode(vtkXMLWriter::Ascii);
550 }
551 
552 //----------------------------------------------------------------------------
SetDataModeToBinary()553 void vtkXMLWriter::SetDataModeToBinary()
554 {
555   this->SetDataMode(vtkXMLWriter::Binary);
556 }
557 
558 //----------------------------------------------------------------------------
SetDataModeToAppended()559 void vtkXMLWriter::SetDataModeToAppended()
560 {
561   this->SetDataMode(vtkXMLWriter::Appended);
562 }
563 
564 //----------------------------------------------------------------------------
SetBlockSize(size_t blockSize)565 void vtkXMLWriter::SetBlockSize(size_t blockSize)
566 {
567   // Enforce constraints on block size.
568   size_t nbs = blockSize;
569 #if VTK_SIZEOF_DOUBLE > VTK_SIZEOF_ID_TYPE
570   typedef double LargestScalarType;
571 #else
572   typedef vtkIdType LargestScalarType;
573 #endif
574   size_t remainder = nbs % sizeof(LargestScalarType);
575   if (remainder)
576     {
577     nbs -= remainder;
578     if (nbs < sizeof(LargestScalarType))
579       {
580       nbs = sizeof(LargestScalarType);
581       }
582     vtkWarningMacro("BlockSize must be a multiple of "
583                     << int(sizeof(LargestScalarType))
584                     << ".  Using " << nbs << " instead of " << blockSize
585                     << ".");
586     }
587   vtkDebugMacro(<< this->GetClassName() << " (" << this
588                 << "): setting BlockSize to " << nbs);
589   if (this->BlockSize != nbs)
590     {
591     this->BlockSize = nbs;
592     this->Modified();
593     }
594 }
595 
596 //----------------------------------------------------------------------------
ProcessRequest(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)597 int vtkXMLWriter::ProcessRequest(vtkInformation* request,
598                                  vtkInformationVector** inputVector,
599                                  vtkInformationVector* outputVector)
600 {
601   // generate the data
602   if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
603     {
604     return this->RequestData(request, inputVector, outputVector);
605     }
606 
607   return this->Superclass::ProcessRequest(request, inputVector, outputVector);
608 }
609 
610 //----------------------------------------------------------------------------
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))611 int vtkXMLWriter::RequestInformation(
612   vtkInformation *vtkNotUsed(request),
613   vtkInformationVector **inputVector,
614   vtkInformationVector *vtkNotUsed(outputVector))
615 {
616   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
617   if (inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()))
618     {
619     this->NumberOfTimeSteps =
620       inInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
621     }
622 
623   return 1;
624 }
625 
626 //----------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * vtkNotUsed (outputVector))627 int vtkXMLWriter::RequestData(vtkInformation* vtkNotUsed(request),
628                               vtkInformationVector** vtkNotUsed(inputVector) ,
629                               vtkInformationVector* vtkNotUsed(outputVector))
630 {
631   this->SetErrorCode(vtkErrorCode::NoError);
632 
633   // Make sure we have a file to write.
634   if (!this->Stream && !this->FileName && !this->WriteToOutputString)
635     {
636     vtkErrorMacro("Writer called with no FileName set.");
637     this->SetErrorCode(vtkErrorCode::NoFileNameError);
638     return 0;
639     }
640 
641   // We are just starting to write.  Do not call
642   // UpdateProgressDiscrete because we want a 0 progress callback the
643   // first time.
644   this->UpdateProgress(0);
645 
646   // Initialize progress range to entire 0..1 range.
647   float wholeProgressRange[2] = { 0.f, 1.f };
648   this->SetProgressRange(wholeProgressRange, 0, 1);
649 
650   // Check input validity and call the real writing code.
651   int result = this->WriteInternal();
652 
653   // If writing failed, delete the file.
654   if (!result)
655     {
656     vtkErrorMacro("Ran out of disk space; deleting file: " << this->FileName);
657     this->DeleteAFile();
658     }
659 
660   // We have finished writing.
661   this->UpdateProgressDiscrete(1);
662 
663   return result;
664 }
665 //----------------------------------------------------------------------------
Write()666 int vtkXMLWriter::Write()
667 {
668   // Make sure we have input.
669   if (this->GetNumberOfInputConnections(0) < 1)
670     {
671     vtkErrorMacro("No input provided!");
672     return 0;
673     }
674 
675   // always write even if the data hasn't changed
676   this->Modified();
677 
678   this->Update();
679   return 1;
680 }
681 
682 
683 //----------------------------------------------------------------------------
OpenStream()684 int vtkXMLWriter::OpenStream()
685 {
686   if (this->Stream)
687     {
688     // Rewind stream to the beginning.
689     this->Stream->seekp(0);
690     }
691   else
692     {
693     if (this->WriteToOutputString)
694       {
695       if (!this->OpenString())
696         {
697         return 0;
698         }
699       }
700     else
701       {
702       if (!this->OpenFile())
703         {
704         return 0;
705         }
706       }
707     }
708 
709   // Make sure sufficient precision is used in the ascii
710   // representation of data and meta-data.
711   this->Stream->precision(11);
712 
713   // Setup the output streams.
714   this->DataStream->SetStream(this->Stream);
715 
716   return 1;
717 }
718 
719 //----------------------------------------------------------------------------
OpenFile()720 int vtkXMLWriter::OpenFile()
721 {
722   if (this->OutFile)
723     {
724     delete this->OutFile;
725     this->OutFile = 0;
726     }
727 
728   // Strip trailing whitespace from the filename.
729   int len = static_cast<int>(strlen(this->FileName));
730   for (int i = len-1; i >= 0; i--)
731     {
732     if (isalnum(this->FileName[i]))
733       {
734       break;
735       }
736     this->FileName[i] = 0;
737     }
738 
739   // Try to open the output file for writing.
740 #ifdef _WIN32
741   this->OutFile = new ofstream(this->FileName, ios::out | ios::binary);
742 #else
743   this->OutFile = new ofstream(this->FileName, ios::out);
744 #endif
745   if (!this->OutFile || !*this->OutFile)
746     {
747     vtkErrorMacro("Error opening output file \"" << this->FileName << "\"");
748     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
749     vtkErrorMacro("Error code \""
750                   << vtkErrorCode::GetStringFromErrorCode(this->GetErrorCode()) << "\"");
751     return 0;
752     }
753   this->Stream = this->OutFile;
754 
755   return 1;
756 }
757 
758 //----------------------------------------------------------------------------
OpenString()759 int vtkXMLWriter::OpenString()
760 {
761   if (this->OutStringStream)
762     {
763     delete this->OutStringStream;
764     this->OutStringStream = 0;
765     }
766 
767   this->OutStringStream = new vtksys_ios::ostringstream();
768   this->Stream = this->OutStringStream;
769 
770   return 1;
771 }
772 
773 //----------------------------------------------------------------------------
CloseStream()774 void vtkXMLWriter::CloseStream()
775 {
776   // Cleanup the output streams.
777   this->DataStream->SetStream(0);
778 
779   if (this->WriteToOutputString)
780     {
781     this->CloseString();
782     }
783   else
784     {
785     this->CloseFile();
786     }
787 
788   this->Stream = 0;
789 }
790 
791 //----------------------------------------------------------------------------
CloseFile()792 void vtkXMLWriter::CloseFile()
793 {
794   if (this->OutFile)
795     {
796     // We opened a file.  Close it.
797     delete this->OutFile;
798     this->OutFile = 0;
799     }
800 }
801 
802 //----------------------------------------------------------------------------
CloseString()803 void vtkXMLWriter::CloseString()
804 {
805   if (this->OutStringStream)
806     {
807     this->OutputString = this->OutStringStream->str();
808     delete this->OutStringStream;
809     this->OutStringStream = 0;
810     }
811 }
812 
813 //----------------------------------------------------------------------------
WriteInternal()814 int vtkXMLWriter::WriteInternal()
815 {
816   if (!this->OpenStream())
817     {
818     return 0;
819     }
820 
821   (*this->Stream).imbue(std::locale::classic());
822 
823   // Tell the subclass to write the data.
824   int result = this->WriteData();
825 
826   // if user manipulate execution don't try closing file
827   if (this->UserContinueExecuting != 1)
828     {
829     this->CloseStream();
830     }
831 
832   return result;
833 }
834 
835 //----------------------------------------------------------------------------
GetDataSetMajorVersion()836 int vtkXMLWriter::GetDataSetMajorVersion()
837 {
838   return (this->HeaderType == vtkXMLWriter::UInt64) ? 1 : 0;
839 }
840 
841 //----------------------------------------------------------------------------
GetDataSetMinorVersion()842 int vtkXMLWriter::GetDataSetMinorVersion()
843 {
844   return (this->HeaderType == vtkXMLWriter::UInt64) ? 0 : 1;
845 }
846 
847 //----------------------------------------------------------------------------
GetInputAsDataSet()848 vtkDataSet* vtkXMLWriter::GetInputAsDataSet()
849 {
850   return static_cast<vtkDataSet*>(this->GetInput());
851 }
852 
853 //----------------------------------------------------------------------------
StartFile()854 int vtkXMLWriter::StartFile()
855 {
856   ostream& os = *(this->Stream);
857 
858   // If this will really be a valid XML file, put the XML header at
859   // the top.
860   if (this->EncodeAppendedData)
861     {
862     os << "<?xml version=\"1.0\"?>\n";
863     }
864 
865   os.imbue(std::locale::classic());
866 
867   // Open the document-level element.  This will contain the rest of
868   // the elements.
869   os << "<VTKFile";
870   this->WriteFileAttributes();
871   os << ">\n";
872 
873   os.flush();
874   if (os.fail())
875     {
876     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
877     return 0;
878     }
879 
880   return 1;
881 }
882 
883 //----------------------------------------------------------------------------
WriteFileAttributes()884 void vtkXMLWriter::WriteFileAttributes()
885 {
886   ostream& os = *(this->Stream);
887 
888   // Write the file's type.
889   this->WriteStringAttribute("type", this->GetDataSetName());
890 
891   // Write the version number of the file.
892   os << " version=\""
893      << this->GetDataSetMajorVersion()
894      << "."
895      << this->GetDataSetMinorVersion()
896      << "\"";
897 
898 
899   // Write the byte order for the file.
900   if (this->ByteOrder == vtkXMLWriter::BigEndian)
901     {
902     os << " byte_order=\"BigEndian\"";
903     }
904   else
905     {
906     os << " byte_order=\"LittleEndian\"";
907     }
908 
909   // Write the header type for binary data.
910   if (this->HeaderType == vtkXMLWriter::UInt64)
911     {
912     os << " header_type=\"UInt64\"";
913     }
914 #if 0 // future: else if (this->FileMajorVersion >= 1)
915     {
916     os << " header_type=\"UInt32\"";
917     }
918 #endif
919 
920   // Write the compressor that will be used for the file.
921   if (this->Compressor)
922     {
923     os << " compressor=\"" << this->Compressor->GetClassName() << "\"";
924     }
925 }
926 
927 //----------------------------------------------------------------------------
EndFile()928 int vtkXMLWriter::EndFile()
929 {
930   ostream& os = *(this->Stream);
931 
932   // Close the document-level element.
933   os << "</VTKFile>\n";
934 
935   os.flush();
936   if (os.fail())
937     {
938     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
939     return 0;
940     }
941 
942   return 1;
943 }
944 
945 //----------------------------------------------------------------------------
DeleteAFile()946 void vtkXMLWriter::DeleteAFile()
947 {
948   if (!this->Stream && this->FileName)
949     {
950     this->DeleteAFile(this->FileName);
951     }
952 }
953 
954 //----------------------------------------------------------------------------
DeleteAFile(const char * name)955 void vtkXMLWriter::DeleteAFile(const char* name)
956 {
957   unlink(name);
958 }
959 
960 //----------------------------------------------------------------------------
StartAppendedData()961 void vtkXMLWriter::StartAppendedData()
962 {
963   ostream& os = *(this->Stream);
964   os << "  <AppendedData encoding=\""
965      << (this->EncodeAppendedData? "base64" : "raw")
966      << "\">\n";
967   os << "   _";
968   this->AppendedDataPosition = os.tellp();
969 
970   // Setup proper output encoding.
971   if (this->EncodeAppendedData)
972     {
973     vtkBase64OutputStream* base64 = vtkBase64OutputStream::New();
974     this->SetDataStream(base64);
975     base64->Delete();
976     }
977   else
978     {
979     vtkOutputStream* raw = vtkOutputStream::New();
980     this->SetDataStream(raw);
981     raw->Delete();
982     }
983 
984   os.flush();
985   if (os.fail())
986     {
987     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
988     }
989 }
990 
991 //----------------------------------------------------------------------------
EndAppendedData()992 void vtkXMLWriter::EndAppendedData()
993 {
994   ostream& os = *(this->Stream);
995   os << "\n";
996   os << "  </AppendedData>\n";
997 
998   os.flush();
999   if (os.fail())
1000     {
1001     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1002     }
1003 }
1004 
1005 //----------------------------------------------------------------------------
1006 vtkTypeInt64
ReserveAttributeSpace(const char * attr,size_t length)1007 vtkXMLWriter::ReserveAttributeSpace(const char* attr, size_t length)
1008 {
1009   // Save the starting stream position.
1010   ostream& os = *(this->Stream);
1011   vtkTypeInt64 startPosition = os.tellp();
1012 
1013   // By default write an empty valid xml: attr="".  In most case it
1014   // will be overwritten but we guarantee that the xml produced will
1015   // be valid in case we stop writing too early.
1016   os << " " << attr << "=\"\"";
1017 
1018   // Now reserve space for the value.
1019   for (size_t i = 0; i < length; ++i)
1020     {
1021     os << " ";
1022     }
1023 
1024   // Flush the stream to make sure the system tries to write now and
1025   // test for a write error reported by the system.
1026   os.flush();
1027   if (os.fail())
1028     {
1029     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1030     }
1031 
1032   // Return the position at which to write the attribute later.
1033   return startPosition;
1034 }
1035 
1036 //----------------------------------------------------------------------------
GetAppendedDataOffset()1037 vtkTypeInt64 vtkXMLWriter::GetAppendedDataOffset()
1038 {
1039   vtkTypeInt64 pos = this->Stream->tellp();
1040   return (pos - this->AppendedDataPosition);
1041 }
1042 
1043 //----------------------------------------------------------------------------
WriteAppendedDataOffset(vtkTypeInt64 streamPos,vtkTypeInt64 & lastoffset,const char * attr)1044 void vtkXMLWriter::WriteAppendedDataOffset(vtkTypeInt64 streamPos,
1045                                            vtkTypeInt64 &lastoffset,
1046                                            const char* attr)
1047 {
1048   // Write an XML attribute with the given name.  The value is the
1049   // current appended data offset.  Starts writing at the given stream
1050   // position, and returns the ending position.  If attr is 0, writes
1051   // only the double quotes.  In all cases, the final stream position
1052   // is left the same as before the call.
1053   ostream& os = *(this->Stream);
1054   vtkTypeInt64 returnPos = os.tellp();
1055   vtkTypeInt64 offset = returnPos - this->AppendedDataPosition;
1056   lastoffset = offset; //saving result
1057   os.seekp(std::streampos(streamPos));
1058   if (attr)
1059     {
1060     os << " " << attr << "=";
1061     }
1062   os << "\"" << offset << "\"";
1063   os.seekp(std::streampos(returnPos));
1064 
1065   os.flush();
1066   if (os.fail())
1067     {
1068     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1069     }
1070 }
1071 
1072 //----------------------------------------------------------------------------
ForwardAppendedDataOffset(vtkTypeInt64 streamPos,vtkTypeInt64 offset,const char * attr)1073 void vtkXMLWriter::ForwardAppendedDataOffset(
1074   vtkTypeInt64 streamPos, vtkTypeInt64 offset, const char* attr)
1075 {
1076   ostream& os = *(this->Stream);
1077   std::streampos returnPos = os.tellp();
1078   os.seekp(std::streampos(streamPos));
1079   if (attr)
1080     {
1081     os << " " << attr << "=";
1082     }
1083   os << "\"" << offset << "\"";
1084   os.seekp(returnPos);
1085 
1086   os.flush();
1087   if (os.fail())
1088     {
1089     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1090     }
1091 }
1092 
1093 //----------------------------------------------------------------------------
ForwardAppendedDataDouble(vtkTypeInt64 streamPos,double value,const char * attr)1094 void vtkXMLWriter::ForwardAppendedDataDouble(
1095   vtkTypeInt64 streamPos, double value, const char* attr)
1096 {
1097   ostream& os = *(this->Stream);
1098   std::streampos returnPos = os.tellp();
1099   os.seekp(std::streampos(streamPos));
1100   if (attr)
1101     {
1102     os << " " << attr << "=";
1103     }
1104   os << "\"" << value << "\"";
1105   os.seekp(returnPos);
1106 
1107   os.flush();
1108   if (os.fail())
1109     {
1110     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1111     }
1112 }
1113 
1114 //----------------------------------------------------------------------------
WriteBinaryData(vtkAbstractArray * a)1115 int vtkXMLWriter::WriteBinaryData(vtkAbstractArray* a)
1116 {
1117   int wordType = a->GetDataType();
1118   size_t outWordSize = this->GetOutputWordTypeSize(wordType);
1119   size_t data_size = a->GetDataSize();
1120   if (this->Compressor)
1121     {
1122     // Need to compress the data.  Create compression header.  This
1123     // reserves enough space in the output.
1124     if (!this->CreateCompressionHeader(data_size*outWordSize))
1125       {
1126       return 0;
1127       }
1128     // Start writing the data.
1129     int result = this->DataStream->StartWriting();
1130 
1131     // Process the actual data.
1132     if (result && !this->WriteBinaryDataInternal(a))
1133       {
1134       result = 0;
1135       }
1136 
1137     // Finish writing the data.
1138     if (result && !this->DataStream->EndWriting())
1139       {
1140       result = 0;
1141       }
1142 
1143     // Go back and write the real compression header in its proper place.
1144     if (result && !this->WriteCompressionHeader())
1145       {
1146       result = 0;
1147       }
1148 
1149     // Destroy the compression header if it was used.
1150     delete this->CompressionHeader;
1151     this->CompressionHeader = 0;
1152 
1153     return result;
1154     }
1155   else
1156     {
1157     // Start writing the data.
1158     if (!this->DataStream->StartWriting())
1159       {
1160       return 0;
1161       }
1162 
1163     // No data compression.  The header is just the length of the data.
1164     vtksys::auto_ptr<vtkXMLDataHeader>
1165       uh(vtkXMLDataHeader::New(this->HeaderType, 1));
1166     if (!uh->Set(0, data_size*outWordSize))
1167       {
1168       vtkErrorMacro("Array \"" << a->GetName() <<
1169                     "\" is too large.  Set HeaderType to UInt64.");
1170       this->SetErrorCode(vtkErrorCode::FileFormatError);
1171       return 0;
1172       }
1173     this->PerformByteSwap(uh->Data(), uh->WordCount(), uh->WordSize());
1174     int writeRes = this->DataStream->Write(uh->Data(), uh->DataSize());
1175     this->Stream->flush();
1176     if (this->Stream->fail())
1177       {
1178       this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1179       return 0;
1180       }
1181     if (!writeRes)
1182       {
1183       return 0;
1184       }
1185 
1186     // Process the actual data.
1187     if (!this->WriteBinaryDataInternal(a))
1188       {
1189       return 0;
1190       }
1191 
1192     // Finish writing the data.
1193     if (!this->DataStream->EndWriting())
1194       {
1195       return 0;
1196       }
1197     }
1198 
1199   return 1;
1200 }
1201 
1202 //----------------------------------------------------------------------------
WriteBinaryDataInternal(vtkAbstractArray * a)1203 int vtkXMLWriter::WriteBinaryDataInternal(vtkAbstractArray* a)
1204 {
1205   // Break into blocks and handle each one separately.  This allows
1206   // for better random access when reading compressed data and saves
1207   // memory during writing.
1208 
1209   // The size of the blocks written (before compression) is
1210   // this->BlockSize.  We need to support the possibility that the
1211   // size of data in memory and the size on disk are different.  This
1212   // is necessary to allow vtkIdType to be converted to UInt32 for
1213   // writing.
1214 
1215   int wordType = a->GetDataType();
1216   size_t memWordSize = this->GetWordTypeSize(wordType);
1217   size_t outWordSize = this->GetOutputWordTypeSize(wordType);
1218 
1219 #ifdef VTK_USE_64BIT_IDS
1220   // If the type is vtkIdType, it may need to be converted to the type
1221   // requested for output.
1222   if ((wordType == VTK_ID_TYPE) && (this->IdType == vtkXMLWriter::Int32))
1223     {
1224     size_t blockWordsEstimate = this->BlockSize / outWordSize;
1225     this->Int32IdTypeBuffer = new Int32IdType[blockWordsEstimate];
1226     }
1227 #endif
1228 
1229   // Decide if we need to byte swap.
1230 #ifdef VTK_WORDS_BIGENDIAN
1231   if (outWordSize > 1 && this->ByteOrder != vtkXMLWriter::BigEndian)
1232 #else
1233   if (outWordSize > 1 && this->ByteOrder != vtkXMLWriter::LittleEndian)
1234 #endif
1235     {
1236     // We need to byte swap.  Prepare a buffer large enough for one
1237     // block.
1238     if (this->Int32IdTypeBuffer)
1239       {
1240       // Just swap in-place in the converted id-type buffer.
1241       this->ByteSwapBuffer =
1242         reinterpret_cast<unsigned char*>(this->Int32IdTypeBuffer);
1243       }
1244     else
1245       {
1246       // The maximum nlock size if this->BlockSize. The actual data in the block
1247       // may be lesser.
1248       this->ByteSwapBuffer = new unsigned char[this->BlockSize];
1249       }
1250     }
1251   int ret;
1252 
1253   size_t numValues = static_cast<size_t>(a->GetNumberOfComponents() *
1254                                          a->GetNumberOfTuples());
1255   switch (wordType)
1256     {
1257     vtkDataArrayIteratorMacro(a,
1258       ret = vtkXMLWriterWriteBinaryDataBlocks<vtkDAValueType>(
1259         this, vtkDABegin, wordType, memWordSize, outWordSize, numValues, 1)
1260       );
1261     case VTK_STRING:
1262       {
1263       vtkArrayIterator *aiter = a->NewIterator();
1264       vtkArrayIteratorTemplate<vtkStdString> *iter =
1265           vtkArrayIteratorTemplate<vtkStdString>::SafeDownCast(aiter);
1266       if (iter)
1267         {
1268         ret = vtkXMLWriterWriteBinaryDataBlocks(
1269               this, iter, wordType, outWordSize, numValues, 1);
1270         }
1271       else
1272         {
1273         vtkWarningMacro("Unsupported iterator for data type : " << wordType);
1274         ret = 0;
1275         }
1276       aiter->Delete();
1277       }
1278       break;
1279     default:
1280       vtkWarningMacro("Cannot write binary data of type : " << wordType);
1281       ret = 0;
1282     }
1283 
1284   // Free the byte swap buffer if it was allocated.
1285   if (this->ByteSwapBuffer && !this->Int32IdTypeBuffer)
1286     {
1287     delete [] this->ByteSwapBuffer;
1288     this->ByteSwapBuffer = 0;
1289     }
1290 
1291 #ifdef VTK_USE_64BIT_IDS
1292   // Free the id-type conversion buffer if it was allocated.
1293   delete [] this->Int32IdTypeBuffer;
1294   this->Int32IdTypeBuffer = 0;
1295 #endif
1296   return ret;
1297 }
1298 
1299 //----------------------------------------------------------------------------
WriteBinaryDataBlock(unsigned char * in_data,size_t numWords,int wordType)1300 int vtkXMLWriter::WriteBinaryDataBlock(unsigned char* in_data,
1301                                        size_t numWords, int wordType)
1302 {
1303   unsigned char* data = in_data;
1304 #ifdef VTK_USE_64BIT_IDS
1305   // If the type is vtkIdType, it may need to be converted to the type
1306   // requested for output.
1307   if ((wordType == VTK_ID_TYPE) && (this->IdType == vtkXMLWriter::Int32))
1308     {
1309     vtkIdType* idBuffer = reinterpret_cast<vtkIdType*>(in_data);
1310 
1311     for (size_t i = 0; i < numWords; ++i)
1312       {
1313       this->Int32IdTypeBuffer[i] = static_cast<Int32IdType>(idBuffer[i]);
1314       }
1315 
1316     data = reinterpret_cast<unsigned char*>(this->Int32IdTypeBuffer);
1317     }
1318 #endif
1319 
1320   // Get the word size of the data buffer.  This is now the size that
1321   // will be written.
1322   size_t wordSize = this->GetOutputWordTypeSize(wordType);
1323 
1324   // If we need to byte swap, do it now.
1325   if (this->ByteSwapBuffer)
1326     {
1327     // If we are converting vtkIdType to 32-bit integer data, the data
1328     // are already in the byte swap buffer because we share the
1329     // conversion buffer.  Otherwise, we need to copy the data before
1330     // byte swapping.
1331     if (data != this->ByteSwapBuffer)
1332       {
1333       memcpy(this->ByteSwapBuffer, data, numWords*wordSize);
1334       data = this->ByteSwapBuffer;
1335       }
1336     this->PerformByteSwap(this->ByteSwapBuffer, numWords, wordSize);
1337     }
1338 
1339   // Now pass the data to the next write phase.
1340   if (this->Compressor)
1341     {
1342     int res = this->WriteCompressionBlock(data, numWords*wordSize);
1343     this->Stream->flush();
1344     if (this->Stream->fail())
1345       {
1346       this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1347       return 0;
1348       }
1349     return res;
1350     }
1351   else
1352     {
1353     int res = this->DataStream->Write(data, numWords*wordSize);
1354     this->Stream->flush();
1355     if (this->Stream->fail())
1356       {
1357       this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1358       return 0;
1359       }
1360     return res;
1361     }
1362 }
1363 
1364 //----------------------------------------------------------------------------
PerformByteSwap(void * data,size_t numWords,size_t wordSize)1365 void vtkXMLWriter::PerformByteSwap(void* data, size_t numWords,
1366                                    size_t wordSize)
1367 {
1368   char* ptr = static_cast<char*>(data);
1369   if (this->ByteOrder == vtkXMLWriter::BigEndian)
1370     {
1371     switch (wordSize)
1372       {
1373       case 1: break;
1374       case 2: vtkByteSwap::Swap2BERange(ptr, numWords); break;
1375       case 4: vtkByteSwap::Swap4BERange(ptr, numWords); break;
1376       case 8: vtkByteSwap::Swap8BERange(ptr, numWords); break;
1377       default:
1378         vtkErrorMacro("Unsupported data type size " << wordSize);
1379       }
1380     }
1381   else
1382     {
1383     switch (wordSize)
1384       {
1385       case 1: break;
1386       case 2: vtkByteSwap::Swap2LERange(ptr, numWords); break;
1387       case 4: vtkByteSwap::Swap4LERange(ptr, numWords); break;
1388       case 8: vtkByteSwap::Swap8LERange(ptr, numWords); break;
1389       default:
1390         vtkErrorMacro("Unsupported data type size " << wordSize);
1391       }
1392     }
1393 }
1394 
1395 //----------------------------------------------------------------------------
SetDataStream(vtkOutputStream * arg)1396 void vtkXMLWriter::SetDataStream(vtkOutputStream* arg)
1397 {
1398   if (this->DataStream != arg)
1399     {
1400     if (this->DataStream != NULL)
1401       {
1402       this->DataStream->UnRegister(this);
1403       }
1404     this->DataStream = arg;
1405     if (this->DataStream != NULL)
1406       {
1407       this->DataStream->Register(this);
1408       this->DataStream->SetStream(this->Stream);
1409       }
1410     }
1411 }
1412 
1413 //----------------------------------------------------------------------------
CreateCompressionHeader(size_t size)1414 int vtkXMLWriter::CreateCompressionHeader(size_t size)
1415 {
1416   // Allocate and initialize the compression header.
1417   // The format is this:
1418   //  struct header {
1419   //    HeaderType number_of_blocks;
1420   //    HeaderType uncompressed_block_size;
1421   //    HeaderType uncompressed_last_block_size;
1422   //    HeaderType compressed_block_sizes[number_of_blocks];
1423   //  }
1424 
1425   // Find the size and number of blocks.
1426   size_t numFullBlocks = size / this->BlockSize;
1427   size_t lastBlockSize = size % this->BlockSize;
1428   size_t numBlocks = numFullBlocks + (lastBlockSize?1:0);
1429   this->CompressionHeader =
1430     vtkXMLDataHeader::New(this->HeaderType, 3+numBlocks);
1431 
1432   // Write out dummy header data.
1433   this->CompressionHeaderPosition = this->Stream->tellp();
1434   int result = (this->DataStream->StartWriting() &&
1435                 this->DataStream->Write(this->CompressionHeader->Data(),
1436                                         this->CompressionHeader->DataSize()) &&
1437                 this->DataStream->EndWriting());
1438 
1439   this->Stream->flush();
1440   if (this->Stream->fail())
1441     {
1442     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1443     return 0;
1444     }
1445 
1446   // Fill in known header data now.
1447   this->CompressionHeader->Set(0, numBlocks);
1448   this->CompressionHeader->Set(1, this->BlockSize);
1449   this->CompressionHeader->Set(2, lastBlockSize);
1450 
1451   // Initialize counter for block writing.
1452   this->CompressionBlockNumber = 0;
1453 
1454   return result;
1455 }
1456 
1457 //----------------------------------------------------------------------------
WriteCompressionBlock(unsigned char * data,size_t size)1458 int vtkXMLWriter::WriteCompressionBlock(unsigned char* data, size_t size)
1459 {
1460   // Compress the data.
1461   vtkUnsignedCharArray* outputArray = this->Compressor->Compress(data, size);
1462 
1463   // Find the compressed size.
1464   size_t outputSize = outputArray->GetNumberOfTuples();
1465   unsigned char* outputPointer = outputArray->GetPointer(0);
1466 
1467   // Write the compressed data.
1468   int result = this->DataStream->Write(outputPointer, outputSize);
1469   this->Stream->flush();
1470   if (this->Stream->fail())
1471     {
1472     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1473     }
1474 
1475   // Store the resulting compressed size in the compression header.
1476   this->CompressionHeader->Set(3+this->CompressionBlockNumber++, outputSize);
1477 
1478   outputArray->Delete();
1479 
1480   return result;
1481 }
1482 
1483 //----------------------------------------------------------------------------
WriteCompressionHeader()1484 int vtkXMLWriter::WriteCompressionHeader()
1485 {
1486   // Write real compression header back into stream.
1487   std::streampos returnPosition = this->Stream->tellp();
1488 
1489   // Need to byte-swap header.
1490   this->PerformByteSwap(this->CompressionHeader->Data(),
1491                         this->CompressionHeader->WordCount(),
1492                         this->CompressionHeader->WordSize());
1493 
1494   if (!this->Stream->seekp(std::streampos(this->CompressionHeaderPosition)))
1495     { return 0; }
1496   int result = (this->DataStream->StartWriting() &&
1497                 this->DataStream->Write(this->CompressionHeader->Data(),
1498                                         this->CompressionHeader->DataSize()) &&
1499                 this->DataStream->EndWriting());
1500   this->Stream->flush();
1501   if (this->Stream->fail())
1502     {
1503     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1504     return 0;
1505     }
1506 
1507   if (!this->Stream->seekp(returnPosition)) { return 0; }
1508   return result;
1509 }
1510 
1511 //----------------------------------------------------------------------------
GetOutputWordTypeSize(int dataType)1512 size_t vtkXMLWriter::GetOutputWordTypeSize(int dataType)
1513 {
1514 #ifdef VTK_USE_64BIT_IDS
1515   // If the type is vtkIdType, it may need to be converted to the type
1516   // requested for output.
1517   if ((dataType == VTK_ID_TYPE) && (this->IdType == vtkXMLWriter::Int32))
1518     {
1519     return 4;
1520     }
1521 #endif
1522   return this->GetWordTypeSize(dataType);
1523 }
1524 
1525 //----------------------------------------------------------------------------
1526 template <class T>
vtkXMLWriterGetWordTypeSize(T *)1527 size_t vtkXMLWriterGetWordTypeSize(T*)
1528 {
1529   return sizeof(T);
1530 }
1531 
1532 //----------------------------------------------------------------------------
GetWordTypeSize(int dataType)1533 size_t vtkXMLWriter::GetWordTypeSize(int dataType)
1534 {
1535   size_t size = 1;
1536   switch (dataType)
1537     {
1538     vtkTemplateMacro(
1539       size = vtkXMLWriterGetWordTypeSize(static_cast<VTK_TT*>(0)));
1540 
1541     case VTK_STRING:
1542       size = sizeof(vtkStdString::value_type);
1543 
1544     default:
1545       vtkWarningMacro("Unsupported data type: " << dataType);
1546       break;
1547     }
1548   return size;
1549 }
1550 
1551 //----------------------------------------------------------------------------
GetWordTypeName(int dataType)1552 const char* vtkXMLWriter::GetWordTypeName(int dataType)
1553 {
1554   char isSigned = 0;
1555   int size = 0;
1556 
1557   // These string values must match vtkXMLDataElement::GetWordTypeAttribute().
1558   switch (dataType)
1559     {
1560   case VTK_STRING:           return "String";
1561     case VTK_FLOAT:          return "Float32";
1562     case VTK_DOUBLE:         return "Float64";
1563     case VTK_ID_TYPE:
1564       {
1565       switch (this->IdType)
1566         {
1567         case vtkXMLWriter::Int32: return "Int32";
1568         case vtkXMLWriter::Int64: return "Int64";
1569         default: return 0;
1570         }
1571       }
1572 #if VTK_TYPE_CHAR_IS_SIGNED
1573     case VTK_CHAR:           isSigned = 1; size = sizeof(char); break;
1574 #else
1575     case VTK_CHAR:           isSigned = 0; size = sizeof(char); break;
1576 #endif
1577     case VTK_INT:            isSigned = 1; size = sizeof(int); break;
1578     case VTK_LONG:           isSigned = 1; size = sizeof(long); break;
1579     case VTK_SHORT:          isSigned = 1; size = sizeof(short); break;
1580     case VTK_SIGNED_CHAR:    isSigned = 1; size = sizeof(signed char); break;
1581     case VTK_UNSIGNED_CHAR:  isSigned = 0; size = sizeof(unsigned char); break;
1582     case VTK_UNSIGNED_INT:   isSigned = 0; size = sizeof(unsigned int); break;
1583     case VTK_UNSIGNED_LONG:  isSigned = 0; size = sizeof(unsigned long); break;
1584     case VTK_UNSIGNED_SHORT: isSigned = 0; size = sizeof(unsigned short); break;
1585 #if defined(VTK_TYPE_USE_LONG_LONG)
1586     case VTK_LONG_LONG:          isSigned = 1; size = sizeof(long long); break;
1587     case VTK_UNSIGNED_LONG_LONG: isSigned = 0; size = sizeof(unsigned long long); break;
1588 #endif
1589 #if defined(VTK_TYPE_USE___INT64)
1590     case VTK___INT64:            isSigned = 1; size = sizeof(__int64); break;
1591 # if defined(VTK_TYPE_CONVERT_UI64_TO_DOUBLE)
1592     case VTK_UNSIGNED___INT64:   isSigned = 0; size = sizeof(unsigned __int64); break;
1593 # endif
1594 #endif
1595     default:
1596     {
1597     vtkWarningMacro("Unsupported data type: " << dataType); } break;
1598     }
1599   const char* type = 0;
1600   switch (size)
1601     {
1602     case 1: type = isSigned? "Int8"  : "UInt8";  break;
1603     case 2: type = isSigned? "Int16" : "UInt16"; break;
1604     case 4: type = isSigned? "Int32" : "UInt32"; break;
1605     case 8: type = isSigned? "Int64" : "UInt64"; break;
1606     default:
1607       {
1608       vtkErrorMacro("Data type size " << size
1609                     << " not supported by VTK XML format.");
1610       }
1611     }
1612   return type;
1613 }
1614 
1615 //----------------------------------------------------------------------------
1616 template <class T>
vtkXMLWriterWriteVectorAttribute(ostream & os,const char * name,int length,T * data)1617 int vtkXMLWriterWriteVectorAttribute(ostream& os, const char* name,
1618                                      int length, T* data)
1619 {
1620   os << " " << name << "=\"";
1621   if (length)
1622     {
1623     os << data[0];
1624     for (int i = 1; i < length; ++i)
1625       {
1626       os << " " << data[i];
1627       }
1628     }
1629   os << "\"";
1630   return os ? 1 : 0;
1631 }
1632 
1633 //----------------------------------------------------------------------------
WriteScalarAttribute(const char * name,int data)1634 int vtkXMLWriter::WriteScalarAttribute(const char* name, int data)
1635 {
1636   return this->WriteVectorAttribute(name, 1, &data);
1637 }
1638 
1639 //----------------------------------------------------------------------------
WriteScalarAttribute(const char * name,float data)1640 int vtkXMLWriter::WriteScalarAttribute(const char* name, float data)
1641 {
1642   return this->WriteVectorAttribute(name, 1, &data);
1643 }
1644 
1645 //----------------------------------------------------------------------------
WriteScalarAttribute(const char * name,double data)1646 int vtkXMLWriter::WriteScalarAttribute(const char* name, double data)
1647 {
1648   return this->WriteVectorAttribute(name, 1, &data);
1649 }
1650 
1651 //----------------------------------------------------------------------------
1652 #ifdef VTK_USE_64BIT_IDS
WriteScalarAttribute(const char * name,vtkIdType data)1653 int vtkXMLWriter::WriteScalarAttribute(const char* name, vtkIdType data)
1654 {
1655   return this->WriteVectorAttribute(name, 1, &data);
1656 }
1657 #endif
1658 
1659 //----------------------------------------------------------------------------
WriteVectorAttribute(const char * name,int length,int * data)1660 int vtkXMLWriter::WriteVectorAttribute(const char* name, int length,
1661                                        int* data)
1662 {
1663   int res =
1664     vtkXMLWriterWriteVectorAttribute(*(this->Stream), name, length, data);
1665 
1666   this->Stream->flush();
1667   if (this->Stream->fail())
1668     {
1669     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1670     }
1671   return res;
1672 }
1673 
1674 //----------------------------------------------------------------------------
WriteVectorAttribute(const char * name,int length,float * data)1675 int vtkXMLWriter::WriteVectorAttribute(const char* name, int length,
1676                                        float* data)
1677 {
1678   int res =
1679     vtkXMLWriterWriteVectorAttribute(*(this->Stream), name, length, data);
1680 
1681   this->Stream->flush();
1682   if (this->Stream->fail())
1683     {
1684     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1685     }
1686   return res;
1687 }
1688 
1689 //----------------------------------------------------------------------------
WriteVectorAttribute(const char * name,int length,double * data)1690 int vtkXMLWriter::WriteVectorAttribute(const char* name, int length,
1691                                        double* data)
1692 {
1693   int res =
1694     vtkXMLWriterWriteVectorAttribute(*(this->Stream), name, length, data);
1695 
1696   this->Stream->flush();
1697   if (this->Stream->fail())
1698     {
1699     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1700     }
1701   return res;
1702 }
1703 
1704 //----------------------------------------------------------------------------
1705 #ifdef VTK_USE_64BIT_IDS
WriteVectorAttribute(const char * name,int length,vtkIdType * data)1706 int vtkXMLWriter::WriteVectorAttribute(const char* name, int length,
1707                                        vtkIdType* data)
1708 {
1709   int res =
1710     vtkXMLWriterWriteVectorAttribute(*(this->Stream), name, length, data);
1711 
1712   this->Stream->flush();
1713   if (this->Stream->fail())
1714     {
1715     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1716     }
1717   return res;
1718 }
1719 #endif
1720 
1721 //----------------------------------------------------------------------------
WriteDataModeAttribute(const char * name)1722 int vtkXMLWriter::WriteDataModeAttribute(const char* name)
1723 {
1724   ostream& os = *(this->Stream);
1725   os << " " << name << "=\"";
1726   if (this->DataMode == vtkXMLWriter::Appended)
1727     {
1728     os << "appended";
1729     }
1730   else if (this->DataMode == vtkXMLWriter::Binary)
1731     {
1732     os << "binary";
1733     }
1734   else
1735     {
1736     os << "ascii";
1737     }
1738   os << "\"";
1739 
1740   os.flush();
1741   if (os.fail())
1742     {
1743     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1744     }
1745   return (os? 1:0);
1746 }
1747 
1748 //----------------------------------------------------------------------------
WriteWordTypeAttribute(const char * name,int dataType)1749 int vtkXMLWriter::WriteWordTypeAttribute(const char* name, int dataType)
1750 {
1751   ostream& os = *(this->Stream);
1752   const char* value = this->GetWordTypeName(dataType);
1753   if (!value)
1754     {
1755     return 0;
1756     }
1757   os << " " << name << "=\"" << value << "\"";
1758   os.flush();
1759   if (os.fail())
1760     {
1761     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1762     }
1763   return os ? 1 : 0;
1764 }
1765 
1766 //----------------------------------------------------------------------------
WriteStringAttribute(const char * name,const char * value)1767 int vtkXMLWriter::WriteStringAttribute(const char* name, const char* value)
1768 {
1769   ostream& os = *(this->Stream);
1770   os << " " << name << "=\"" << value << "\"";
1771 
1772   os.flush();
1773   if (os.fail())
1774     {
1775     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
1776     }
1777   return os ? 1 : 0;
1778 }
1779 
1780 //----------------------------------------------------------------------------
1781 // This method is provided so that the specialization code for certain types
1782 // can be minimal.
1783 template <class T>
vtkXMLWriteAsciiValue(ostream & os,const T & value)1784 inline ostream& vtkXMLWriteAsciiValue(ostream& os, const T& value)
1785 {
1786   os << value;
1787   return os;
1788 }
1789 
1790 //----------------------------------------------------------------------------
1791 VTK_TEMPLATE_SPECIALIZE
vtkXMLWriteAsciiValue(ostream & os,const char & c)1792 inline ostream& vtkXMLWriteAsciiValue(ostream& os, const char &c)
1793 {
1794   os << short(c);
1795   return os;
1796 }
1797 
1798 //----------------------------------------------------------------------------
1799 VTK_TEMPLATE_SPECIALIZE
vtkXMLWriteAsciiValue(ostream & os,const unsigned char & c)1800 inline ostream& vtkXMLWriteAsciiValue(ostream& os, const unsigned char &c)
1801 {
1802   os << static_cast<unsigned short>(c);
1803   return os;
1804 }
1805 
1806 //----------------------------------------------------------------------------
1807 VTK_TEMPLATE_SPECIALIZE
vtkXMLWriteAsciiValue(ostream & os,const signed char & c)1808 inline ostream& vtkXMLWriteAsciiValue(ostream& os, const signed char &c)
1809 {
1810   os << short(c);
1811   return os;
1812 }
1813 
1814 //----------------------------------------------------------------------------
1815 VTK_TEMPLATE_SPECIALIZE
vtkXMLWriteAsciiValue(ostream & os,const vtkStdString & str)1816 inline ostream& vtkXMLWriteAsciiValue(ostream& os, const vtkStdString& str)
1817 {
1818   vtkStdString::const_iterator iter = str.begin();
1819   vtkXMLWriteAsciiValue(os, *iter);
1820   iter++;
1821   for (; iter != str.end(); ++iter)
1822     {
1823     os << " ";
1824     vtkXMLWriteAsciiValue(os, *iter);
1825     }
1826   os << " ";
1827   char delim = 0x0;
1828   return vtkXMLWriteAsciiValue(os, delim);
1829 }
1830 
1831 //----------------------------------------------------------------------------
1832 template <class iterT>
vtkXMLWriteAsciiData(ostream & os,iterT * iter,vtkIndent indent)1833 int vtkXMLWriteAsciiData(ostream& os, iterT* iter, vtkIndent indent)
1834 {
1835   if (!iter)
1836     {
1837     return 0;
1838     }
1839   size_t columns = 6;
1840   size_t length = iter->GetNumberOfTuples() *
1841     iter->GetNumberOfComponents();
1842 
1843   size_t rows = length / columns;
1844   size_t lastRowLength = length % columns;
1845   vtkIdType index = 0;
1846   for (size_t r = 0; r < rows; ++r)
1847     {
1848     os << indent;
1849     vtkXMLWriteAsciiValue(os, iter->GetValue(index++));
1850     for (size_t c = 1; c < columns; ++c)
1851       {
1852       os << " ";
1853       vtkXMLWriteAsciiValue(os, iter->GetValue(index++));
1854       }
1855     os << "\n";
1856     }
1857   if (lastRowLength > 0)
1858     {
1859     os << indent;
1860     vtkXMLWriteAsciiValue(os, iter->GetValue(index++));
1861     for (size_t c = 1; c < lastRowLength; ++c)
1862       {
1863       os << " " ;
1864     vtkXMLWriteAsciiValue(os, iter->GetValue(index++));
1865       }
1866     os << "\n";
1867     }
1868   return os ? 1 : 0;
1869 }
1870 
1871 //----------------------------------------------------------------------------
WriteAsciiData(vtkAbstractArray * a,vtkIndent indent)1872 int vtkXMLWriter::WriteAsciiData(vtkAbstractArray* a, vtkIndent indent)
1873 {
1874   vtkArrayIterator* iter = a->NewIterator();
1875   ostream& os = *(this->Stream);
1876   int ret;
1877   switch (a->GetDataType())
1878     {
1879     vtkArrayIteratorTemplateMacro(
1880       ret = vtkXMLWriteAsciiData(os, static_cast<VTK_TT*>(iter), indent));
1881     // Why isn't vtkBitArray handled?
1882   default:
1883     ret = 0;
1884     break;
1885     }
1886   iter->Delete();
1887   return ret;
1888 }
1889 
1890 //----------------------------------------------------------------------------
WriteArrayAppended(vtkAbstractArray * a,vtkIndent indent,OffsetsManager & offs,const char * alternateName,int writeNumTuples,int timestep)1891 void vtkXMLWriter::WriteArrayAppended(
1892         vtkAbstractArray* a,
1893         vtkIndent indent,
1894         OffsetsManager &offs,
1895         const char* alternateName,
1896         int writeNumTuples,
1897         int timestep)
1898 {
1899   ostream& os = *(this->Stream);
1900   // Write the header <DataArray or <Array:
1901   this->WriteArrayHeader(a,indent,alternateName, writeNumTuples, timestep);
1902   int shortFormatTag = 1; // close with: />
1903   //
1904   if (vtkDataArray::SafeDownCast(a))
1905     {
1906     // write the scalar range of this data array, we reserver space because we
1907     // don't actually have the data at this point
1908     offs.GetRangeMinPosition(timestep)
1909       = this->ReserveAttributeSpace("RangeMin");
1910     offs.GetRangeMaxPosition(timestep)
1911       = this->ReserveAttributeSpace("RangeMax");
1912     }
1913   else
1914     {
1915     // ranges are not written for non-data arrays.
1916     offs.GetRangeMinPosition(timestep) = -1;
1917     offs.GetRangeMaxPosition(timestep) = -1;
1918     }
1919 
1920   //
1921   offs.GetPosition(timestep) = this->ReserveAttributeSpace("offset");
1922 
1923   // Write information in the recognized keys associated with this array.
1924   vtkInformation *info=a->GetInformation();
1925 
1926   vtkInformationQuadratureSchemeDefinitionVectorKey *dictKey=vtkQuadratureSchemeDefinition::DICTIONARY();
1927   int hasDictKey=info->Has(dictKey);
1928 
1929   vtkInformationStringKey *offsNameKey=vtkQuadratureSchemeDefinition::QUADRATURE_OFFSET_ARRAY_NAME();
1930   int hasOffsNameKey = info->Has(offsNameKey);
1931 
1932   if (hasOffsNameKey || hasDictKey)
1933     {
1934     // close header
1935     // with </DataArray> or </Array>
1936     os << ">" << endl;
1937     shortFormatTag=0;
1938     }
1939 
1940   if (hasDictKey)
1941     {
1942     vtkXMLDataElement *eKey = vtkXMLDataElement::New();
1943     dictKey->SaveState(info,eKey);
1944     eKey->PrintXML(os,indent.GetNextIndent());
1945     eKey->Delete();
1946     }
1947 
1948   if (hasOffsNameKey)
1949     {
1950     vtkXMLDataElement *eKey = vtkXMLDataElement::New();
1951     eKey->SetName("InformationKey");
1952     eKey->SetAttribute("name", "QUADRATURE_OFFSET_ARRAY_NAME");
1953     eKey->SetAttribute("location", "vtkQuadratureSchemeDefinition");
1954     eKey->SetAttribute("value", offsNameKey->Get(info));
1955     eKey->PrintXML(os,indent.GetNextIndent());
1956     eKey->Delete();
1957     }
1958 
1959   // Close tag.
1960   this->WriteArrayFooter(os, indent, a, shortFormatTag);
1961 }
1962 
1963 //----------------------------------------------------------------------------
WriteArrayAppendedData(vtkAbstractArray * a,vtkTypeInt64 pos,vtkTypeInt64 & lastoffset)1964 void vtkXMLWriter::WriteArrayAppendedData(vtkAbstractArray* a,
1965                                           vtkTypeInt64 pos,
1966                                           vtkTypeInt64& lastoffset)
1967 {
1968   this->WriteAppendedDataOffset(pos, lastoffset, "offset");
1969   this->WriteBinaryData(a);
1970 }
1971 
1972 //----------------------------------------------------------------------------
WriteArrayHeader(vtkAbstractArray * a,vtkIndent indent,const char * alternateName,int writeNumTuples,int timestep)1973 void vtkXMLWriter::WriteArrayHeader(vtkAbstractArray* a,  vtkIndent indent,
1974                                         const char* alternateName,
1975                                         int writeNumTuples,
1976                                         int timestep)
1977 {
1978   ostream& os = *(this->Stream);
1979   if (vtkDataArray::SafeDownCast(a))
1980     {
1981     os << indent << "<DataArray";
1982     }
1983   else
1984     {
1985     os << indent << "<Array";
1986     }
1987   this->WriteWordTypeAttribute("type", a->GetDataType());
1988   if (alternateName)
1989     {
1990     this->WriteStringAttribute("Name", alternateName);
1991     }
1992   else if (const char* arrayName = a->GetName())
1993     {
1994     this->WriteStringAttribute("Name", arrayName);
1995     }
1996   else
1997     {
1998     // Generate a name for this array.
1999     vtksys_ios::ostringstream name;
2000     void* p = a;
2001     name << "Array " << p;
2002     this->WriteStringAttribute("Name", name.str().c_str());
2003     }
2004   if (a->GetNumberOfComponents() > 1)
2005     {
2006     this->WriteScalarAttribute("NumberOfComponents",
2007       a->GetNumberOfComponents());
2008     }
2009 
2010   //always write out component names, even if only 1 component
2011   vtksys_ios::ostringstream buff;
2012   const char* compName = NULL;
2013   for (int i = 0; i < a->GetNumberOfComponents(); ++i)
2014     {
2015     //get the component names
2016     buff << "ComponentName" << i;
2017     compName = a->GetComponentName(i);
2018     if (compName)
2019       {
2020       this->WriteStringAttribute(buff.str().c_str(), compName);
2021       compName = NULL;
2022       }
2023     buff.str("");
2024     buff.clear();
2025     }
2026 
2027   if (this->NumberOfTimeSteps > 1)
2028     {
2029     this->WriteScalarAttribute("TimeStep", timestep);
2030     }
2031   else
2032     {
2033     //assert(timestep == -1); //FieldData problem
2034     }
2035   if (writeNumTuples)
2036     {
2037     this->WriteScalarAttribute("NumberOfTuples",
2038       a->GetNumberOfTuples());
2039     }
2040 
2041   this->WriteDataModeAttribute("format");
2042 }
2043 
2044 //----------------------------------------------------------------------------
WriteArrayFooter(ostream & os,vtkIndent indent,vtkAbstractArray * a,int shortFormat)2045 void vtkXMLWriter::WriteArrayFooter(
2046         ostream &os,
2047         vtkIndent indent,
2048         vtkAbstractArray *a,
2049         int shortFormat)
2050 {
2051    // Close the tag: </DataArray>, </Array> or />
2052   if (shortFormat)
2053     {
2054     os << "/>" << endl;
2055     }
2056   else
2057     {
2058     vtkDataArray* da = vtkDataArray::SafeDownCast(a);
2059     os << indent << (da ? "</DataArray>" : "</Array>") << "\n";
2060     }
2061   // Force write and check for errors.
2062   os.flush();
2063   if (os.fail())
2064     {
2065     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2066     }
2067 }
2068 
2069 //----------------------------------------------------------------------------
WriteInlineData(vtkAbstractArray * a,vtkIndent indent)2070 void vtkXMLWriter::WriteInlineData(vtkAbstractArray* a, vtkIndent indent)
2071 {
2072   if (this->DataMode == vtkXMLWriter::Binary)
2073     {
2074     ostream& os = *(this->Stream);
2075     os << indent;
2076     this->WriteBinaryData(a);
2077     os << "\n";
2078     }
2079   else
2080     {
2081     this->WriteAsciiData(a, indent);
2082     }
2083 }
2084 
2085 //----------------------------------------------------------------------------
WriteArrayInline(vtkAbstractArray * a,vtkIndent indent,const char * alternateName,int writeNumTuples)2086 void vtkXMLWriter::WriteArrayInline(
2087         vtkAbstractArray* a,
2088         vtkIndent indent,
2089         const char* alternateName,
2090         int writeNumTuples)
2091 {
2092   ostream& os = *(this->Stream);
2093   // Write the header <DataArray or <Array:
2094   this->WriteArrayHeader(a, indent, alternateName, writeNumTuples, 0);
2095   //
2096   vtkDataArray* da = vtkDataArray::SafeDownCast(a);
2097   if (da)
2098     {
2099     // write the range
2100     this->WriteScalarAttribute("RangeMin",da->GetRange(-1)[0]);
2101     this->WriteScalarAttribute("RangeMax",da->GetRange(-1)[1]);
2102     }
2103   // Close the header
2104   os << ">\n";
2105   // Write recognized information keys associated with this array.
2106   vtkInformation *info=a->GetInformation();
2107   vtkInformationQuadratureSchemeDefinitionVectorKey *key=vtkQuadratureSchemeDefinition::DICTIONARY();
2108   if (info->Has(key))
2109     {
2110     vtkXMLDataElement *eKey=vtkXMLDataElement::New();
2111     key->SaveState(info,eKey);
2112     eKey->PrintXML(os,indent);
2113     eKey->Delete();
2114     }
2115   // Write the inline data.
2116   this->WriteInlineData(a, indent.GetNextIndent());
2117   // Close tag.
2118   this->WriteArrayFooter(os, indent, a, 0);
2119 }
2120 
2121 //----------------------------------------------------------------------------
WriteFieldData(vtkIndent indent)2122 void vtkXMLWriter::WriteFieldData(vtkIndent indent)
2123 {
2124   vtkFieldData *fieldData = this->GetInput()->GetFieldData();
2125   if (!fieldData || !fieldData->GetNumberOfArrays())
2126     {
2127     return;
2128     }
2129 
2130   if (this->DataMode == vtkXMLWriter::Appended)
2131     {
2132     this->WriteFieldDataAppended(fieldData, indent, this->FieldDataOM);
2133     }
2134   else
2135     {
2136     // Write the point data arrays.
2137     this->WriteFieldDataInline(fieldData, indent);
2138     }
2139 }
2140 
2141 //----------------------------------------------------------------------------
WriteFieldDataInline(vtkFieldData * fd,vtkIndent indent)2142 void vtkXMLWriter::WriteFieldDataInline(vtkFieldData* fd, vtkIndent indent)
2143 {
2144   ostream& os = *(this->Stream);
2145   char** names = this->CreateStringArray(fd->GetNumberOfArrays());
2146 
2147   os << indent << "<FieldData>\n";
2148 
2149   float progressRange[2] = { 0.f, 0.f };
2150   this->GetProgressRange(progressRange);
2151   for (int i = 0; i < fd->GetNumberOfArrays(); ++i)
2152     {
2153     this->SetProgressRange(progressRange, i, fd->GetNumberOfArrays());
2154     this->WriteArrayInline(fd->GetAbstractArray(i), indent.GetNextIndent(),
2155       names[i], 1);
2156     if (this->ErrorCode != vtkErrorCode::NoError)
2157       {
2158       this->DestroyStringArray(fd->GetNumberOfArrays(), names);
2159       return;
2160       }
2161     }
2162 
2163   os << indent << "</FieldData>\n";
2164   os.flush();
2165   if (os.fail())
2166     {
2167     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2168     this->DestroyStringArray(fd->GetNumberOfArrays(), names);
2169     return;
2170     }
2171 
2172   this->DestroyStringArray(fd->GetNumberOfArrays(), names);
2173 }
2174 
2175 //----------------------------------------------------------------------------
WritePointDataInline(vtkPointData * pd,vtkIndent indent)2176 void vtkXMLWriter::WritePointDataInline(vtkPointData* pd, vtkIndent indent)
2177 {
2178   ostream& os = *(this->Stream);
2179   char** names = this->CreateStringArray(pd->GetNumberOfArrays());
2180 
2181   os << indent << "<PointData";
2182   this->WriteAttributeIndices(pd, names);
2183 
2184   if (this->ErrorCode != vtkErrorCode::NoError)
2185     {
2186     this->DestroyStringArray(pd->GetNumberOfArrays(), names);
2187     return;
2188     }
2189 
2190   os << ">\n";
2191 
2192   float progressRange[2] = { 0.f, 0.f };
2193   this->GetProgressRange(progressRange);
2194   for (int i = 0; i < pd->GetNumberOfArrays(); ++i)
2195     {
2196     this->SetProgressRange(progressRange, i, pd->GetNumberOfArrays());
2197     vtkAbstractArray* a = pd->GetAbstractArray(i);
2198     this->WriteArrayInline(a, indent.GetNextIndent(), names[i]);
2199     if (this->ErrorCode != vtkErrorCode::NoError)
2200       {
2201       this->DestroyStringArray(pd->GetNumberOfArrays(), names);
2202       return;
2203       }
2204     }
2205 
2206   os << indent << "</PointData>\n";
2207   os.flush();
2208   if (os.fail())
2209     {
2210     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2211     this->DestroyStringArray(pd->GetNumberOfArrays(), names);
2212     return;
2213     }
2214 
2215   this->DestroyStringArray(pd->GetNumberOfArrays(), names);
2216 }
2217 
2218 //----------------------------------------------------------------------------
WriteCellDataInline(vtkCellData * cd,vtkIndent indent)2219 void vtkXMLWriter::WriteCellDataInline(vtkCellData* cd, vtkIndent indent)
2220 {
2221   ostream& os = *(this->Stream);
2222   char** names = this->CreateStringArray(cd->GetNumberOfArrays());
2223 
2224   os << indent << "<CellData";
2225   this->WriteAttributeIndices(cd, names);
2226 
2227   if (this->ErrorCode != vtkErrorCode::NoError)
2228     {
2229     this->DestroyStringArray(cd->GetNumberOfArrays(), names);
2230     return;
2231     }
2232 
2233   os << ">\n";
2234 
2235   float progressRange[2] = { 0.f, 0.f };
2236   this->GetProgressRange(progressRange);
2237   for (int i = 0; i < cd->GetNumberOfArrays(); ++i)
2238     {
2239     this->SetProgressRange(progressRange, i, cd->GetNumberOfArrays());
2240     vtkAbstractArray* a = cd->GetAbstractArray(i);
2241     this->WriteArrayInline(a, indent.GetNextIndent(), names[i]);
2242     if (this->ErrorCode != vtkErrorCode::NoError)
2243       {
2244       this->DestroyStringArray(cd->GetNumberOfArrays(), names);
2245       return;
2246       }
2247     }
2248 
2249   os << indent << "</CellData>\n";
2250   os.flush();
2251   if (os.fail())
2252     {
2253     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2254     this->DestroyStringArray(cd->GetNumberOfArrays(), names);
2255     return;
2256     }
2257 
2258   this->DestroyStringArray(cd->GetNumberOfArrays(), names);
2259 }
2260 
2261 
2262 //----------------------------------------------------------------------------
WriteFieldDataAppended(vtkFieldData * fd,vtkIndent indent,OffsetsManagerGroup * fdManager)2263 void vtkXMLWriter::WriteFieldDataAppended(vtkFieldData* fd,
2264                                           vtkIndent indent,
2265                                           OffsetsManagerGroup *fdManager)
2266 {
2267   ostream& os = *(this->Stream);
2268   char** names = this->CreateStringArray(fd->GetNumberOfArrays());
2269 
2270   os << indent << "<FieldData>\n";
2271 
2272   // When we want to write index arrays with String Arrays, we will
2273   // have to determine the actual arrays written out to the file
2274   // and allocate the fdManager accordingly.
2275   fdManager->Allocate(fd->GetNumberOfArrays());
2276   for (int i = 0; i < fd->GetNumberOfArrays(); ++i)
2277     {
2278     fdManager->GetElement(i).Allocate(1);
2279     this->WriteArrayAppended(fd->GetAbstractArray(i),
2280       indent.GetNextIndent(), fdManager->GetElement(i), names[i], 1 , 0);
2281     if (this->ErrorCode != vtkErrorCode::NoError)
2282       {
2283       this->DestroyStringArray(fd->GetNumberOfArrays(), names);
2284       return;
2285       }
2286     }
2287   os << indent << "</FieldData>\n";
2288 
2289   os.flush();
2290   if (os.fail())
2291     {
2292     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2293     }
2294   this->DestroyStringArray(fd->GetNumberOfArrays(), names);
2295 }
2296 
2297 
2298 
2299 //----------------------------------------------------------------------------
WriteFieldDataAppendedData(vtkFieldData * fd,int timestep,OffsetsManagerGroup * fdManager)2300 void vtkXMLWriter::WriteFieldDataAppendedData(vtkFieldData* fd, int timestep,
2301                                               OffsetsManagerGroup *fdManager)
2302 {
2303   float progressRange[2] = { 0.f, 0.f };
2304   this->GetProgressRange(progressRange);
2305   fdManager->Allocate(fd->GetNumberOfArrays());
2306   for (int i = 0; i < fd->GetNumberOfArrays(); ++i)
2307     {
2308     fdManager->GetElement(i).Allocate(this->NumberOfTimeSteps);
2309     this->SetProgressRange(progressRange, i, fd->GetNumberOfArrays());
2310     this->WriteArrayAppendedData(fd->GetAbstractArray(i),
2311       fdManager->GetElement(i).GetPosition(timestep),
2312       fdManager->GetElement(i).GetOffsetValue(timestep));
2313     vtkDataArray* da = fd->GetArray(i);
2314     if (da)
2315       {
2316       // Write ranges only for data arrays.
2317       double *range = da->GetRange(-1);
2318       this->ForwardAppendedDataDouble
2319         (fdManager->GetElement(i).GetRangeMinPosition(timestep),
2320          range[0], "RangeMin");
2321       this->ForwardAppendedDataDouble
2322         (fdManager->GetElement(i).GetRangeMaxPosition(timestep),
2323          range[1], "RangeMax");
2324       }
2325     if (this->ErrorCode != vtkErrorCode::NoError)
2326       {
2327       return;
2328       }
2329     }
2330 }
2331 
2332 
2333 //----------------------------------------------------------------------------
WritePointDataAppended(vtkPointData * pd,vtkIndent indent,OffsetsManagerGroup * pdManager)2334 void vtkXMLWriter::WritePointDataAppended(vtkPointData* pd, vtkIndent indent,
2335                                           OffsetsManagerGroup *pdManager)
2336 {
2337   ostream& os = *(this->Stream);
2338   char** names = this->CreateStringArray(pd->GetNumberOfArrays());
2339 
2340   os << indent << "<PointData";
2341   this->WriteAttributeIndices(pd, names);
2342 
2343   if (this->ErrorCode != vtkErrorCode::NoError)
2344     {
2345     this->DestroyStringArray(pd->GetNumberOfArrays(), names);
2346     return;
2347     }
2348 
2349   os << ">\n";
2350 
2351   pdManager->Allocate(pd->GetNumberOfArrays());
2352   for (int i = 0; i < pd->GetNumberOfArrays(); ++i)
2353     {
2354     pdManager->GetElement(i).Allocate(this->NumberOfTimeSteps);
2355     for (int t = 0; t < this->NumberOfTimeSteps; ++t)
2356       {
2357       this->WriteArrayAppended(pd->GetAbstractArray(i), indent.GetNextIndent(),
2358         pdManager->GetElement(i), names[i], 0, t);
2359       if (this->ErrorCode != vtkErrorCode::NoError)
2360         {
2361         this->DestroyStringArray(pd->GetNumberOfArrays(), names);
2362         return;
2363         }
2364       }
2365     }
2366 
2367   os << indent << "</PointData>\n";
2368 
2369   os.flush();
2370   if (os.fail())
2371     {
2372     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2373     }
2374   this->DestroyStringArray(pd->GetNumberOfArrays(), names);
2375 }
2376 
2377 //----------------------------------------------------------------------------
WritePointDataAppendedData(vtkPointData * pd,int timestep,OffsetsManagerGroup * pdManager)2378 void vtkXMLWriter::WritePointDataAppendedData(vtkPointData* pd, int timestep,
2379                                               OffsetsManagerGroup *pdManager)
2380 {
2381   float progressRange[2] = { 0.f, 0.f };
2382 
2383   this->GetProgressRange(progressRange);
2384   for (int i = 0; i < pd->GetNumberOfArrays(); ++i)
2385     {
2386     this->SetProgressRange(progressRange, i, pd->GetNumberOfArrays());
2387     unsigned long mtime = pd->GetMTime();
2388     // Only write pd if MTime has changed
2389     unsigned long &pdMTime = pdManager->GetElement(i).GetLastMTime();
2390     vtkAbstractArray* a = pd->GetAbstractArray(i);
2391     if ( pdMTime != mtime )
2392       {
2393       pdMTime = mtime;
2394       this->WriteArrayAppendedData(a,
2395          pdManager->GetElement(i).GetPosition(timestep),
2396          pdManager->GetElement(i).GetOffsetValue(timestep));
2397       if (this->ErrorCode != vtkErrorCode::NoError)
2398         {
2399         return;
2400         }
2401       }
2402     else
2403       {
2404       assert(timestep > 0);
2405       pdManager->GetElement(i).GetOffsetValue(timestep) =
2406         pdManager->GetElement(i).GetOffsetValue(timestep-1);
2407       this->ForwardAppendedDataOffset
2408         (pdManager->GetElement(i).GetPosition(timestep),
2409          pdManager->GetElement(i).GetOffsetValue(timestep), "offset");
2410       }
2411     vtkDataArray* d = vtkDataArray::SafeDownCast(a);
2412     if (d)
2413       {
2414       // ranges are only written in case of Data Arrays.
2415       double *range = d->GetRange(-1);
2416       this->ForwardAppendedDataDouble
2417         (pdManager->GetElement(i).GetRangeMinPosition(timestep),
2418          range[0], "RangeMin");
2419       this->ForwardAppendedDataDouble
2420         (pdManager->GetElement(i).GetRangeMaxPosition(timestep),
2421          range[1], "RangeMax");
2422       }
2423     }
2424 }
2425 
2426 //----------------------------------------------------------------------------
WriteCellDataAppended(vtkCellData * cd,vtkIndent indent,OffsetsManagerGroup * cdManager)2427 void vtkXMLWriter::WriteCellDataAppended(vtkCellData* cd, vtkIndent indent,
2428                                          OffsetsManagerGroup *cdManager)
2429 {
2430   ostream& os = *(this->Stream);
2431   char** names = this->CreateStringArray(cd->GetNumberOfArrays());
2432 
2433   os << indent << "<CellData";
2434   this->WriteAttributeIndices(cd, names);
2435 
2436   if (this->ErrorCode != vtkErrorCode::NoError)
2437     {
2438     this->DestroyStringArray(cd->GetNumberOfArrays(), names);
2439     return;
2440     }
2441 
2442   os << ">\n";
2443 
2444   cdManager->Allocate(cd->GetNumberOfArrays());
2445   for (int i = 0; i < cd->GetNumberOfArrays(); ++i)
2446     {
2447     cdManager->GetElement(i).Allocate(this->NumberOfTimeSteps);
2448     for (int t = 0; t < this->NumberOfTimeSteps; ++t)
2449       {
2450       this->WriteArrayAppended(cd->GetAbstractArray(i), indent.GetNextIndent(),
2451         cdManager->GetElement(i), names[i], 0, t);
2452       if (this->ErrorCode != vtkErrorCode::NoError)
2453         {
2454         this->DestroyStringArray(cd->GetNumberOfArrays(), names);
2455         return;
2456         }
2457       }
2458     }
2459 
2460   os << indent << "</CellData>\n";
2461 
2462   os.flush();
2463   if (os.fail())
2464     {
2465     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2466     }
2467   this->DestroyStringArray(cd->GetNumberOfArrays(), names);
2468 }
2469 
2470 //----------------------------------------------------------------------------
WriteCellDataAppendedData(vtkCellData * cd,int timestep,OffsetsManagerGroup * cdManager)2471 void vtkXMLWriter::WriteCellDataAppendedData(vtkCellData* cd, int timestep,
2472                                              OffsetsManagerGroup *cdManager)
2473 {
2474   float progressRange[2] = { 0.f, 0.f };
2475   this->GetProgressRange(progressRange);
2476 
2477   for (int i = 0; i < cd->GetNumberOfArrays(); ++i)
2478     {
2479     this->SetProgressRange(progressRange, i, cd->GetNumberOfArrays());
2480     unsigned long mtime = cd->GetMTime();
2481     // Only write pd if MTime has changed
2482     unsigned long &cdMTime = cdManager->GetElement(i).GetLastMTime();
2483     vtkAbstractArray* a = cd->GetAbstractArray(i);
2484     if ( cdMTime != mtime )
2485       {
2486       cdMTime = mtime;
2487       this->WriteArrayAppendedData
2488         (a,
2489          cdManager->GetElement(i).GetPosition(timestep),
2490          cdManager->GetElement(i).GetOffsetValue(timestep));
2491       if (this->ErrorCode != vtkErrorCode::NoError)
2492         {
2493         return;
2494         }
2495       }
2496     else
2497       {
2498       assert(timestep > 0);
2499       cdManager->GetElement(i).GetOffsetValue(timestep) =
2500         cdManager->GetElement(i).GetOffsetValue(timestep-1);
2501       this->ForwardAppendedDataOffset(
2502         cdManager->GetElement(i).GetPosition(timestep),
2503         cdManager->GetElement(i).GetOffsetValue(timestep),
2504         "offset");
2505       }
2506     vtkDataArray* d = vtkDataArray::SafeDownCast(a);
2507     if (d)
2508       {
2509       double *range = d->GetRange(-1);
2510       this->ForwardAppendedDataDouble
2511         (cdManager->GetElement(i).GetRangeMinPosition(timestep),
2512          range[0], "RangeMin");
2513       this->ForwardAppendedDataDouble
2514         (cdManager->GetElement(i).GetRangeMaxPosition(timestep),
2515          range[1], "RangeMax");
2516       }
2517     }
2518 }
2519 
2520 //----------------------------------------------------------------------------
WriteAttributeIndices(vtkDataSetAttributes * dsa,char ** names)2521 void vtkXMLWriter::WriteAttributeIndices(vtkDataSetAttributes* dsa,
2522                                          char** names)
2523 {
2524   int attributeIndices[vtkDataSetAttributes::NUM_ATTRIBUTES];
2525   dsa->GetAttributeIndices(attributeIndices);
2526   for (int i = 0; i < vtkDataSetAttributes::NUM_ATTRIBUTES; ++i)
2527     {
2528     if (attributeIndices[i] >= 0)
2529       {
2530       const char* attrName = dsa->GetAttributeTypeAsString(i);
2531       vtkDataArray* a = dsa->GetArray(attributeIndices[i]);
2532       const char* arrayName = a->GetName();
2533       if (!arrayName)
2534         {
2535         // Assign a name to the array.
2536         names[attributeIndices[i]] = new char[strlen(attrName)+2];
2537         strcpy(names[attributeIndices[i]], attrName);
2538         strcat(names[attributeIndices[i]], "_");
2539         arrayName = names[attributeIndices[i]];
2540         }
2541       this->WriteStringAttribute(attrName, arrayName);
2542       if (this->ErrorCode != vtkErrorCode::NoError)
2543         {
2544         return;
2545         }
2546       }
2547     }
2548 }
2549 
2550 //----------------------------------------------------------------------------
WritePointsAppended(vtkPoints * points,vtkIndent indent,OffsetsManager * ptManager)2551 void vtkXMLWriter::WritePointsAppended(vtkPoints* points, vtkIndent indent,
2552                                        OffsetsManager *ptManager)
2553 {
2554   ostream& os = *(this->Stream);
2555 
2556   // Only write points if they exist.
2557   os << indent << "<Points>\n";
2558   if (points)
2559     {
2560     for (int t = 0; t< this->NumberOfTimeSteps; ++t)
2561       {
2562       this->WriteArrayAppended(points->GetData(),
2563         indent.GetNextIndent(), *ptManager, 0, 0, t);
2564       }
2565     }
2566   os << indent << "</Points>\n";
2567 
2568   os.flush();
2569   if (os.fail())
2570     {
2571     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2572     }
2573 }
2574 
2575 //----------------------------------------------------------------------------
WritePointsAppendedData(vtkPoints * points,int timestep,OffsetsManager * ptManager)2576 void vtkXMLWriter::WritePointsAppendedData(vtkPoints* points, int timestep,
2577                                            OffsetsManager *ptManager)
2578 {
2579   // Only write points if they exist.
2580   if (points)
2581     {
2582     unsigned long mtime = points->GetMTime();
2583     // Only write points if MTime has changed
2584     unsigned long &pointsMTime = ptManager->GetLastMTime();
2585     // since points->Data is a vtkDataArray.
2586     vtkDataArray* outPoints = points->GetData();
2587     if ( pointsMTime != mtime || timestep == 0 )
2588       {
2589       pointsMTime = mtime;
2590       this->WriteArrayAppendedData(outPoints,
2591         ptManager->GetPosition(timestep), ptManager->GetOffsetValue(timestep));
2592       }
2593     else
2594       {
2595       assert(timestep > 0);
2596       ptManager->GetOffsetValue(timestep) = ptManager->GetOffsetValue(timestep-1);
2597       this->ForwardAppendedDataOffset(
2598         ptManager->GetPosition(timestep),
2599         ptManager->GetOffsetValue(timestep), "offset");
2600       }
2601     double *range = outPoints->GetRange(-1);
2602     this->ForwardAppendedDataDouble
2603       (ptManager->GetRangeMinPosition(timestep),
2604        range[0], "RangeMin");
2605     this->ForwardAppendedDataDouble
2606       (ptManager->GetRangeMaxPosition(timestep),
2607        range[1], "RangeMax" );
2608     }
2609 }
2610 
2611 //----------------------------------------------------------------------------
WritePointsInline(vtkPoints * points,vtkIndent indent)2612 void vtkXMLWriter::WritePointsInline(vtkPoints* points, vtkIndent indent)
2613 {
2614   ostream& os = *(this->Stream);
2615   // Only write points if they exist.
2616   os << indent << "<Points>\n";
2617   if (points)
2618     {
2619     vtkAbstractArray* outPoints = points->GetData();
2620     this->WriteArrayInline(outPoints, indent.GetNextIndent());
2621     }
2622   os << indent << "</Points>\n";
2623 
2624   os.flush();
2625   if (os.fail())
2626     {
2627     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2628     }
2629 }
2630 
2631 //----------------------------------------------------------------------------
WriteCoordinatesInline(vtkDataArray * xc,vtkDataArray * yc,vtkDataArray * zc,vtkIndent indent)2632 void vtkXMLWriter::WriteCoordinatesInline(vtkDataArray* xc, vtkDataArray* yc,
2633                                           vtkDataArray* zc, vtkIndent indent)
2634 {
2635   ostream& os = *(this->Stream);
2636 
2637   // Only write coordinates if they exist.
2638   os << indent << "<Coordinates>\n";
2639   if (xc && yc && zc)
2640     {
2641 
2642     // Split progress over the three coordinates arrays.
2643     vtkIdType total = (xc->GetNumberOfTuples()+
2644                        yc->GetNumberOfTuples()+
2645                        zc->GetNumberOfTuples());
2646     if (total == 0)
2647       {
2648       total = 1;
2649       }
2650     float fractions[4] =
2651       {
2652         0,
2653         float(xc->GetNumberOfTuples()) / total,
2654         float(xc->GetNumberOfTuples()+yc->GetNumberOfTuples()) / total,
2655         1
2656       };
2657     float progressRange[2] = { 0.f, 0.f };
2658     this->GetProgressRange(progressRange);
2659 
2660     this->SetProgressRange(progressRange, 0, fractions);
2661     this->WriteArrayInline(xc, indent.GetNextIndent());
2662     if (this->ErrorCode != vtkErrorCode::NoError)
2663       {
2664       return;
2665       }
2666 
2667     this->SetProgressRange(progressRange, 1, fractions);
2668     this->WriteArrayInline(yc, indent.GetNextIndent());
2669     if (this->ErrorCode != vtkErrorCode::NoError)
2670       {
2671       return;
2672       }
2673 
2674     this->SetProgressRange(progressRange, 2, fractions);
2675     this->WriteArrayInline(zc, indent.GetNextIndent());
2676     if (this->ErrorCode != vtkErrorCode::NoError)
2677       {
2678       return;
2679       }
2680 
2681     }
2682   os << indent << "</Coordinates>\n";
2683 
2684   os.flush();
2685   if (os.fail())
2686     {
2687     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2688     return;
2689     }
2690 }
2691 
2692 //----------------------------------------------------------------------------
2693 void
WriteCoordinatesAppended(vtkDataArray * xc,vtkDataArray * yc,vtkDataArray * zc,vtkIndent indent,OffsetsManagerGroup * coordManager)2694 vtkXMLWriter::WriteCoordinatesAppended(vtkDataArray* xc, vtkDataArray* yc,
2695                                        vtkDataArray* zc, vtkIndent indent,
2696                                        OffsetsManagerGroup *coordManager)
2697 {
2698   ostream& os = *(this->Stream);
2699 
2700   // Helper for the 'for' loop
2701   vtkDataArray *allcoords[3];
2702   allcoords[0] = xc;
2703   allcoords[1] = yc;
2704   allcoords[2] = zc;
2705 
2706   // Only write coordinates if they exist.
2707   os << indent << "<Coordinates>\n";
2708   coordManager->Allocate(3);
2709   if (xc && yc && zc)
2710     {
2711     for (int i = 0; i < 3; ++i)
2712       {
2713       coordManager->GetElement(i).Allocate(this->NumberOfTimeSteps);
2714       for (int t = 0; t < this->NumberOfTimeSteps; ++t)
2715         {
2716         this->WriteArrayAppended(allcoords[i], indent.GetNextIndent(),
2717           coordManager->GetElement(i), 0, 0, t);
2718         if (this->ErrorCode != vtkErrorCode::NoError)
2719           {
2720           return ;
2721           }
2722         }
2723       }
2724     }
2725   os << indent << "</Coordinates>\n";
2726   os.flush();
2727   if (os.fail())
2728     {
2729     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2730     }
2731 }
2732 
2733 //----------------------------------------------------------------------------
WriteCoordinatesAppendedData(vtkDataArray * xc,vtkDataArray * yc,vtkDataArray * zc,int timestep,OffsetsManagerGroup * coordManager)2734 void vtkXMLWriter::WriteCoordinatesAppendedData(vtkDataArray* xc, vtkDataArray* yc,
2735                                                 vtkDataArray* zc, int timestep,
2736                                                 OffsetsManagerGroup *coordManager)
2737 {
2738   // Only write coordinates if they exist.
2739   if (xc && yc && zc)
2740     {
2741     // Split progress over the three coordinates arrays.
2742     vtkIdType total = (xc->GetNumberOfTuples()+
2743                        yc->GetNumberOfTuples()+
2744                        zc->GetNumberOfTuples());
2745     if (total == 0)
2746       {
2747       total = 1;
2748       }
2749     float fractions[4] =
2750       {
2751         0,
2752         float(xc->GetNumberOfTuples()) / total,
2753         float(xc->GetNumberOfTuples()+yc->GetNumberOfTuples()) / total,
2754         1
2755       };
2756     float progressRange[2] = { 0.f, 0.f };
2757     this->GetProgressRange(progressRange);
2758 
2759     // Helper for the 'for' loop
2760     vtkDataArray *allcoords[3];
2761     allcoords[0] = xc;
2762     allcoords[1] = yc;
2763     allcoords[2] = zc;
2764 
2765     for (int i = 0; i < 3; ++i)
2766       {
2767       this->SetProgressRange(progressRange, i, fractions);
2768       unsigned long mtime = allcoords[i]->GetMTime();
2769       // Only write pd if MTime has changed
2770       unsigned long &coordMTime = coordManager->GetElement(i).GetLastMTime();
2771       if (coordMTime != mtime)
2772         {
2773         coordMTime = mtime;
2774         this->WriteArrayAppendedData(allcoords[i],
2775           coordManager->GetElement(i).GetPosition(timestep),
2776           coordManager->GetElement(i).GetOffsetValue(timestep));
2777         if (this->ErrorCode != vtkErrorCode::NoError)
2778           {
2779           return;
2780           }
2781         }
2782       else
2783         {
2784         }
2785       }
2786     }
2787 }
2788 
2789 //----------------------------------------------------------------------------
WritePPointData(vtkPointData * pd,vtkIndent indent)2790 void vtkXMLWriter::WritePPointData(vtkPointData* pd, vtkIndent indent)
2791 {
2792   if (pd->GetNumberOfArrays() == 0)
2793     {
2794     return;
2795     }
2796   ostream& os = *(this->Stream);
2797   char** names = this->CreateStringArray(pd->GetNumberOfArrays());
2798 
2799   os << indent << "<PPointData";
2800   this->WriteAttributeIndices(pd, names);
2801   if (this->ErrorCode != vtkErrorCode::NoError)
2802     {
2803     this->DestroyStringArray(pd->GetNumberOfArrays(), names);
2804     return;
2805     }
2806   os << ">\n";
2807 
2808   for (int i = 0; i < pd->GetNumberOfArrays(); ++i)
2809     {
2810     this->WritePArray(pd->GetAbstractArray(i), indent.GetNextIndent(), names[i]);
2811     if (this->ErrorCode != vtkErrorCode::NoError)
2812       {
2813       this->DestroyStringArray(pd->GetNumberOfArrays(), names);
2814       return;
2815       }
2816     }
2817 
2818   os << indent << "</PPointData>\n";
2819   os.flush();
2820   if (os.fail())
2821     {
2822     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2823     }
2824 
2825   this->DestroyStringArray(pd->GetNumberOfArrays(), names);
2826 }
2827 
2828 //----------------------------------------------------------------------------
WritePCellData(vtkCellData * cd,vtkIndent indent)2829 void vtkXMLWriter::WritePCellData(vtkCellData* cd, vtkIndent indent)
2830 {
2831   if (cd->GetNumberOfArrays() == 0)
2832     {
2833     return;
2834     }
2835   ostream& os = *(this->Stream);
2836   char** names = this->CreateStringArray(cd->GetNumberOfArrays());
2837 
2838   os << indent << "<PCellData";
2839   this->WriteAttributeIndices(cd, names);
2840   os << ">\n";
2841 
2842   for (int i = 0; i < cd->GetNumberOfArrays(); ++i)
2843     {
2844     this->WritePArray(cd->GetAbstractArray(i), indent.GetNextIndent(), names[i]);
2845     }
2846 
2847   os << indent << "</PCellData>\n";
2848 
2849   this->DestroyStringArray(cd->GetNumberOfArrays(), names);
2850 }
2851 
2852 //----------------------------------------------------------------------------
WritePPoints(vtkPoints * points,vtkIndent indent)2853 void vtkXMLWriter::WritePPoints(vtkPoints* points, vtkIndent indent)
2854 {
2855   ostream& os = *(this->Stream);
2856   // Only write points if they exist.
2857   os << indent << "<PPoints>\n";
2858   if (points)
2859     {
2860     this->WritePArray(points->GetData(), indent.GetNextIndent());
2861     }
2862   os << indent << "</PPoints>\n";
2863   os.flush();
2864   if (os.fail())
2865     {
2866     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2867     }
2868 }
2869 
2870 //----------------------------------------------------------------------------
WritePArray(vtkAbstractArray * a,vtkIndent indent,const char * alternateName)2871 void vtkXMLWriter::WritePArray(vtkAbstractArray* a, vtkIndent indent,
2872                                    const char* alternateName)
2873 {
2874   vtkDataArray* d = vtkDataArray::SafeDownCast(a);
2875   ostream& os = *(this->Stream);
2876   if (d)
2877     {
2878     os << indent << "<PDataArray";
2879     }
2880   else
2881     {
2882     os << indent << "<PArray";
2883     }
2884   this->WriteWordTypeAttribute("type", a->GetDataType());
2885   if (alternateName)
2886     {
2887     this->WriteStringAttribute("Name", alternateName);
2888     }
2889   else
2890     {
2891     const char* arrayName = a->GetName();
2892     if (arrayName)
2893       {
2894       this->WriteStringAttribute("Name", arrayName);
2895       }
2896     }
2897   if (a->GetNumberOfComponents() > 1)
2898     {
2899     this->WriteScalarAttribute("NumberOfComponents",
2900                                a->GetNumberOfComponents());
2901     }
2902   os << "/>\n";
2903 
2904   os.flush();
2905   if (os.fail())
2906     {
2907     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2908     }
2909 }
2910 
2911 //----------------------------------------------------------------------------
WritePCoordinates(vtkDataArray * xc,vtkDataArray * yc,vtkDataArray * zc,vtkIndent indent)2912 void vtkXMLWriter::WritePCoordinates(vtkDataArray* xc, vtkDataArray* yc,
2913                                      vtkDataArray* zc, vtkIndent indent)
2914 {
2915   ostream& os = *(this->Stream);
2916 
2917   // Only write coordinates if they exist.
2918   os << indent << "<PCoordinates>\n";
2919   if (xc && yc && zc)
2920     {
2921     this->WritePArray(xc, indent.GetNextIndent());
2922     if (this->ErrorCode != vtkErrorCode::NoError)
2923       {
2924       return;
2925       }
2926     this->WritePArray(yc, indent.GetNextIndent());
2927     if (this->ErrorCode != vtkErrorCode::NoError)
2928       {
2929       return;
2930       }
2931     this->WritePArray(zc, indent.GetNextIndent());
2932     if (this->ErrorCode != vtkErrorCode::NoError)
2933       {
2934       return;
2935       }
2936     }
2937   os << indent << "</PCoordinates>\n";
2938   os.flush();
2939   if (os.fail())
2940     {
2941     this->SetErrorCode(vtkErrorCode::GetLastSystemError());
2942     }
2943 }
2944 
2945 //----------------------------------------------------------------------------
CreateStringArray(int numStrings)2946 char** vtkXMLWriter::CreateStringArray(int numStrings)
2947 {
2948   char** strings = new char*[numStrings];
2949   for (int i = 0; i < numStrings; ++i)
2950     {
2951     strings[i] = 0;
2952     }
2953   return strings;
2954 }
2955 
2956 //----------------------------------------------------------------------------
DestroyStringArray(int numStrings,char ** strings)2957 void vtkXMLWriter::DestroyStringArray(int numStrings, char** strings)
2958 {
2959   for (int i = 0; i < numStrings; ++i)
2960     {
2961     delete [] strings[i];
2962     }
2963   delete [] strings;
2964 }
2965 
2966 //----------------------------------------------------------------------------
GetProgressRange(float range[2])2967 void vtkXMLWriter::GetProgressRange(float range[2])
2968 {
2969   range[0] = this->ProgressRange[0];
2970   range[1] = this->ProgressRange[1];
2971 }
2972 
2973 //----------------------------------------------------------------------------
SetProgressRange(const float range[2],int curStep,int numSteps)2974 void vtkXMLWriter::SetProgressRange(const float range[2], int curStep, int numSteps)
2975 {
2976   float stepSize = (range[1] - range[0])/numSteps;
2977   this->ProgressRange[0] = range[0] + stepSize*curStep;
2978   this->ProgressRange[1] = range[0] + stepSize*(curStep+1);
2979   this->UpdateProgressDiscrete(this->ProgressRange[0]);
2980 }
2981 
2982 //----------------------------------------------------------------------------
SetProgressRange(const float range[2],int curStep,const float * fractions)2983 void vtkXMLWriter::SetProgressRange(const float range[2], int curStep,
2984                                     const float* fractions)
2985 {
2986   float width = range[1] - range[0];
2987   this->ProgressRange[0] = range[0] + fractions[curStep]*width;
2988   this->ProgressRange[1] = range[0] + fractions[curStep+1]*width;
2989   this->UpdateProgressDiscrete(this->ProgressRange[0]);
2990 }
2991 
2992 //----------------------------------------------------------------------------
SetProgressPartial(float fraction)2993 void vtkXMLWriter::SetProgressPartial(float fraction)
2994 {
2995   float width = this->ProgressRange[1] - this->ProgressRange[0];
2996   this->UpdateProgressDiscrete(this->ProgressRange[0] + fraction*width);
2997 }
2998 
2999 //----------------------------------------------------------------------------
UpdateProgressDiscrete(float progress)3000 void vtkXMLWriter::UpdateProgressDiscrete(float progress)
3001 {
3002   if (!this->AbortExecute)
3003     {
3004     // Round progress to nearest 100th.
3005     float rounded = static_cast<float>(
3006       static_cast<int>((progress * 100) + 0.5f)) / 100.f;
3007     if (this->GetProgress() != rounded)
3008       {
3009       this->UpdateProgress(rounded);
3010       }
3011     }
3012 }
3013 
3014 //----------------------------------------------------------------------------
WritePrimaryElementAttributes(ostream & os,vtkIndent indent)3015 void vtkXMLWriter::WritePrimaryElementAttributes(ostream &os, vtkIndent indent)
3016 {
3017   // Write the time step if any:
3018   if (this->NumberOfTimeSteps > 1)
3019     {
3020     // First thing allocate NumberOfTimeValues
3021     assert(this->NumberOfTimeValues == NULL);
3022     this->NumberOfTimeValues = new vtkTypeInt64[this->NumberOfTimeSteps];
3023     os << indent << "TimeValues=\"\n";
3024 
3025     std::string blankline = std::string(40, ' '); //enough room for precision
3026     for (int i = 0; i < this->NumberOfTimeSteps; i++)
3027       {
3028       this->NumberOfTimeValues[i] = os.tellp();
3029       os << blankline.c_str() << "\n";
3030       }
3031     os << "\"";
3032     }
3033 }
3034 
3035 //----------------------------------------------------------------------------
WritePrimaryElement(ostream & os,vtkIndent indent)3036 int vtkXMLWriter::WritePrimaryElement(ostream &os, vtkIndent indent)
3037 {
3038   // Open the primary element.
3039   os << indent << "<" << this->GetDataSetName();
3040 
3041   this->WritePrimaryElementAttributes(os, indent);
3042 
3043   // Close the primary element:
3044   os << ">\n";
3045   os.flush();
3046   if (os.fail())
3047     {
3048     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
3049     return 0;
3050     }
3051   return 1;
3052 }
3053 
3054 // The following function are designed to be called outside of the VTK pipeline
3055 // typically from a C interface or when ParaView want to control the writing
3056 //----------------------------------------------------------------------------
Start()3057 void vtkXMLWriter::Start()
3058 {
3059   // Make sure we have input.
3060   if (this->GetNumberOfInputConnections(0) < 1)
3061     {
3062     vtkErrorMacro("No input provided!");
3063     return;
3064     }
3065   this->UserContinueExecuting = 1;
3066 }
3067 
3068 //----------------------------------------------------------------------------
3069 // The function does not make sense in the general case but we need to handle
3070 // the case where the simulation stop before reaching the number of steps
3071 // specified by the user. Therefore the CurrentTimeIndex is never equal
3072 // to NumberOfTimeStep and thus we need to force closing of the xml file
Stop()3073 void vtkXMLWriter::Stop()
3074 {
3075   this->UserContinueExecuting = 0;
3076   this->Modified();
3077   this->Update();
3078   this->UserContinueExecuting = -1; //put back the writer in initial state
3079 }
3080 
3081 //----------------------------------------------------------------------------
WriteNextTime(double time)3082 void vtkXMLWriter::WriteNextTime(double time)
3083 {
3084   this->Modified();
3085   this->Update();
3086 
3087   ostream& os = *(this->Stream);
3088 
3089   if (this->NumberOfTimeValues)
3090     {
3091     // Write user specified time value in the TimeValues attribute
3092     std::streampos returnPos = os.tellp();
3093     vtkTypeInt64 t = this->NumberOfTimeValues[this->CurrentTimeIndex-1];
3094     os.seekp(std::streampos(t));
3095     os << time;
3096     os.seekp(returnPos);
3097     }
3098 }
3099