/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkXMLWriter.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkXMLWriter.h" #include "vtkBase64OutputStream.h" #include "vtkByteSwap.h" #include "vtkCellData.h" #include "vtkCommand.h" #include "vtkDataArray.h" #include "vtkDataSet.h" #include "vtkErrorCode.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkOutputStream.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkUnsignedCharArray.h" #include "vtkZLibDataCompressor.h" #define vtkOffsetsManager_DoNotInclude #include "vtkOffsetsManagerArray.h" #undef vtkOffsetsManager_DoNotInclude #include #include #include #if !defined(_WIN32) || defined(__CYGWIN__) # include /* unlink */ #else # include /* unlink */ #endif vtkCxxRevisionMacro(vtkXMLWriter, "$Revision: 1.58.2.4 $"); vtkCxxSetObjectMacro(vtkXMLWriter, Compressor, vtkDataCompressor); //---------------------------------------------------------------------------- vtkXMLWriter::vtkXMLWriter() { this->FileName = 0; this->Stream = 0; // Default binary data mode is base-64 encoding. this->DataStream = vtkBase64OutputStream::New(); // Byte order defaults to that of machine. #ifdef VTK_WORDS_BIGENDIAN this->ByteOrder = vtkXMLWriter::BigEndian; #else this->ByteOrder = vtkXMLWriter::LittleEndian; #endif // Output vtkIdType size defaults to real size. #ifdef VTK_USE_64BIT_IDS this->IdType = vtkXMLWriter::Int64; #else this->IdType = vtkXMLWriter::Int32; #endif // Initialize compression data. this->BlockSize = 32768; //2^15 this->Compressor = vtkZLibDataCompressor::New(); this->CompressionHeader = 0; this->Int32IdTypeBuffer = 0; this->ByteSwapBuffer = 0; this->EncodeAppendedData = 1; this->AppendedDataPosition = 0; this->DataMode = vtkXMLWriter::Appended; this->ProgressRange[0] = 0; this->ProgressRange[1] = 1; this->SetNumberOfOutputPorts(0); this->SetNumberOfInputPorts(1); this->OutFile = 0; // Time support this->TimeStep = 0; // By default the file does not have timestep this->TimeStepRange[0] = 0; this->TimeStepRange[1] = 0; this->NumberOfTimeSteps = 1; this->CurrentTimeIndex = 0; this->UserContinueExecuting = -1; //invalid state this->NumberOfTimeValues = NULL; this->FieldDataOM = new OffsetsManagerGroup; } //---------------------------------------------------------------------------- vtkXMLWriter::~vtkXMLWriter() { this->SetFileName(0); this->DataStream->Delete(); this->SetCompressor(0); delete this->OutFile; delete this->FieldDataOM; delete[] this->NumberOfTimeValues; } //---------------------------------------------------------------------------- void vtkXMLWriter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "FileName: " << (this->FileName? this->FileName:"(none)") << "\n"; if(this->ByteOrder == vtkXMLWriter::BigEndian) { os << indent << "ByteOrder: BigEndian\n"; } else { os << indent << "ByteOrder: LittleEndian\n"; } if(this->IdType == vtkXMLWriter::Int32) { os << indent << "IdType: Int32\n"; } else { os << indent << "IdType: Int64\n"; } if(this->DataMode == vtkXMLWriter::Ascii) { os << indent << "DataMode: Ascii\n"; } else if(this->DataMode == vtkXMLWriter::Binary) { os << indent << "DataMode: Binary\n"; } else { os << indent << "DataMode: Appended\n"; } if(this->Compressor) { os << indent << "Compressor: " << this->Compressor << "\n"; } else { os << indent << "Compressor: (none)\n"; } os << indent << "EncodeAppendedData: " << this->EncodeAppendedData << "\n"; os << indent << "BlockSize: " << this->BlockSize << "\n"; if(this->Stream) { os << indent << "Stream: " << this->Stream << "\n"; } else { os << indent << "Stream: (none)\n"; } os << indent << "TimeStep:" << this->TimeStep << "\n"; os << indent << "NumberOfTimeSteps:" << this->NumberOfTimeSteps << "\n"; os << indent << "TimeStepRange:(" << this->TimeStepRange[0] << "," << this->TimeStepRange[1] << ")\n"; } //---------------------------------------------------------------------------- void vtkXMLWriter::SetInput(vtkDataObject* input) { this->SetInput(0, input); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetInput(int index, vtkDataObject* input) { if(input) { this->SetInputConnection(index, input->GetProducerPort()); } else { // Setting a NULL input removes the connection. this->SetInputConnection(index, 0); } } //---------------------------------------------------------------------------- vtkDataObject* vtkXMLWriter::GetInput(int port) { if (this->GetNumberOfInputConnections(port) < 1) { return 0; } return this->GetExecutive()->GetInputData(port, 0); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetByteOrderToBigEndian() { this->SetByteOrder(vtkXMLWriter::BigEndian); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetByteOrderToLittleEndian() { this->SetByteOrder(vtkXMLWriter::LittleEndian); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetIdType(int t) { #if !defined(VTK_USE_64BIT_IDS) if(t == vtkXMLWriter::Int64) { vtkErrorMacro("Support for Int64 vtkIdType not compiled in VTK."); return; } #endif vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting IdType to " << t); if(this->IdType != t) { this->IdType = t; this->Modified(); } } //---------------------------------------------------------------------------- void vtkXMLWriter::SetIdTypeToInt32() { this->SetIdType(vtkXMLWriter::Int32); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetIdTypeToInt64() { this->SetIdType(vtkXMLWriter::Int64); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetDataModeToAscii() { this->SetDataMode(vtkXMLWriter::Ascii); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetDataModeToBinary() { this->SetDataMode(vtkXMLWriter::Binary); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetDataModeToAppended() { this->SetDataMode(vtkXMLWriter::Appended); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetBlockSize(unsigned int blockSize) { // Enforce constraints on block size. unsigned int nbs = blockSize; #if VTK_SIZEOF_DOUBLE > VTK_SIZEOF_ID_TYPE typedef double LargestScalarType; #else typedef vtkIdType LargestScalarType; #endif unsigned int remainder = nbs % sizeof(LargestScalarType); if(remainder) { nbs -= remainder; if(nbs < sizeof(LargestScalarType)) { nbs = sizeof(LargestScalarType); } vtkWarningMacro("BlockSize must be a multiple of " << int(sizeof(LargestScalarType)) << ". Using " << nbs << " instead of " << blockSize << "."); } vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting BlockSize to " << nbs); if(this->BlockSize != nbs) { this->BlockSize = nbs; this->Modified(); } } //---------------------------------------------------------------------------- int vtkXMLWriter::ProcessRequest(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // generate the data if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA())) { return this->RequestData(request, inputVector, outputVector); } return this->Superclass::ProcessRequest(request, inputVector, outputVector); } //---------------------------------------------------------------------------- int vtkXMLWriter::RequestInformation( vtkInformation *vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *vtkNotUsed(outputVector)) { vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); if ( inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()) ) { this->NumberOfTimeSteps = inInfo->Length( vtkStreamingDemandDrivenPipeline::TIME_STEPS() ); } return 1; } //---------------------------------------------------------------------------- int vtkXMLWriter::RequestData(vtkInformation* vtkNotUsed( request ), vtkInformationVector** vtkNotUsed( inputVector ) , vtkInformationVector* vtkNotUsed( outputVector) ) { this->SetErrorCode(vtkErrorCode::NoError); // Make sure we have a file to write. if(!this->Stream && !this->FileName) { vtkErrorMacro("Writer called with no FileName set."); this->SetErrorCode(vtkErrorCode::NoFileNameError); return 0; } // We are just starting to write. Do not call // UpdateProgressDiscrete because we want a 0 progress callback the // first time. this->UpdateProgress(0); // Initialize progress range to entire 0..1 range. float wholeProgressRange[2] = {0,1}; this->SetProgressRange(wholeProgressRange, 0, 1); // Check input validity and call the real writing code. int result = this->WriteInternal(); // If writing failed, delete the file. if(!result) { vtkErrorMacro("Ran out of disk space; deleting file: " << this->FileName); this->DeleteAFile(); } // We have finished writing. this->UpdateProgressDiscrete(1); return result; } //---------------------------------------------------------------------------- int vtkXMLWriter::Write() { // Make sure we have input. if (this->GetNumberOfInputConnections(0) < 1) { vtkErrorMacro("No input provided!"); return 0; } // always write even if the data hasn't changed this->Modified(); this->Update(); return 1; } //---------------------------------------------------------------------------- int vtkXMLWriter::OpenFile() { this->OutFile = 0; if(this->Stream) { // Rewind stream to the beginning. this->Stream->seekp(0); } else { // Try to open the output file for writing. #ifdef _WIN32 this->OutFile = new ofstream(this->FileName, ios::out | ios::binary); #else this->OutFile = new ofstream(this->FileName, ios::out); #endif if(!this->OutFile || !*this->OutFile) { vtkErrorMacro("Error opening output file \"" << this->FileName << "\""); this->SetErrorCode(vtkErrorCode::GetLastSystemError()); vtkErrorMacro("Error code \"" << vtkErrorCode::GetStringFromErrorCode(this->GetErrorCode()) << "\""); return 0; } this->Stream = this->OutFile; } // Setup the output streams. this->DataStream->SetStream(this->Stream); return 1; } //---------------------------------------------------------------------------- void vtkXMLWriter::CloseFile() { // Cleanup the output streams. this->DataStream->SetStream(0); if(this->OutFile) { // We opened a file. Close it. delete this->OutFile; this->OutFile = 0; this->Stream = 0; } } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteInternal() { if (!this->OpenFile()) { return 0; } // Tell the subclass to write the data. int result = this->WriteData(); // if user manipulate execution don't try closing file if( this->UserContinueExecuting != 1 ) { this->CloseFile(); } return result; } //---------------------------------------------------------------------------- int vtkXMLWriter::GetDataSetMajorVersion() { return 0; } //---------------------------------------------------------------------------- int vtkXMLWriter::GetDataSetMinorVersion() { return 1; } //---------------------------------------------------------------------------- vtkDataSet* vtkXMLWriter::GetInputAsDataSet() { return static_cast(this->GetInput()); } //---------------------------------------------------------------------------- int vtkXMLWriter::StartFile() { ostream& os = *(this->Stream); // If this will really be a valid XML file, put the XML header at // the top. if(this->EncodeAppendedData) { os << "\n"; } // Open the document-level element. This will contain the rest of // the elements. os << "WriteFileAttributes(); os << ">\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); return 0; } return 1; } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteFileAttributes() { ostream& os = *(this->Stream); // Write the file's type. this->WriteStringAttribute("type", this->GetDataSetName()); // Write the version number of the file. os << " version=\"" << this->GetDataSetMajorVersion() << "." << this->GetDataSetMinorVersion() << "\""; // Write the byte order for the file. if(this->ByteOrder == vtkXMLWriter::BigEndian) { os << " byte_order=\"BigEndian\""; } else { os << " byte_order=\"LittleEndian\""; } // Write the compressor that will be used for the file. if(this->Compressor) { os << " compressor=\"" << this->Compressor->GetClassName() << "\""; } } //---------------------------------------------------------------------------- int vtkXMLWriter::EndFile() { ostream& os = *(this->Stream); // Close the document-level element. os << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); return 0; } return 1; } //---------------------------------------------------------------------------- void vtkXMLWriter::DeleteAFile() { if(!this->Stream && this->FileName) { this->DeleteAFile(this->FileName); } } //---------------------------------------------------------------------------- void vtkXMLWriter::DeleteAFile(const char* name) { unlink(name); } //---------------------------------------------------------------------------- void vtkXMLWriter::StartAppendedData() { ostream& os = *(this->Stream); os << " EncodeAppendedData? "base64" : "raw") << "\">\n"; os << " _"; this->AppendedDataPosition = os.tellp(); // Setup proper output encoding. if(this->EncodeAppendedData) { vtkBase64OutputStream* base64 = vtkBase64OutputStream::New(); this->SetDataStream(base64); base64->Delete(); } else { vtkOutputStream* raw = vtkOutputStream::New(); this->SetDataStream(raw); raw->Delete(); } os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } } //---------------------------------------------------------------------------- void vtkXMLWriter::EndAppendedData() { ostream& os = *(this->Stream); os << "\n"; os << " \n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } } //---------------------------------------------------------------------------- unsigned long vtkXMLWriter::ReserveAttributeSpace(const char* attr, int length) { // Save the starting stream position. ostream& os = *(this->Stream); unsigned long startPosition = os.tellp(); // By default write an empty valid xml: attr="". In most case it // will be overwritten but we guarantee that the xml produced will // be valid in case we stop writting too early. os << " " << attr << "=\"\""; // Now reserve space for the value. for(int i=0; i < length; ++i) { os << " "; } // Flush the stream to make sure the system tries to write now and // test for a write error reported by the system. os.flush(); if(os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } // Return the position at which to write the attribute later. return startPosition; } //---------------------------------------------------------------------------- unsigned long vtkXMLWriter::GetAppendedDataOffset() { unsigned long pos = this->Stream->tellp(); return (pos - this->AppendedDataPosition); } //---------------------------------------------------------------------------- unsigned long vtkXMLWriter::WriteAppendedDataOffset(unsigned long streamPos, unsigned long &lastoffset, const char* attr) { // Write an XML attribute with the given name. The value is the // current appended data offset. Starts writing at the given stream // position, and returns the ending position. If attr is 0, writes // only the double quotes. In all cases, the final stream position // is left the same as before the call. ostream& os = *(this->Stream); unsigned long returnPos = os.tellp(); unsigned long offset = returnPos - this->AppendedDataPosition; lastoffset = offset; //saving result os.seekp(streamPos); if(attr) { os << " " << attr << "="; } os << "\"" << offset << "\""; unsigned long endPos = os.tellp(); os.seekp(returnPos); os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } return endPos; } //---------------------------------------------------------------------------- unsigned long vtkXMLWriter::ForwardAppendedDataOffset(unsigned long streamPos, unsigned long offset, const char* attr) { ostream& os = *(this->Stream); unsigned long returnPos = os.tellp(); os.seekp(streamPos); if(attr) { os << " " << attr << "="; } os << "\"" << offset << "\""; unsigned long endPos = os.tellp(); os.seekp(returnPos); os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } return endPos; } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteBinaryData(void* data, int numWords, int wordType) { unsigned long outWordSize = this->GetOutputWordTypeSize(wordType); if(this->Compressor) { // Need to compress the data. Create compression header. This // reserves enough space in the output. if(!this->CreateCompressionHeader(numWords*outWordSize)) { return 0; } // Start writing the data. int result = this->DataStream->StartWriting(); // Process the actual data. if(result && !this->WriteBinaryDataInternal(data, numWords, wordType)) { result = 0; } // Finish writing the data. if(result && !this->DataStream->EndWriting()) { result = 0; } // Go back and write the real compression header in its proper place. if(result && !this->WriteCompressionHeader()) { result = 0; } // Destroy the compression header if it was used. if(this->CompressionHeader) { delete [] this->CompressionHeader; this->CompressionHeader = 0; } return result; } else { // No data compression. The header is just the length of the data. HeaderType length = numWords*outWordSize; unsigned char* p = reinterpret_cast(&length); this->PerformByteSwap(p, 1, sizeof(HeaderType)); // Start writing the data. if(!this->DataStream->StartWriting()) { return 0; } // Write the header consisting only of the data length. int writeRes = this->DataStream->Write(p, sizeof(HeaderType)); this->Stream->flush(); if (this->Stream->fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); return 0; } if(!writeRes) { return 0; } // Process the actual data. if(!this->WriteBinaryDataInternal(data, numWords, wordType)) { return 0; } // Finish writing the data. if(!this->DataStream->EndWriting()) { return 0; } } return 1; } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteBinaryDataInternal(void* data, int numWords, int wordType) { // Break into blocks and handle each one separately. This allows // for better random access when reading compressed data and saves // memory during writing. // The size of the blocks written (before compression) is // this->BlockSize. We need to support the possibility that the // size of data in memory and the size on disk are different. This // is necessary to allow vtkIdType to be converted to UInt32 for // writing. unsigned long memWordSize = this->GetWordTypeSize(wordType); unsigned long outWordSize = this->GetOutputWordTypeSize(wordType); unsigned long blockWords = this->BlockSize/outWordSize; unsigned long memBlockSize = blockWords*memWordSize; #ifdef VTK_USE_64BIT_IDS // If the type is vtkIdType, it may need to be converted to the type // requested for output. if((wordType == VTK_ID_TYPE) && (this->IdType == vtkXMLWriter::Int32)) { this->Int32IdTypeBuffer = new Int32IdType[blockWords]; } #endif // Decide if we need to byte swap. #ifdef VTK_WORDS_BIGENDIAN if(outWordSize > 1 && this->ByteOrder != vtkXMLWriter::BigEndian) #else if(outWordSize > 1 && this->ByteOrder != vtkXMLWriter::LittleEndian) #endif { // We need to byte swap. Prepare a buffer large enough for one // block. if(this->Int32IdTypeBuffer) { // Just swap in-place in the converted id-type buffer. this->ByteSwapBuffer = reinterpret_cast(this->Int32IdTypeBuffer); } else { this->ByteSwapBuffer = new unsigned char[blockWords*outWordSize]; } } // Prepare a pointer and counter to move through the data. unsigned char* ptr = reinterpret_cast(data); unsigned long wordsLeft = numWords; // Do the complete blocks. this->SetProgressPartial(0); int result = 1; while(result && (wordsLeft >= blockWords)) { if(!this->WriteBinaryDataBlock(ptr, blockWords, wordType)) { result = 0; } ptr += memBlockSize; wordsLeft -= blockWords; this->SetProgressPartial(float(numWords-wordsLeft)/numWords); } // Do the last partial block if any. if(result && (wordsLeft > 0)) { if(!this->WriteBinaryDataBlock(ptr, wordsLeft, wordType)) { result = 0; } } this->SetProgressPartial(1); // Free the byte swap buffer if it was allocated. if(this->ByteSwapBuffer && !this->Int32IdTypeBuffer) { delete [] this->ByteSwapBuffer; this->ByteSwapBuffer = 0; } #ifdef VTK_USE_64BIT_IDS // Free the id-type conversion buffer if it was allocated. if(this->Int32IdTypeBuffer) { delete [] this->Int32IdTypeBuffer; this->Int32IdTypeBuffer = 0; } #endif return result; } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteBinaryDataBlock(unsigned char* in_data, int numWords, int wordType) { unsigned char* data = in_data; #ifdef VTK_USE_64BIT_IDS // If the type is vtkIdType, it may need to be converted to the type // requested for output. if((wordType == VTK_ID_TYPE) && (this->IdType == vtkXMLWriter::Int32)) { vtkIdType* idBuffer = reinterpret_cast(in_data); int i; for(i=0;i < numWords; ++i) { this->Int32IdTypeBuffer[i] = static_cast(idBuffer[i]); } data = reinterpret_cast(this->Int32IdTypeBuffer); } #endif // Get the word size of the data buffer. This is now the size that // will be written. unsigned long wordSize = this->GetOutputWordTypeSize(wordType); // If we need to byte swap, do it now. if(this->ByteSwapBuffer) { // If we are converting vtkIdType to 32-bit integer data, the data // are already in the byte swap buffer because we share the // conversion buffer. Otherwise, we need to copy the data before // byte swapping. if(data != this->ByteSwapBuffer) { memcpy(this->ByteSwapBuffer, data, numWords*wordSize); data = this->ByteSwapBuffer; } this->PerformByteSwap(this->ByteSwapBuffer, numWords, wordSize); } // Now pass the data to the next write phase. if(this->Compressor) { int res = this->WriteCompressionBlock(data, numWords*wordSize); this->Stream->flush(); if (this->Stream->fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); return 0; } return res; } else { int res = this->DataStream->Write(data, numWords*wordSize); this->Stream->flush(); if (this->Stream->fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); return 0; } return res; } } //---------------------------------------------------------------------------- void vtkXMLWriter::PerformByteSwap(void* data, int numWords, int wordSize) { char* ptr = static_cast(data); if(this->ByteOrder == vtkXMLWriter::BigEndian) { switch (wordSize) { case 1: break; case 2: vtkByteSwap::Swap2BERange(ptr, numWords); break; case 4: vtkByteSwap::Swap4BERange(ptr, numWords); break; case 8: vtkByteSwap::Swap8BERange(ptr, numWords); break; default: vtkErrorMacro("Unsupported data type size " << wordSize); } } else { switch (wordSize) { case 1: break; case 2: vtkByteSwap::Swap2LERange(ptr, numWords); break; case 4: vtkByteSwap::Swap4LERange(ptr, numWords); break; case 8: vtkByteSwap::Swap8LERange(ptr, numWords); break; default: vtkErrorMacro("Unsupported data type size " << wordSize); } } } //---------------------------------------------------------------------------- void vtkXMLWriter::SetDataStream(vtkOutputStream* arg) { if(this->DataStream != arg) { if(this->DataStream != NULL) { this->DataStream->UnRegister(this); } this->DataStream = arg; if(this->DataStream != NULL) { this->DataStream->Register(this); this->DataStream->SetStream(this->Stream); } } } //---------------------------------------------------------------------------- int vtkXMLWriter::CreateCompressionHeader(unsigned long size) { // Allocate and initialize the compression header. // The format is this: // struct header { // HeaderType number_of_blocks; // HeaderType uncompressed_block_size; // HeaderType uncompressed_last_block_size; // HeaderType compressed_block_sizes[number_of_blocks]; // } // Find the size and number of blocks. unsigned long numFullBlocks = size / this->BlockSize; unsigned long lastBlockSize = size % this->BlockSize; unsigned int numBlocks = numFullBlocks + (lastBlockSize?1:0); unsigned int headerLength = numBlocks+3; this->CompressionHeaderLength = headerLength; this->CompressionHeader = new HeaderType[headerLength]; // Write out dummy header data. unsigned int i; for(i=0; i < headerLength; ++i) { this->CompressionHeader[i] = 0; } this->CompressionHeaderPosition = this->Stream->tellp(); unsigned char* ch = reinterpret_cast(this->CompressionHeader); unsigned int chSize = (this->CompressionHeaderLength*sizeof(HeaderType)); int result = (this->DataStream->StartWriting() && this->DataStream->Write(ch, chSize) && this->DataStream->EndWriting()); this->Stream->flush(); if (this->Stream->fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); return 0; } // Fill in known header data now. this->CompressionHeader[0] = numBlocks; this->CompressionHeader[1] = this->BlockSize; this->CompressionHeader[2] = lastBlockSize; // Initialize counter for block writing. this->CompressionBlockNumber = 0; return result; } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteCompressionBlock(unsigned char* data, unsigned long size) { // Compress the data. vtkUnsignedCharArray* outputArray = this->Compressor->Compress(data, size); // Find the compressed size. HeaderType outputSize = outputArray->GetNumberOfTuples(); unsigned char* outputPointer = outputArray->GetPointer(0); // Write the compressed data. int result = this->DataStream->Write(outputPointer, outputSize); this->Stream->flush(); if (this->Stream->fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } // Store the resulting compressed size in the compression header. this->CompressionHeader[3+this->CompressionBlockNumber++] = outputSize; outputArray->Delete(); return result; } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteCompressionHeader() { // Write real compression header back into stream. unsigned long returnPosition = this->Stream->tellp(); // Need to byte-swap header. this->PerformByteSwap(this->CompressionHeader, this->CompressionHeaderLength, sizeof(HeaderType)); if(!this->Stream->seekp(this->CompressionHeaderPosition)) { return 0; } unsigned char* ch = reinterpret_cast(this->CompressionHeader); unsigned int chSize = (this->CompressionHeaderLength*sizeof(HeaderType)); int result = (this->DataStream->StartWriting() && this->DataStream->Write(ch, chSize) && this->DataStream->EndWriting()); this->Stream->flush(); if (this->Stream->fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); return 0; } if(!this->Stream->seekp(returnPosition)) { return 0; } return result; } //---------------------------------------------------------------------------- unsigned long vtkXMLWriter::GetOutputWordTypeSize(int dataType) { #ifdef VTK_USE_64BIT_IDS // If the type is vtkIdType, it may need to be converted to the type // requested for output. if((dataType == VTK_ID_TYPE) && (this->IdType == vtkXMLWriter::Int32)) { return 4; } #endif return this->GetWordTypeSize(dataType); } //---------------------------------------------------------------------------- template unsigned long vtkXMLWriterGetWordTypeSize(T*) { return sizeof(T); } //---------------------------------------------------------------------------- unsigned long vtkXMLWriter::GetWordTypeSize(int dataType) { unsigned long size = 1; switch (dataType) { vtkTemplateMacro( size = vtkXMLWriterGetWordTypeSize(static_cast(0)) ); default: { vtkWarningMacro("Unsupported data type: " << dataType); } break; } return size; } //---------------------------------------------------------------------------- const char* vtkXMLWriter::GetWordTypeName(int dataType) { char isSigned = 0; int size = 0; // These string values must match vtkXMLDataElement::GetWordTypeAttribute(). switch (dataType) { case VTK_FLOAT: return "Float32"; case VTK_DOUBLE: return "Float64"; case VTK_ID_TYPE: { switch (this->IdType) { case vtkXMLWriter::Int32: return "Int32"; case vtkXMLWriter::Int64: return "Int64"; default: return 0; } } #if VTK_TYPE_CHAR_IS_SIGNED case VTK_CHAR: isSigned = 1; size = sizeof(char); break; #else case VTK_CHAR: isSigned = 0; size = sizeof(char); break; #endif case VTK_INT: isSigned = 1; size = sizeof(int); break; case VTK_LONG: isSigned = 1; size = sizeof(long); break; case VTK_SHORT: isSigned = 1; size = sizeof(short); break; case VTK_SIGNED_CHAR: isSigned = 1; size = sizeof(signed char); break; case VTK_UNSIGNED_CHAR: isSigned = 0; size = sizeof(unsigned char); break; case VTK_UNSIGNED_INT: isSigned = 0; size = sizeof(unsigned int); break; case VTK_UNSIGNED_LONG: isSigned = 0; size = sizeof(unsigned long); break; case VTK_UNSIGNED_SHORT: isSigned = 0; size = sizeof(unsigned short); break; #if defined(VTK_TYPE_USE_LONG_LONG) case VTK_LONG_LONG: isSigned = 1; size = sizeof(long long); break; case VTK_UNSIGNED_LONG_LONG: isSigned = 0; size = sizeof(unsigned long long); break; #endif #if defined(VTK_TYPE_USE___INT64) case VTK___INT64: isSigned = 1; size = sizeof(__int64); break; # if defined(VTK_TYPE_CONVERT_UI64_TO_DOUBLE) case VTK_UNSIGNED___INT64: isSigned = 0; size = sizeof(unsigned __int64); break; # endif #endif default: { vtkWarningMacro("Unsupported data type: " << dataType); } break; } const char* type = 0; switch (size) { case 1: type = isSigned? "Int8" : "UInt8"; break; case 2: type = isSigned? "Int16" : "UInt16"; break; case 4: type = isSigned? "Int32" : "UInt32"; break; case 8: type = isSigned? "Int64" : "UInt64"; break; default: { vtkErrorMacro("Data type size " << size << " not supported by VTK XML format."); } } return type; } //---------------------------------------------------------------------------- template int vtkXMLWriterWriteVectorAttribute(ostream& os, const char* name, int length, T* data) { os << " " << name << "=\""; if(length) { int i; os << data[0]; for(i=1;i < length; ++i) { os << " " << data[i]; } } os << "\""; return (os? 1:0); } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteScalarAttribute(const char* name, int data) { return this->WriteVectorAttribute(name, 1, &data); } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteScalarAttribute(const char* name, float data) { return this->WriteVectorAttribute(name, 1, &data); } //---------------------------------------------------------------------------- #ifdef VTK_USE_64BIT_IDS int vtkXMLWriter::WriteScalarAttribute(const char* name, vtkIdType data) { return this->WriteVectorAttribute(name, 1, &data); } #endif //---------------------------------------------------------------------------- int vtkXMLWriter::WriteVectorAttribute(const char* name, int length, int* data) { int res = vtkXMLWriterWriteVectorAttribute(*(this->Stream), name, length, data); this->Stream->flush(); if (this->Stream->fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } return res; } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteVectorAttribute(const char* name, int length, float* data) { int res = vtkXMLWriterWriteVectorAttribute(*(this->Stream), name, length, data); this->Stream->flush(); if (this->Stream->fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } return res; } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteVectorAttribute(const char* name, int length, double* data) { int res = vtkXMLWriterWriteVectorAttribute(*(this->Stream), name, length, data); this->Stream->flush(); if (this->Stream->fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } return res; } //---------------------------------------------------------------------------- #ifdef VTK_USE_64BIT_IDS int vtkXMLWriter::WriteVectorAttribute(const char* name, int length, vtkIdType* data) { int res = vtkXMLWriterWriteVectorAttribute(*(this->Stream), name, length, data); this->Stream->flush(); if (this->Stream->fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } return res; } #endif //---------------------------------------------------------------------------- int vtkXMLWriter::WriteDataModeAttribute(const char* name) { ostream& os = *(this->Stream); os << " " << name << "=\""; if(this->DataMode == vtkXMLWriter::Appended) { os << "appended"; } else if(this->DataMode == vtkXMLWriter::Binary) { os << "binary"; } else { os << "ascii"; } os << "\""; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } return (os? 1:0); } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteWordTypeAttribute(const char* name, int dataType) { ostream& os = *(this->Stream); const char* value = this->GetWordTypeName(dataType); if(!value) { return 0; } os << " " << name << "=\"" << value << "\""; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } return (os? 1:0); } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteStringAttribute(const char* name, const char* value) { ostream& os = *(this->Stream); os << " " << name << "=\"" << value << "\""; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } return (os? 1:0); } //---------------------------------------------------------------------------- template int vtkXMLWriteAsciiData(ostream& os, T* data, int length, vtkIndent indent, long) { int columns = 6; int rows = length/columns; int lastRowLength = length%columns; int r,c; int pos=0; for(r=0;r < rows;++r) { os << indent << data[pos++]; for(c=1;c < columns;++c) { os << " " << data[pos++]; } os << "\n"; } if(lastRowLength > 0) { os << indent << data[pos++]; for(c=1;c < lastRowLength;++c) { os << " " << data[pos++]; } os << "\n"; } return (os? 1:0); } //---------------------------------------------------------------------------- int vtkXMLWriteAsciiData(ostream& os, char* data, int length, vtkIndent indent, int) { int columns = 6; int rows = length/columns; int lastRowLength = length%columns; int r,c; int pos=0; for(r=0;r < rows;++r) { os << indent << short(data[pos++]); for(c=1;c < columns;++c) { os << " " << short(data[pos++]); } os << "\n"; } if(lastRowLength > 0) { os << indent << short(data[pos++]); for(c=1;c < lastRowLength;++c) { os << " " << short(data[pos++]); } os << "\n"; } return (os? 1:0); } //---------------------------------------------------------------------------- int vtkXMLWriteAsciiData(ostream& os, unsigned char* data, int length, vtkIndent indent, int) { int columns = 6; int rows = length/columns; int lastRowLength = length%columns; int r,c; int pos=0; typedef unsigned short ushort; for(r=0;r < rows;++r) { os << indent << ushort(data[pos++]); for(c=1;c < columns;++c) { os << " " << ushort(data[pos++]); } os << "\n"; } if(lastRowLength > 0) { os << indent << ushort(data[pos++]); for(c=1;c < lastRowLength;++c) { os << " " << ushort(data[pos++]); } os << "\n"; } return (os? 1:0); } //---------------------------------------------------------------------------- int vtkXMLWriteAsciiData(ostream& os, signed char* data, int length, vtkIndent indent, int) { int columns = 6; int rows = length/columns; int lastRowLength = length%columns; int r,c; int pos=0; for(r=0;r < rows;++r) { os << indent << short(data[pos++]); for(c=1;c < columns;++c) { os << " " << short(data[pos++]); } os << "\n"; } if(lastRowLength > 0) { os << indent << short(data[pos++]); for(c=1;c < lastRowLength;++c) { os << " " << short(data[pos++]); } os << "\n"; } return (os? 1:0); } //---------------------------------------------------------------------------- int vtkXMLWriter::WriteAsciiData(void* data, int numWords, int wordType, vtkIndent indent) { void* b = data; int nw = numWords; vtkIndent i = indent; this->Stream->precision(11); ostream& os = *(this->Stream); switch(wordType) { vtkTemplateMacro( return vtkXMLWriteAsciiData(os, static_cast(b), nw, i, 1) ); default: return 0; } } //---------------------------------------------------------------------------- unsigned long vtkXMLWriter::WriteDataArrayAppended(vtkDataArray* a, vtkIndent indent, const char* alternateName, int writeNumTuples, int timestep) { ostream& os = *(this->Stream); // Write the header WriteDataArrayHeader(a,indent,alternateName, writeNumTuples, timestep); unsigned long pos = this->ReserveAttributeSpace("offset"); // Close the header os << "/>\n"; this->WriteDataArrayFooter(os, indent); return pos; } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteDataArrayAppendedData(vtkDataArray* a, unsigned long pos, unsigned long &lastoffset) { this->WriteAppendedDataOffset(pos, lastoffset, "offset"); if (this->ErrorCode != vtkErrorCode::NoError) { return; } this->WriteBinaryData(a->GetVoidPointer(0), a->GetNumberOfTuples()*a->GetNumberOfComponents(), a->GetDataType()); } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteDataArrayHeader(vtkDataArray* a, vtkIndent indent, const char* alternateName, int writeNumTuples, int timestep) { ostream& os = *(this->Stream); os << indent << "WriteWordTypeAttribute("type", a->GetDataType()); if(alternateName) { this->WriteStringAttribute("Name", alternateName); } else if(const char* arrayName = a->GetName()) { this->WriteStringAttribute("Name", arrayName); } else { // Generate a name for this array. vtksys_ios::ostringstream name; void* p = a; name << "Array " << p; this->WriteStringAttribute("Name", name.str().c_str()); } if(a->GetNumberOfComponents() > 1) { this->WriteScalarAttribute("NumberOfComponents", a->GetNumberOfComponents()); } if(this->NumberOfTimeSteps > 1) { this->WriteScalarAttribute("TimeStep", timestep); } else { //assert( timestep == -1); //FieldData problem } if(writeNumTuples) { this->WriteScalarAttribute("NumberOfTuples", a->GetNumberOfTuples()); } this->WriteDataModeAttribute("format"); } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteDataArrayFooter(ostream &os, vtkIndent ) { os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteDataArrayInline(vtkDataArray* a, vtkIndent indent, const char* alternateName, int writeNumTuples) { ostream& os = *(this->Stream); // Write the header WriteDataArrayHeader(a, indent, alternateName, writeNumTuples, -1); // Close the header os << ">\n"; // Write the data this->WriteInlineData(a->GetVoidPointer(0), a->GetNumberOfTuples()*a->GetNumberOfComponents(), a->GetDataType(), indent.GetNextIndent()); // Close the os << indent << "\n"; this->WriteDataArrayFooter(os, indent); } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteInlineData(void* data, int numWords, int wordType, vtkIndent indent) { if(this->DataMode == vtkXMLWriter::Binary) { ostream& os = *(this->Stream); os << indent; this->WriteBinaryData(data, numWords, wordType); os << "\n"; } else { this->WriteAsciiData(data, numWords, wordType, indent); } } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteFieldData(vtkIndent indent) { vtkFieldData *fieldData = this->GetInput()->GetFieldData(); if (!fieldData || !fieldData->GetNumberOfArrays()) { return; } if(this->DataMode == vtkXMLWriter::Appended) { this->WriteFieldDataAppended(fieldData, indent, this->FieldDataOM); } else { // Write the point data arrays. this->WriteFieldDataInline(fieldData, indent); } } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteFieldDataInline(vtkFieldData* fd, vtkIndent indent) { ostream& os = *(this->Stream); char** names = this->CreateStringArray(fd->GetNumberOfArrays()); os << indent << "\n"; float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); int i; for(i=0; i < fd->GetNumberOfArrays(); ++i) { this->SetProgressRange(progressRange, i, fd->GetNumberOfArrays()); this->WriteDataArrayInline(fd->GetArray(i), indent.GetNextIndent(), names[i], 1); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(fd->GetNumberOfArrays(), names); return; } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); this->DestroyStringArray(fd->GetNumberOfArrays(), names); return; } this->DestroyStringArray(fd->GetNumberOfArrays(), names); } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePointDataInline(vtkPointData* pd, vtkIndent indent) { ostream& os = *(this->Stream); char** names = this->CreateStringArray(pd->GetNumberOfArrays()); os << indent << "WriteAttributeIndices(pd, names); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(pd->GetNumberOfArrays(), names); return; } os << ">\n"; float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); int i; for(i=0; i < pd->GetNumberOfArrays(); ++i) { this->SetProgressRange(progressRange, i, pd->GetNumberOfArrays()); vtkDataArray* a = this->CreateArrayForPoints(pd->GetArray(i)); this->WriteDataArrayInline(a, indent.GetNextIndent(), names[i]); a->Delete(); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(pd->GetNumberOfArrays(), names); return; } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); this->DestroyStringArray(pd->GetNumberOfArrays(), names); return; } this->DestroyStringArray(pd->GetNumberOfArrays(), names); } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteCellDataInline(vtkCellData* cd, vtkIndent indent) { ostream& os = *(this->Stream); char** names = this->CreateStringArray(cd->GetNumberOfArrays()); os << indent << "WriteAttributeIndices(cd, names); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(cd->GetNumberOfArrays(), names); return; } os << ">\n"; float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); int i; for(i=0; i < cd->GetNumberOfArrays(); ++i) { this->SetProgressRange(progressRange, i, cd->GetNumberOfArrays()); vtkDataArray* a = this->CreateArrayForCells(cd->GetArray(i)); this->WriteDataArrayInline(a, indent.GetNextIndent(), names[i]); a->Delete(); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(cd->GetNumberOfArrays(), names); return; } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); this->DestroyStringArray(cd->GetNumberOfArrays(), names); return; } this->DestroyStringArray(cd->GetNumberOfArrays(), names); } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteFieldDataAppended(vtkFieldData* fd, vtkIndent indent, OffsetsManagerGroup *fdManager) { ostream& os = *(this->Stream); char** names = this->CreateStringArray(fd->GetNumberOfArrays()); os << indent << "\n"; int i; fdManager->Allocate(fd->GetNumberOfArrays()); for(i=0; i < fd->GetNumberOfArrays(); ++i) { fdManager->GetElement(i).Allocate(1); fdManager->GetElement(i).GetPosition(0) = this->WriteDataArrayAppended(fd->GetArray(i), indent.GetNextIndent(), names[i], 1 , -1); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(fd->GetNumberOfArrays(), names); return; } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } this->DestroyStringArray(fd->GetNumberOfArrays(), names); } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteFieldDataAppendedData(vtkFieldData* fd, int timestep, OffsetsManagerGroup *fdManager) { float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); int i; fdManager->Allocate(fd->GetNumberOfArrays()); for(i=0; i < fd->GetNumberOfArrays(); ++i) { fdManager->GetElement(i).Allocate(this->NumberOfTimeSteps); this->SetProgressRange(progressRange, i, fd->GetNumberOfArrays()); this->WriteDataArrayAppendedData(fd->GetArray(i), fdManager->GetElement(i).GetPosition(timestep), fdManager->GetElement(i).GetOffsetValue(timestep)); if (this->ErrorCode != vtkErrorCode::NoError) { return; } } } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePointDataAppended(vtkPointData* pd, vtkIndent indent, OffsetsManagerGroup *pdManager) { ostream& os = *(this->Stream); char** names = this->CreateStringArray(pd->GetNumberOfArrays()); os << indent << "WriteAttributeIndices(pd, names); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(pd->GetNumberOfArrays(), names); return; } os << ">\n"; pdManager->Allocate(pd->GetNumberOfArrays()); for(int i=0; i < pd->GetNumberOfArrays(); ++i) { pdManager->GetElement(i).Allocate(this->NumberOfTimeSteps); for(int t=0; t< this->NumberOfTimeSteps; ++t) { pdManager->GetElement(i).GetPosition(t) = this->WriteDataArrayAppended(pd->GetArray(i), indent.GetNextIndent(), names[i],0,t); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(pd->GetNumberOfArrays(), names); return; } } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } this->DestroyStringArray(pd->GetNumberOfArrays(), names); } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePointDataAppendedData(vtkPointData* pd, int timestep, OffsetsManagerGroup *pdManager) { float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); for(int i=0; i < pd->GetNumberOfArrays(); ++i) { this->SetProgressRange(progressRange, i, pd->GetNumberOfArrays()); unsigned long mtime = pd->GetMTime(); // Only write pd if MTime has changed unsigned long &pdMTime = pdManager->GetElement(i).GetLastMTime(); if( pdMTime != mtime ) { pdMTime = mtime; vtkDataArray* a = this->CreateArrayForPoints(pd->GetArray(i)); this->WriteDataArrayAppendedData(a, pdManager->GetElement(i).GetPosition(timestep), pdManager->GetElement(i).GetOffsetValue(timestep)); a->Delete(); if (this->ErrorCode != vtkErrorCode::NoError) { return; } } else { assert( timestep > 0 ); pdManager->GetElement(i).GetOffsetValue(timestep) = pdManager->GetElement(i).GetOffsetValue(timestep-1); this->ForwardAppendedDataOffset(pdManager->GetElement(i).GetPosition(timestep), pdManager->GetElement(i).GetOffsetValue(timestep), "offset" ); } } } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteCellDataAppended(vtkCellData* cd, vtkIndent indent, OffsetsManagerGroup *cdManager) { ostream& os = *(this->Stream); char** names = this->CreateStringArray(cd->GetNumberOfArrays()); os << indent << "WriteAttributeIndices(cd, names); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(cd->GetNumberOfArrays(), names); return; } os << ">\n"; cdManager->Allocate(cd->GetNumberOfArrays()); for(int i=0; i < cd->GetNumberOfArrays(); ++i) { cdManager->GetElement(i).Allocate(this->NumberOfTimeSteps); for(int t=0; t< this->NumberOfTimeSteps; ++t) { cdManager->GetElement(i).GetPosition(t) = this->WriteDataArrayAppended(cd->GetArray(i), indent.GetNextIndent(), names[i],0,t); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(cd->GetNumberOfArrays(), names); return; } } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } this->DestroyStringArray(cd->GetNumberOfArrays(), names); } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteCellDataAppendedData(vtkCellData* cd, int timestep, OffsetsManagerGroup *cdManager) { float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); int i; for(i=0; i < cd->GetNumberOfArrays(); ++i) { this->SetProgressRange(progressRange, i, cd->GetNumberOfArrays()); unsigned long mtime = cd->GetMTime(); // Only write pd if MTime has changed unsigned long &cdMTime = cdManager->GetElement(i).GetLastMTime(); if( cdMTime != mtime ) { cdMTime = mtime; vtkDataArray* a = this->CreateArrayForCells(cd->GetArray(i)); this->WriteDataArrayAppendedData(a, cdManager->GetElement(i).GetPosition(timestep), cdManager->GetElement(i).GetOffsetValue(timestep)); a->Delete(); if (this->ErrorCode != vtkErrorCode::NoError) { return; } } else { assert( timestep > 0 ); cdManager->GetElement(i).GetOffsetValue(timestep) = cdManager->GetElement(i).GetOffsetValue(timestep-1); this->ForwardAppendedDataOffset( cdManager->GetElement(i).GetPosition(timestep), cdManager->GetElement(i).GetOffsetValue(timestep), "offset" ); } } } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteAttributeIndices(vtkDataSetAttributes* dsa, char** names) { int i; int attributeIndices[vtkDataSetAttributes::NUM_ATTRIBUTES]; dsa->GetAttributeIndices(attributeIndices); for(i=0;i < vtkDataSetAttributes::NUM_ATTRIBUTES;++i) { if(attributeIndices[i] >= 0) { const char* attrName = dsa->GetAttributeTypeAsString(i); vtkDataArray* a = dsa->GetArray(attributeIndices[i]); const char* arrayName = a->GetName(); if(!arrayName) { // Assign a name to the array. names[attributeIndices[i]] = new char[strlen(attrName)+2]; strcpy(names[attributeIndices[i]], attrName); strcat(names[attributeIndices[i]], "_"); arrayName = names[attributeIndices[i]]; } this->WriteStringAttribute(attrName, arrayName); if (this->ErrorCode != vtkErrorCode::NoError) { return; } } } } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePointsAppended(vtkPoints* points, vtkIndent indent, OffsetsManager *ptManager) { ostream& os = *(this->Stream); // Only write points if they exist. os << indent << "\n"; if(points) { for(int t=0; t< this->NumberOfTimeSteps; ++t) { ptManager->GetPosition(t) = this->WriteDataArrayAppended(points->GetData(), indent.GetNextIndent(),0,0,t); } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePointsAppendedData(vtkPoints* points, int timestep, OffsetsManager *ptManager) { // Only write points if they exist. if(points) { unsigned long mtime = points->GetMTime(); // Only write points if MTime has changed unsigned long &pointsMTime = ptManager->GetLastMTime(); if( pointsMTime != mtime ) { pointsMTime = mtime; vtkDataArray* outPoints = this->CreateArrayForPoints(points->GetData()); this->WriteDataArrayAppendedData(outPoints, ptManager->GetPosition(timestep), ptManager->GetOffsetValue(timestep)); outPoints->Delete(); } else { assert( timestep > 0 ); ptManager->GetOffsetValue(timestep) = ptManager->GetOffsetValue(timestep-1); this->ForwardAppendedDataOffset( ptManager->GetPosition(timestep), ptManager->GetOffsetValue(timestep), "offset"); } } } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePointsInline(vtkPoints* points, vtkIndent indent) { ostream& os = *(this->Stream); // Only write points if they exist. os << indent << "\n"; if(points) { vtkDataArray* outPoints = this->CreateArrayForPoints(points->GetData()); this->WriteDataArrayInline(outPoints, indent.GetNextIndent()); outPoints->Delete(); } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteCoordinatesInline(vtkDataArray* xc, vtkDataArray* yc, vtkDataArray* zc, vtkIndent indent) { ostream& os = *(this->Stream); // Only write coordinates if they exist. os << indent << "\n"; if(xc && yc && zc) { vtkDataArray* oxc = this->CreateExactCoordinates(xc, 0); vtkDataArray* oyc = this->CreateExactCoordinates(yc, 1); vtkDataArray* ozc = this->CreateExactCoordinates(zc, 2); // Split progress over the three coordinates arrays. vtkIdType total = (oxc->GetNumberOfTuples()+ oyc->GetNumberOfTuples()+ ozc->GetNumberOfTuples()); if(total == 0) { total = 1; } float fractions[4] = { 0, float(oxc->GetNumberOfTuples()) / total, float(oxc->GetNumberOfTuples()+oyc->GetNumberOfTuples()) / total, 1 }; float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); this->SetProgressRange(progressRange, 0, fractions); this->WriteDataArrayInline(oxc, indent.GetNextIndent()); if (this->ErrorCode != vtkErrorCode::NoError) { oxc->Delete(); oyc->Delete(); ozc->Delete(); return; } this->SetProgressRange(progressRange, 1, fractions); this->WriteDataArrayInline(oyc, indent.GetNextIndent()); if (this->ErrorCode != vtkErrorCode::NoError) { oxc->Delete(); oyc->Delete(); ozc->Delete(); return; } this->SetProgressRange(progressRange, 2, fractions); this->WriteDataArrayInline(ozc, indent.GetNextIndent()); if (this->ErrorCode != vtkErrorCode::NoError) { oxc->Delete(); oyc->Delete(); ozc->Delete(); return; } oxc->Delete(); oyc->Delete(); ozc->Delete(); } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); return; } } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteCoordinatesAppended(vtkDataArray* xc, vtkDataArray* yc, vtkDataArray* zc, vtkIndent indent, OffsetsManagerGroup *coordManager) { ostream& os = *(this->Stream); // Helper for the 'for' loop vtkDataArray *allcoords[3]; allcoords[0] = xc; allcoords[1] = yc; allcoords[2] = zc; // Only write coordinates if they exist. os << indent << "\n"; coordManager->Allocate(3); if(xc && yc && zc) { for(int i=0; i<3; ++i) { coordManager->GetElement(i).Allocate(this->NumberOfTimeSteps); for(int t=0; tNumberOfTimeSteps; ++t) { coordManager->GetElement(i).GetPosition(t) = this->WriteDataArrayAppended(allcoords[i], indent.GetNextIndent()); if (this->ErrorCode != vtkErrorCode::NoError) { return ; } } } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteCoordinatesAppendedData(vtkDataArray* xc, vtkDataArray* yc, vtkDataArray* zc, int timestep, OffsetsManagerGroup *coordManager) { // Only write coordinates if they exist. if(xc && yc && zc) { vtkDataArray* oxc = this->CreateExactCoordinates(xc, 0); vtkDataArray* oyc = this->CreateExactCoordinates(yc, 1); vtkDataArray* ozc = this->CreateExactCoordinates(zc, 2); // Split progress over the three coordinates arrays. vtkIdType total = (oxc->GetNumberOfTuples()+ oyc->GetNumberOfTuples()+ ozc->GetNumberOfTuples()); if(total == 0) { total = 1; } float fractions[4] = { 0, float(oxc->GetNumberOfTuples()) / total, float(oxc->GetNumberOfTuples()+oyc->GetNumberOfTuples()) / total, 1 }; float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); // Helper for the 'for' loop vtkDataArray *allcoords[3]; allcoords[0] = oxc; allcoords[1] = oyc; allcoords[2] = ozc; for(int i=0; i<3; ++i) { this->SetProgressRange(progressRange, i, fractions); unsigned long mtime = allcoords[i]->GetMTime(); // Only write pd if MTime has changed unsigned long &coordMTime = coordManager->GetElement(i).GetLastMTime(); if( coordMTime != mtime ) { coordMTime = mtime; this->WriteDataArrayAppendedData(allcoords[i], coordManager->GetElement(i).GetPosition(timestep), coordManager->GetElement(i).GetOffsetValue(timestep)); if (this->ErrorCode != vtkErrorCode::NoError) { oxc->Delete(); oyc->Delete(); ozc->Delete(); return; } } else { } } oxc->Delete(); oyc->Delete(); ozc->Delete(); } } //---------------------------------------------------------------------------- vtkDataArray* vtkXMLWriter::CreateArrayForPoints(vtkDataArray* inArray) { // Only some subclasses need to do anything. By default, just // return the array as given. inArray->Register(0); return inArray; } //---------------------------------------------------------------------------- vtkDataArray* vtkXMLWriter::CreateArrayForCells(vtkDataArray* inArray) { // Only some subclasses need to do anything. By default, just // return the array as given. inArray->Register(0); return inArray; } //---------------------------------------------------------------------------- vtkDataArray* vtkXMLWriter::CreateExactCoordinates(vtkDataArray* inArray, int) { // This method is just a dummy because we don't want a pure virtual. // Subclasses that need it should define the real version. vtkErrorMacro("vtkXMLWriter::CreateExactCoordinates should never be called."); inArray->Register(0); return inArray; } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePPointData(vtkPointData* pd, vtkIndent indent) { if(pd->GetNumberOfArrays() == 0) { return; } ostream& os = *(this->Stream); char** names = this->CreateStringArray(pd->GetNumberOfArrays()); os << indent << "WriteAttributeIndices(pd, names); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(pd->GetNumberOfArrays(), names); return; } os << ">\n"; int i; for(i=0; i < pd->GetNumberOfArrays(); ++i) { this->WritePDataArray(pd->GetArray(i), indent.GetNextIndent(), names[i]); if (this->ErrorCode != vtkErrorCode::NoError) { this->DestroyStringArray(pd->GetNumberOfArrays(), names); return; } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } this->DestroyStringArray(pd->GetNumberOfArrays(), names); } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePCellData(vtkCellData* cd, vtkIndent indent) { if(cd->GetNumberOfArrays() == 0) { return; } ostream& os = *(this->Stream); char** names = this->CreateStringArray(cd->GetNumberOfArrays()); os << indent << "WriteAttributeIndices(cd, names); os << ">\n"; int i; for(i=0; i < cd->GetNumberOfArrays(); ++i) { this->WritePDataArray(cd->GetArray(i), indent.GetNextIndent(), names[i]); } os << indent << "\n"; this->DestroyStringArray(cd->GetNumberOfArrays(), names); } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePPoints(vtkPoints* points, vtkIndent indent) { ostream& os = *(this->Stream); // Only write points if they exist. os << indent << "\n"; if(points) { this->WritePDataArray(points->GetData(), indent.GetNextIndent()); } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePDataArray(vtkDataArray* a, vtkIndent indent, const char* alternateName) { ostream& os = *(this->Stream); os << indent << "WriteWordTypeAttribute("type", a->GetDataType()); if(alternateName) { this->WriteStringAttribute("Name", alternateName); } else { const char* arrayName = a->GetName(); if(arrayName) { this->WriteStringAttribute("Name", arrayName); } } if(a->GetNumberOfComponents() > 1) { this->WriteScalarAttribute("NumberOfComponents", a->GetNumberOfComponents()); } os << "/>\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePCoordinates(vtkDataArray* xc, vtkDataArray* yc, vtkDataArray* zc, vtkIndent indent) { ostream& os = *(this->Stream); // Only write coordinates if they exist. os << indent << "\n"; if(xc && yc && zc) { this->WritePDataArray(xc, indent.GetNextIndent()); if (this->ErrorCode != vtkErrorCode::NoError) { return; } this->WritePDataArray(yc, indent.GetNextIndent()); if (this->ErrorCode != vtkErrorCode::NoError) { return; } this->WritePDataArray(zc, indent.GetNextIndent()); if (this->ErrorCode != vtkErrorCode::NoError) { return; } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::GetLastSystemError()); } } //---------------------------------------------------------------------------- char** vtkXMLWriter::CreateStringArray(int numStrings) { char** strings = new char*[numStrings]; int i; for(i=0; i < numStrings; ++i) { strings[i] = 0; } return strings; } //---------------------------------------------------------------------------- void vtkXMLWriter::DestroyStringArray(int numStrings, char** strings) { int i; for(i=0; i < numStrings; ++i) { if(strings[i]) { delete [] strings[i]; } } delete [] strings; } //---------------------------------------------------------------------------- void vtkXMLWriter::GetProgressRange(float* range) { range[0] = this->ProgressRange[0]; range[1] = this->ProgressRange[1]; } //---------------------------------------------------------------------------- void vtkXMLWriter::SetProgressRange(float* range, int curStep, int numSteps) { float stepSize = (range[1] - range[0])/numSteps; this->ProgressRange[0] = range[0] + stepSize*curStep; this->ProgressRange[1] = range[0] + stepSize*(curStep+1); this->UpdateProgressDiscrete(this->ProgressRange[0]); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetProgressRange(float* range, int curStep, float* fractions) { float width = range[1] - range[0]; this->ProgressRange[0] = range[0] + fractions[curStep]*width; this->ProgressRange[1] = range[0] + fractions[curStep+1]*width; this->UpdateProgressDiscrete(this->ProgressRange[0]); } //---------------------------------------------------------------------------- void vtkXMLWriter::SetProgressPartial(float fraction) { float width = this->ProgressRange[1] - this->ProgressRange[0]; this->UpdateProgressDiscrete(this->ProgressRange[0] + fraction*width); } //---------------------------------------------------------------------------- void vtkXMLWriter::UpdateProgressDiscrete(float progress) { if(!this->AbortExecute) { // Round progress to nearest 100th. float rounded = float(int((progress*100)+0.5))/100; if(this->GetProgress() != rounded) { this->UpdateProgress(rounded); } } } //---------------------------------------------------------------------------- void vtkXMLWriter::WritePrimaryElementAttributes(ostream &os, vtkIndent indent) { // Write the time step if any: if( this->NumberOfTimeSteps > 1) { // First thing allocate NumberOfTimeValues assert( this->NumberOfTimeValues == NULL ); this->NumberOfTimeValues = new unsigned long[this->NumberOfTimeSteps]; os << indent << "TimeValues=\"\n"; vtkstd::string blankline = vtkstd::string(40, ' '); //enough room for precision for(int i=0; iNumberOfTimeSteps; i++) { this->NumberOfTimeValues[i] = os.tellp(); os << blankline.c_str() << "\n"; } os << "\""; } } //---------------------------------------------------------------------------- int vtkXMLWriter::WritePrimaryElement(ostream &os, vtkIndent indent) { // Open the primary element. os << indent << "<" << this->GetDataSetName(); this->WritePrimaryElementAttributes(os,indent); // Close the primary element: os << ">\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); return 0; } return 1; } // The following function are designed to be called outside of the VTK pipeline // typically from a C interface or when ParaView want to control the writing //---------------------------------------------------------------------------- void vtkXMLWriter::Start() { // Make sure we have input. if (this->GetNumberOfInputConnections(0) < 1) { vtkErrorMacro("No input provided!"); return; } this->UserContinueExecuting = 1; } //---------------------------------------------------------------------------- // The function does not make sense in the general case but we need to handle // the case where the simulation stop before reaching the number of steps // specified by the user. Therefore the CurrentTimeIndex is never equal // to NumberOfTimeStep and thus we need to force closing of the xml file void vtkXMLWriter::Stop() { this->UserContinueExecuting = 0; this->Modified(); this->Update(); this->UserContinueExecuting = -1; //put back the writer in initial state } //---------------------------------------------------------------------------- void vtkXMLWriter::WriteNextTime(double time) { this->Modified(); this->Update(); ostream& os = *(this->Stream); if (this->NumberOfTimeValues) { // Write user specified time value in the TimeValues attribute unsigned long returnPos = os.tellp(); os.seekp(this->NumberOfTimeValues[this->CurrentTimeIndex-1]); os << time; os.seekp(returnPos); } }