/*========================================================================= Program: Visualization Toolkit Module: vtkArrayWriter.cxx 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 "vtkArrayWriter.h" #include "vtkArrayData.h" #include "vtkArrayPrint.h" #include "vtkDenseArray.h" #include "vtkExecutive.h" #include "vtkInformation.h" #include "vtkObjectFactory.h" #include "vtkSmartPointer.h" #include "vtkSparseArray.h" #include "vtkUnicodeString.h" #include #include #include #include namespace { template inline void WriteValue(std::ostream& stream, const T& value) { stream << value; } inline void WriteValue(std::ostream& stream, const double& value) { if(std::abs(value) < std::numeric_limits::min()) stream << 0; else stream << value; } inline void WriteValue(std::ostream& stream, const vtkStdString& value) { stream << value; } inline void WriteValue(std::ostream& stream, const vtkUnicodeString& value) { stream << value.utf8_str(); } void WriteHeader(const vtkStdString& array_type, const vtkStdString& type_name, vtkArray* array, ostream& stream, bool WriteBinary) { // Serialize the array type ... stream << array_type << " " << type_name << "\n"; // Serialize output format, binary or ascii WriteBinary ? stream << "binary" <<"\n" : stream << "ascii" << "\n"; const vtkArrayExtents extents = array->GetExtents(); const vtkIdType dimensions = array->GetDimensions(); // Serialize the array name ... stream << array->GetName() << "\n"; // Serialize the array extents and number of non-nullptr values ... for(vtkIdType i = 0; i != dimensions; ++i) stream << extents[i].GetBegin() << " " << extents[i].GetEnd() << " "; stream << array->GetNonNullSize() << "\n"; // Serialize the dimension-label for each dimension ... for(vtkIdType i = 0; i != dimensions; ++i) stream << array->GetDimensionLabel(i) << "\n"; } void WriteEndianOrderMark(ostream& stream) { // Serialize an endian-order mark ... const vtkTypeUInt32 endian_order = 0x12345678; stream.write( reinterpret_cast(&endian_order), sizeof(endian_order)); } template bool WriteSparseArrayBinary(const vtkStdString& type_name, vtkArray* array, ostream& stream) { vtkSparseArray* const concrete_array = vtkSparseArray::SafeDownCast(array); if(!concrete_array) return false; // Write the array header ... WriteHeader("vtk-sparse-array", type_name, array, stream, true); WriteEndianOrderMark(stream); // Serialize the array nullptr value ... stream.write( reinterpret_cast(&concrete_array->GetNullValue()), sizeof(ValueT)); // Serialize the array coordinates ... for(vtkIdType i = 0; i != array->GetDimensions(); ++i) { stream.write( reinterpret_cast(concrete_array->GetCoordinateStorage(i)), concrete_array->GetNonNullSize() * sizeof(vtkIdType)); } // Serialize the array values ... stream.write( reinterpret_cast(concrete_array->GetValueStorage()), concrete_array->GetNonNullSize() * sizeof(ValueT)); return true; } template<> bool WriteSparseArrayBinary(const vtkStdString& type_name, vtkArray* array, ostream& stream) { vtkSparseArray* const concrete_array = vtkSparseArray::SafeDownCast(array); if(!concrete_array) return false; // Write the array header ... WriteHeader("vtk-sparse-array", type_name, array, stream, true); WriteEndianOrderMark(stream); // Serialize the array nullptr value ... stream.write( concrete_array->GetNullValue().c_str(), concrete_array->GetNullValue().size() + 1); // Serialize the array coordinates ... for(vtkIdType i = 0; i != array->GetDimensions(); ++i) { stream.write( reinterpret_cast(concrete_array->GetCoordinateStorage(i)), concrete_array->GetNonNullSize() * sizeof(vtkIdType)); } // Serialize the array values as a set of packed, nullptr-terminated strings ... const vtkIdType value_count = array->GetNonNullSize(); for(vtkIdType n = 0; n != value_count; ++n) { const vtkStdString& value = concrete_array->GetValueN(n); stream.write( value.c_str(), value.size() + 1); } return true; } template<> bool WriteSparseArrayBinary(const vtkStdString& type_name, vtkArray* array, ostream& stream) { vtkSparseArray* const concrete_array = vtkSparseArray::SafeDownCast(array); if(!concrete_array) return false; // Write the array header ... WriteHeader("vtk-sparse-array", type_name, array, stream, true); WriteEndianOrderMark(stream); // Serialize the array nullptr value ... stream.write( concrete_array->GetNullValue().utf8_str(), strlen(concrete_array->GetNullValue().utf8_str()) + 1); // Serialize the array coordinates ... for(vtkIdType i = 0; i != array->GetDimensions(); ++i) { stream.write( reinterpret_cast(concrete_array->GetCoordinateStorage(i)), concrete_array->GetNonNullSize() * sizeof(vtkIdType)); } // Serialize the array values as a set of packed, nullptr-terminated strings ... const vtkIdType value_count = array->GetNonNullSize(); for(vtkIdType n = 0; n != value_count; ++n) { const vtkUnicodeString& value = concrete_array->GetValueN(n); stream.write( value.utf8_str(), strlen(value.utf8_str()) + 1); } return true; } template bool WriteDenseArrayBinary(const vtkStdString& type_name, vtkArray* array, ostream& stream) { vtkDenseArray* const concrete_array = vtkDenseArray::SafeDownCast(array); if(!concrete_array) return false; // Write the array header ... WriteHeader("vtk-dense-array", type_name, array, stream, true); WriteEndianOrderMark(stream); // Serialize the array values ... stream.write( reinterpret_cast(concrete_array->GetStorage()), concrete_array->GetNonNullSize() * sizeof(ValueT)); return true; } template<> bool WriteDenseArrayBinary(const vtkStdString& type_name, vtkArray* array, ostream& stream) { vtkDenseArray* const concrete_array = vtkDenseArray::SafeDownCast(array); if(!concrete_array) return false; // Write the array header ... WriteHeader("vtk-dense-array", type_name, array, stream, true); WriteEndianOrderMark(stream); // Serialize the array values as a set of packed, nullptr-terminated strings ... const vtkIdType value_count = array->GetNonNullSize(); for(vtkIdType n = 0; n != value_count; ++n) { const vtkStdString& value = concrete_array->GetValueN(n); stream.write( value.c_str(), value.size() + 1); } return true; } template<> bool WriteDenseArrayBinary(const vtkStdString& type_name, vtkArray* array, ostream& stream) { vtkDenseArray* const concrete_array = vtkDenseArray::SafeDownCast(array); if(!concrete_array) return false; // Write the array header ... WriteHeader("vtk-dense-array", type_name, array, stream, true); WriteEndianOrderMark(stream); // Serialize the array values as a set of packed, nullptr-terminated strings ... const vtkIdType value_count = array->GetNonNullSize(); for(vtkIdType n = 0; n != value_count; ++n) { const vtkUnicodeString& value = concrete_array->GetValueN(n); stream.write( value.utf8_str(), strlen(value.utf8_str()) + 1); } return true; } template bool WriteSparseArrayAscii(const vtkStdString& type_name, vtkArray* array, ostream& stream) { vtkSparseArray* const concrete_array = vtkSparseArray::SafeDownCast(array); if(!concrete_array) return false; // Write the header ... WriteHeader("vtk-sparse-array", type_name, array, stream, false); // Ensure that floating-point types are serialized with full precision if(std::numeric_limits::is_specialized) stream.precision(std::numeric_limits::digits10 + 1); // Write the array nullptr value ... WriteValue(stream, concrete_array->GetNullValue()); stream << "\n"; // Write the array contents ... const vtkIdType dimensions = array->GetDimensions(); const vtkIdType non_null_size = array->GetNonNullSize(); vtkArrayCoordinates coordinates; for(vtkIdType n = 0; n != non_null_size; ++n) { array->GetCoordinatesN(n, coordinates); for(vtkIdType i = 0; i != dimensions; ++i) stream << coordinates[i] << " "; WriteValue(stream, concrete_array->GetValueN(n)); stream << "\n"; } return true; } template bool WriteDenseArrayAscii(const vtkStdString& type_name, vtkArray* array, ostream& stream) { vtkDenseArray* const concrete_array = vtkDenseArray::SafeDownCast(array); if(!concrete_array) return false; // Write the header ... WriteHeader("vtk-dense-array", type_name, array, stream, false); // Write the array contents ... const vtkArrayExtents extents = array->GetExtents(); // Ensure that floating-point types are serialized with full precision if(std::numeric_limits::is_specialized) stream.precision(std::numeric_limits::digits10 + 1); vtkArrayCoordinates coordinates; for(vtkArrayExtents::SizeT n = 0; n != extents.GetSize(); ++n) { extents.GetRightToLeftCoordinatesN(n, coordinates); WriteValue(stream, concrete_array->GetValue(coordinates)); stream << "\n"; } return true; } } // End anonymous namespace vtkStandardNewMacro(vtkArrayWriter); vtkArrayWriter::vtkArrayWriter() : FileName(nullptr), Binary(false), WriteToOutputString(false) { } vtkArrayWriter::~vtkArrayWriter() { this->SetFileName(nullptr); } void vtkArrayWriter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "FileName: " << (this->FileName ? this->FileName : "(none)") << endl; os << indent << "Binary: " << this->Binary << endl; os << indent << "WriteToOutputString: " << (this->WriteToOutputString ? "on" : "off") << endl; os << indent << "OutputString: " << this->OutputString << endl; } int vtkArrayWriter::FillInputPortInformation( int vtkNotUsed(port), vtkInformation* info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkArrayData"); return 1; } void vtkArrayWriter::WriteData() { if(this->WriteToOutputString) { this->OutputString = this->Write(this->Binary > 0 ? true : false); } else { this->Write(this->FileName ? this->FileName : "", this->Binary > 0 ? true : false); } } int vtkArrayWriter::Write() { return Superclass::Write(); } bool vtkArrayWriter::Write(const vtkStdString& file_name, bool WriteBinary) { ofstream file(file_name.c_str(), std::ios::binary); return this->Write(file, WriteBinary); } bool vtkArrayWriter::Write(vtkArray* array, const vtkStdString& file_name, bool WriteBinary) { ofstream file(file_name.c_str(), std::ios::binary); return vtkArrayWriter::Write(array, file, WriteBinary); } bool vtkArrayWriter::Write(ostream& stream, bool WriteBinary) { try { if(this->GetNumberOfInputConnections(0) != 1) throw std::runtime_error("Exactly one input required."); vtkArrayData* const array_data = vtkArrayData::SafeDownCast(this->GetExecutive()->GetInputData(0, 0)); if(!array_data) throw std::runtime_error("vtkArrayData input required."); if(array_data->GetNumberOfArrays() != 1) throw std::runtime_error("vtkArrayData with exactly one array required."); vtkArray* const array = array_data->GetArray(static_cast(0)); if(!array) throw std::runtime_error("Cannot serialize nullptr vtkArray."); return this->Write(array, stream, WriteBinary); } catch(std::exception& e) { vtkErrorMacro("caught exception: " << e.what()); } return false; } bool vtkArrayWriter::Write(vtkArray* array, ostream& stream, bool WriteBinary) { try { if(!array) throw std::runtime_error("Cannot serialize nullptr vtkArray."); if(WriteBinary) { if(WriteSparseArrayBinary("integer", array, stream)) return true; if(WriteSparseArrayBinary("double", array, stream)) return true; if(WriteSparseArrayBinary("string", array, stream)) return true; if(WriteSparseArrayBinary("unicode-string", array, stream)) return true; if(WriteDenseArrayBinary("integer", array, stream)) return true; if(WriteDenseArrayBinary("double", array, stream)) return true; if(WriteDenseArrayBinary("string", array, stream)) return true; if(WriteDenseArrayBinary("unicode-string", array, stream)) return true; } else { if(WriteSparseArrayAscii("integer", array, stream)) return true; if(WriteSparseArrayAscii("double", array, stream)) return true; if(WriteSparseArrayAscii("string", array, stream)) return true; if(WriteSparseArrayAscii("unicode-string", array, stream)) return true; if(WriteDenseArrayAscii("integer", array, stream)) return true; if(WriteDenseArrayAscii("double", array, stream)) return true; if(WriteDenseArrayAscii("string", array, stream)) return true; if(WriteDenseArrayAscii("unicode-string", array, stream)) return true; } throw std::runtime_error(std::string("Unhandled array type: ") + array->GetClassName()); } catch(std::exception& e) { vtkGenericWarningMacro("caught exception: " << e.what()); } return false; } vtkStdString vtkArrayWriter::Write(bool WriteBinary) { std::ostringstream oss; this->Write(oss, WriteBinary); return oss.str(); } vtkStdString vtkArrayWriter::Write(vtkArray* array, bool WriteBinary) { std::ostringstream oss; vtkArrayWriter::Write(array, oss, WriteBinary); return oss.str(); }