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