/*========================================================================= Program: Visualization Toolkit Module: vtkISIReader.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 "vtkISIReader.h" #include "vtkCommand.h" #include "vtkObjectFactory.h" #include "vtkStdString.h" #include "vtkStringArray.h" #include "vtkTable.h" #include "vtkVariant.h" #include "vtksys/FStream.hxx" #include #include vtkStandardNewMacro(vtkISIReader); // Not all platforms support std::getline(istream&, std::string) so // we have to provide our own static istream& my_getline(istream& input, std::string& output, char delimiter = '\n'); //------------------------------------------------------------------------------ vtkISIReader::vtkISIReader() : FileName(nullptr) , Delimiter(nullptr) , MaxRecords(0) { this->SetDelimiter(";"); this->SetNumberOfInputPorts(0); this->SetNumberOfOutputPorts(1); } //------------------------------------------------------------------------------ vtkISIReader::~vtkISIReader() { this->SetDelimiter(nullptr); this->SetFileName(nullptr); } //------------------------------------------------------------------------------ void vtkISIReader::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "FileName: " << (this->FileName ? this->FileName : "(none)") << endl; os << indent << "Delimiter: " << (this->Delimiter ? this->Delimiter : "(none)") << endl; os << indent << "MaxRecords: " << this->MaxRecords << endl; } //------------------------------------------------------------------------------ int vtkISIReader::RequestData( vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector) { // Check that the filename has been specified if (!this->FileName) { vtkErrorMacro("vtkISIReader: You must specify a filename!"); return 0; } // Open the file vtksys::ifstream file(this->FileName, ios::in | ios::binary); if (!file) { vtkErrorMacro(<< "vtkISIReader could not open file " << this->FileName); return 0; } // Get the total size of the file ... file.seekg(0, ios::end); const int total_bytes = file.tellg(); // Go back to the top of the file file.seekg(0, ios::beg); // Store the text data into a vtkTable vtkTable* table = vtkTable::GetData(outputVector); // Keep a mapping of column-name to column-index for quick lookups ... std::map columns; // Get header information from the first two lines of the file ... std::string line_buffer; my_getline(file, line_buffer); if (line_buffer != "FN ISI Export Format") { vtkErrorMacro(<< "File " << this->FileName << " is not an ISI file"); return 0; } my_getline(file, line_buffer); if (line_buffer != "VR 1.0") { vtkErrorMacro(<< "File " << this->FileName << " is not an ISI version 1.0 file"); return 0; } const std::string delimiter(this->Delimiter ? this->Delimiter : ""); int record_count = 0; // For each record in the file ... for (my_getline(file, line_buffer); file; my_getline(file, line_buffer)) { // Stop if we exceed the maximum number of records ... if (this->MaxRecords && record_count >= this->MaxRecords) break; double progress = total_bytes ? static_cast(file.tellg()) / static_cast(total_bytes) : 0.5; this->InvokeEvent(vtkCommand::ProgressEvent, &progress); // Add a new row to the table for the record ... table->InsertNextBlankRow(); // For each field in the record ... for (; file;) { const std::string tag_type = line_buffer.size() >= 2 ? line_buffer.substr(0, 2) : std::string(); if (tag_type == "ER") break; if (tag_type == "EF") break; std::string tag_value = line_buffer.size() > 3 ? line_buffer.substr(3) : std::string(); // For each line in the field ... for (my_getline(file, line_buffer); file; my_getline(file, line_buffer)) { const std::string next_tag_type = line_buffer.size() >= 2 ? line_buffer.substr(0, 2) : std::string(); if (next_tag_type != " ") break; const std::string next_tag_value = line_buffer.size() > 3 ? line_buffer.substr(3) : std::string(); tag_value += delimiter + next_tag_value; } // If necessary, add a new column to the table to store this value ... if (!columns.count(tag_type)) { vtkStringArray* const new_column = vtkStringArray::New(); new_column->SetName(tag_type.c_str()); new_column->SetNumberOfTuples(record_count + 1); columns[tag_type] = table->GetNumberOfColumns(); table->AddColumn(new_column); new_column->Delete(); } // Set the table value ... table->SetValue(record_count, columns[tag_type], tag_value.c_str()); } // Keep track of the current record count ... ++record_count; } return 1; } //------------------------------------------------------------------------------ static istream& my_getline(istream& input, std::string& output, char delimiter) { output = ""; unsigned int numCharactersRead = 0; int nextValue = 0; while ((nextValue = input.get()) != EOF && numCharactersRead < output.max_size()) { ++numCharactersRead; char downcast = static_cast(nextValue); if (downcast == delimiter || (delimiter == '\n' && downcast == '\r')) { if (delimiter == '\n' && downcast == '\r' && input.peek() == '\n') { input.get(); } return input; } else { output += downcast; } } return input; }