/*========================================================================= Program: Visualization Toolkit Module: vtkArrayReader.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. =========================================================================*/ /*------------------------------------------------------------------------- Copyright 2008 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. -------------------------------------------------------------------------*/ #include "vtkArrayReader.h" #include "vtkCommand.h" #include "vtkDenseArray.h" #include "vtkObjectFactory.h" #include "vtkSmartPointer.h" #include "vtkSparseArray.h" #include "vtkUnicodeString.h" #include #include #include vtkStandardNewMacro(vtkArrayReader); namespace { template void ExtractValue(istream& stream, ValueT& value) { stream >> value; } void ExtractValue(istream& stream, vtkStdString& value) { std::getline(stream, value); vtkStdString::size_type begin, end; begin = 0; end = value.size(); while ((begin < end) && isspace(value[begin])) begin++; while ((begin < end) && isspace(value[end-1])) end--; value = value.substr(begin, end); } void ExtractValue(istream& stream, vtkUnicodeString& value) { std::string buffer; std::getline(stream, buffer); vtkStdString::size_type begin, end; begin = 0; end = buffer.size(); while ((begin < end) && isspace(buffer[begin])) begin++; while ((begin < end) && isspace(buffer[end-1])) end--; buffer = buffer.substr(begin, end); value = vtkUnicodeString::from_utf8(buffer); } void ReadHeader(istream& stream, vtkArrayExtents& extents, vtkArrayExtents::SizeT& non_null_size, vtkArray* array) { if(!array) throw std::runtime_error("Missing array."); // Load the array name ... std::string name; std::getline(stream, name); array->SetName(name); // Load array extents ... std::string extents_string; std::getline(stream, extents_string); std::istringstream extents_buffer(extents_string); vtkArrayExtents::CoordinateT extent; std::vector temp_extents; for(extents_buffer >> extent; extents_buffer; extents_buffer >> extent) temp_extents.push_back(extent); extents.SetDimensions(0); while(temp_extents.size() > 1) { const vtkArrayExtents::CoordinateT begin = temp_extents.front(); temp_extents.erase(temp_extents.begin()); const vtkArrayExtents::CoordinateT end = temp_extents.front(); temp_extents.erase(temp_extents.begin()); extents.Append(vtkArrayRange(begin, end)); } if(extents.GetDimensions() < 1) throw std::runtime_error("Array cannot have fewer than one dimension."); if(temp_extents.empty()) throw std::runtime_error("Missing non null size."); non_null_size = temp_extents.back(); array->Resize(extents); // Load dimension-labels ... for(vtkArrayExtents::DimensionT i = 0; i != extents.GetDimensions(); ++i) { std::string label; std::getline(stream, label); array->SetDimensionLabel(i, label); } } void ReadEndianOrderMark(istream& stream, bool& swap_endian) { // Load the endian-order mark ... vtkTypeUInt32 endian_order = 0; stream.read( reinterpret_cast(&endian_order), sizeof(endian_order)); swap_endian = endian_order == 0x12345678 ? false : true; } template vtkSparseArray* ReadSparseArrayBinary(istream& stream) { // Create the array ... vtkSmartPointer > array = vtkSmartPointer >::New(); // Read the file header ... vtkArrayExtents extents; vtkArrayExtents::SizeT non_null_size = 0; bool swap_endian = false; ReadHeader(stream, extents, non_null_size, array); ReadEndianOrderMark(stream, swap_endian); // Read the array nullptr value ... ValueT null_value; stream.read( reinterpret_cast(&null_value), sizeof(ValueT)); array->SetNullValue(null_value); // Read array coordinates ... array->ReserveStorage(non_null_size); for(vtkArray::DimensionT i = 0; i != array->GetDimensions(); ++i) { stream.read( reinterpret_cast(array->GetCoordinateStorage(i)), non_null_size * sizeof(vtkArray::CoordinateT)); } // Read array values ... stream.read( reinterpret_cast(array->GetValueStorage()), non_null_size * sizeof(ValueT)); array->Register(nullptr); return array; } template<> vtkSparseArray* ReadSparseArrayBinary(istream& stream) { // Create the array ... vtkSmartPointer > array = vtkSmartPointer >::New(); // Read the file header ... vtkArrayExtents extents; vtkArrayExtents::SizeT non_null_size = 0; bool swap_endian = false; ReadHeader(stream, extents, non_null_size, array); ReadEndianOrderMark(stream, swap_endian); // Read the array nullptr value ... std::string null_value; for(int character = stream.get(); stream; character = stream.get()) { if(character == 0) { array->SetNullValue(null_value); break; } else { null_value += character; } } // Read array coordinates ... array->ReserveStorage(non_null_size); for(vtkArray::DimensionT i = 0; i != array->GetDimensions(); ++i) { stream.read( reinterpret_cast(array->GetCoordinateStorage(i)), non_null_size * sizeof(vtkArray::CoordinateT)); } // Read array values ... std::string buffer; vtkArray::SizeT n = 0; for(int character = stream.get(); stream; character = stream.get()) { if(character == 0) { array->SetValueN(n++, buffer); buffer.resize(0); } else { buffer += character; } } array->Register(nullptr); return array; } template<> vtkSparseArray* ReadSparseArrayBinary(istream& stream) { // Create the array ... vtkSmartPointer > array = vtkSmartPointer >::New(); // Read the file header ... vtkArrayExtents extents; vtkArrayExtents::SizeT non_null_size = 0; bool swap_endian = false; ReadHeader(stream, extents, non_null_size, array); ReadEndianOrderMark(stream, swap_endian); // Read the array nullptr value ... std::string null_value; for(int character = stream.get(); stream; character = stream.get()) { if(character == 0) { array->SetNullValue(vtkUnicodeString::from_utf8(null_value)); break; } else { null_value += character; } } // Read array coordinates ... array->ReserveStorage(non_null_size); for(vtkArray::DimensionT i = 0; i != array->GetDimensions(); ++i) { stream.read( reinterpret_cast(array->GetCoordinateStorage(i)), non_null_size * sizeof(vtkArray::CoordinateT)); } // Read array values ... std::string buffer; vtkArray::SizeT n = 0; for(int character = stream.get(); stream; character = stream.get()) { if(character == 0) { array->SetValueN(n++, vtkUnicodeString::from_utf8(buffer)); buffer.resize(0); } else { buffer += character; } } array->Register(nullptr); return array; } template vtkDenseArray* ReadDenseArrayBinary(istream& stream) { // Create the array ... vtkSmartPointer > array = vtkSmartPointer >::New(); // Read the file header ... vtkArrayExtents extents; vtkArrayExtents::SizeT non_null_size = 0; bool swap_endian = false; ReadHeader(stream, extents, non_null_size, array); ReadEndianOrderMark(stream, swap_endian); // Read array values ... stream.read( reinterpret_cast(array->GetStorage()), non_null_size * sizeof(ValueT)); if(stream.eof()) throw std::runtime_error("Premature end-of-file."); if(stream.bad()) throw std::runtime_error("Error while reading file."); array->Register(nullptr); return array; } template<> vtkDenseArray* ReadDenseArrayBinary(istream& stream) { // Create the array ... vtkSmartPointer > array = vtkSmartPointer >::New(); // Read the file header ... vtkArrayExtents extents; vtkArrayExtents::SizeT non_null_size = 0; bool swap_endian = false; ReadHeader(stream, extents, non_null_size, array); ReadEndianOrderMark(stream, swap_endian); // Read array values ... std::string buffer; vtkArray::SizeT n = 0; for(int character = stream.get(); stream; character = stream.get()) { if(character == 0) { array->SetValueN(n++, buffer); buffer.resize(0); } else { buffer += character; } } array->Register(nullptr); return array; } template<> vtkDenseArray* ReadDenseArrayBinary(istream& stream) { // Create the array ... vtkSmartPointer > array = vtkSmartPointer >::New(); // Read the file header ... vtkArrayExtents extents; vtkArrayExtents::SizeT non_null_size = 0; bool swap_endian = false; ReadHeader(stream, extents, non_null_size, array); ReadEndianOrderMark(stream, swap_endian); // Read array values ... std::string buffer; vtkArray::SizeT n = 0; for(int character = stream.get(); stream; character = stream.get()) { if(character == 0) { array->SetValueN(n++, vtkUnicodeString::from_utf8(buffer)); buffer.resize(0); } else { buffer += character; } } array->Register(nullptr); return array; } template vtkSparseArray* ReadSparseArrayAscii(istream& stream) { // Create the array ... vtkSmartPointer > array = vtkSmartPointer >::New(); // Read the stream header ... vtkArrayExtents extents; vtkArrayExtents::SizeT non_null_size = 0; ReadHeader(stream, extents, non_null_size, array); if(non_null_size > extents.GetSize()) throw std::runtime_error("Too many values for a sparse array."); // Read the array nullptr value ... std::string line_buffer; std::getline(stream, line_buffer); if(!stream) throw std::runtime_error("Premature end-of-stream reading nullptr value."); std::istringstream line_stream(line_buffer); ValueT null_value; ExtractValue(line_stream, null_value); if(!line_stream) throw std::runtime_error("Missing nullptr value."); array->SetNullValue(null_value); // Setup storage for the stream contents ... array->ReserveStorage(non_null_size); std::vector coordinates(array->GetDimensions()); for(vtkArray::DimensionT j = 0; j != array->GetDimensions(); ++j) coordinates[j] = array->GetCoordinateStorage(j); ValueT* value = array->GetValueStorage(); // Read the stream contents ... vtkArray::SizeT value_count = 0; for(; value_count < non_null_size; ++value_count) { std::getline(stream, line_buffer); if(!stream) break; line_stream.clear(); line_stream.str(line_buffer); for(vtkArray::DimensionT j = 0; j != array->GetDimensions(); ++j) { line_stream >> *(coordinates[j] + value_count); if(!extents[j].Contains(*(coordinates[j] + value_count))) throw std::runtime_error("Coordinate out-of-bounds."); if(!line_stream) throw std::runtime_error("Missing coordinate."); } ExtractValue(line_stream, *(value + value_count)); if(!line_stream) throw std::runtime_error("Missing value."); } // Ensure we loaded enough values ... if(value_count != non_null_size) throw std::runtime_error("Stream doesn't contain enough values."); array->Register(nullptr); return array; } template vtkDenseArray* ReadDenseArrayAscii(istream& stream) { // Create the array ... vtkSmartPointer > array = vtkSmartPointer >::New(); // Read the file header ... vtkArrayExtents extents; vtkArrayExtents::SizeT non_null_size = 0; ReadHeader(stream, extents, non_null_size, array); if(non_null_size != extents.GetSize()) throw std::runtime_error("Incorrect number of values for a dense array."); // Read the file contents ... ValueT value; vtkArray::SizeT n = 0; vtkArrayCoordinates coordinates; for(; n < non_null_size; ++n) { ExtractValue(stream, value); if (!stream) break; extents.GetRightToLeftCoordinatesN(n, coordinates); array->SetValue(coordinates, value); } if(n != non_null_size) throw std::runtime_error("Stream doesn't contain enough values."); // If there is more in the stream (e.g. in vtkArrayDataReader), // eat the newline so the stream is ready for the next vtkArray. if(stream) { stream.get(); } array->Register(nullptr); return array; } } // End anonymous namespace vtkArrayReader::vtkArrayReader() : FileName(nullptr) { this->SetNumberOfInputPorts(0); this->ReadFromInputString = false; } vtkArrayReader::~vtkArrayReader() { this->SetFileName(nullptr); } void vtkArrayReader::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "FileName: " << (this->FileName ? this->FileName : "(none)") << endl; os << indent << "InputString: " << this->InputString << endl; os << indent << "ReadFromInputString: " << (this->ReadFromInputString ? "on" : "off") << endl; } void vtkArrayReader::SetInputString(const vtkStdString& string) { this->InputString = string; this->Modified(); } vtkStdString vtkArrayReader::GetInputString() { return this->InputString; } int vtkArrayReader::RequestData( vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector) { try { vtkArray* array = nullptr; if(this->ReadFromInputString) { array = this->Read(this->InputString); } else { if(!this->FileName) throw std::runtime_error("FileName not set."); ifstream file(this->FileName, std::ios::binary); array = this->Read(file); } if(!array) throw std::runtime_error("Error reading array."); vtkArrayData* const array_data = vtkArrayData::GetData(outputVector); array_data->ClearArrays(); array_data->AddArray(array); array->Delete(); return 1; } catch(std::exception& e) { vtkErrorMacro(<< e.what()); } return 0; } vtkArray* vtkArrayReader::Read(const vtkStdString& str) { std::istringstream iss(str); return vtkArrayReader::Read(iss); } vtkArray* vtkArrayReader::Read(istream& stream) { try { // Read enough of the file header to identify the type ... std::string header_string; std::getline(stream, header_string); std::istringstream header_buffer(header_string); std::string header_magic; std::string header_type; header_buffer >> header_magic >> header_type; // Read input file type, binary or ascii std::string header_file_string; std::string header_file_type; std::getline(stream, header_file_string); std::istringstream header_file_type_buffer(header_file_string); header_file_type_buffer >> header_file_type; bool read_binary = false; if(header_file_type == "binary") { read_binary = true; } else if(header_file_type != "ascii") { throw std::runtime_error("Unknown file type: " + header_file_type); } if(header_magic == "vtk-sparse-array") { if(header_type == "integer") { return (read_binary ? ReadSparseArrayBinary(stream) : ReadSparseArrayAscii(stream)); } else if(header_type == "double") { return (read_binary ? ReadSparseArrayBinary(stream) : ReadSparseArrayAscii(stream)); } else if(header_type == "string") { return (read_binary ? ReadSparseArrayBinary(stream) : ReadSparseArrayAscii(stream)); } else if(header_type == "unicode-string") { return (read_binary ? ReadSparseArrayBinary(stream) : ReadSparseArrayAscii(stream)); } else { throw std::runtime_error("Unknown array type: " + header_type); } } else if(header_magic == "vtk-dense-array") { if(header_type == "integer") { return (read_binary ? ReadDenseArrayBinary(stream) : ReadDenseArrayAscii(stream)); } else if(header_type == "double") { return (read_binary ? ReadDenseArrayBinary(stream) : ReadDenseArrayAscii(stream)); } else if(header_type == "string") { return (read_binary ? ReadDenseArrayBinary(stream) : ReadDenseArrayAscii(stream)); } else if(header_type == "unicode-string") { return (read_binary ? ReadDenseArrayBinary(stream) : ReadDenseArrayAscii(stream)); } else { throw std::runtime_error("Unknown array type: " + header_type); } } else { throw std::runtime_error("Unknown file type: " + header_magic); } } catch(std::exception& e) { vtkGenericWarningMacro(<< e.what()); } return nullptr; }