/*========================================================================= Program: Visualization Toolkit Module: vtkRISReader.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 "vtkRISReader.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(vtkRISReader); // 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'); //------------------------------------------------------------------------------ vtkRISReader::vtkRISReader() : FileName(nullptr) , Delimiter(nullptr) , MaxRecords(0) { this->SetDelimiter(";"); this->SetNumberOfInputPorts(0); this->SetNumberOfOutputPorts(1); } //------------------------------------------------------------------------------ vtkRISReader::~vtkRISReader() { this->SetDelimiter(nullptr); this->SetFileName(nullptr); } //------------------------------------------------------------------------------ void vtkRISReader::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 vtkRISReader::RequestData( vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector) { // Check that the filename has been specified if (!this->FileName) { vtkErrorMacro("vtkRISReader: You must specify a filename!"); return 0; } // Open the file vtksys::ifstream file(this->FileName, ios::in | ios::binary); if (!file) { vtkErrorMacro(<< "vtkRISReader 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; std::string line_buffer; 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)) { // Skip empty lines ... if (line_buffer.empty()) continue; // 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() >= 6 && line_buffer[2] == ' ' && line_buffer[3] == ' ' && line_buffer[4] == '-' && line_buffer[5] == ' ' ? line_buffer.substr(0, 2) : std::string(); if (tag_type == "ER") break; std::string tag_value = line_buffer.size() > 6 ? line_buffer.substr(6) : 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() >= 6 && line_buffer[2] == ' ' && line_buffer[3] == ' ' && line_buffer[4] == '-' && line_buffer[5] == ' ' ? line_buffer.substr(0, 2) : std::string(); if (next_tag_type == tag_type) { const std::string next_tag_value = line_buffer.size() > 6 ? line_buffer.substr(6) : std::string(); tag_value += delimiter + next_tag_value; } else if (next_tag_type.empty()) { tag_value += line_buffer; } else { break; } } // 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; } /* // Loop through every line in the file ... std::string tag; std::string tag_type; vtkStdString tag_value; bool explicit_tag; for(my_getline(file, line_buffer); file; my_getline(file, line_buffer)) { if(this->MaxRecords && record_count >= this->MaxRecords) break; // Skip empty lines ... if(line_buffer.empty()) continue; double progress = total_bytes ? static_cast(file.tellg()) / static_cast(total_bytes) : 0.5; this->InvokeEvent(vtkCommand::ProgressEvent, &progress); // Try to extract the tag, tag type, and tag value ... if(line_buffer.size() >= 6 && line_buffer[2] == ' ' && line_buffer[3] == ' ' && line_buffer[4] == '-' && line_buffer[5] == ' ') { explicit_tag = true; tag_type = line_buffer.substr(0, 2); tag_value = line_buffer.substr(6); } else { explicit_tag = false; tag_value = line_buffer; } // If this is the end of a record ... if(tag_type == "ER") { ++record_count; continue; } // If necessary, add a new row to the table to store this value ... while(table->GetNumberOfRows() < record_count + 1) table->InsertNextBlankRow(); // 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 ... vtkStdString old_value = table->GetValue(record_count, columns[tag_type]).ToString(); if(old_value.empty()) { table->SetValue(record_count, columns[tag_type], tag_value); } else { if(explicit_tag) { table->SetValue(record_count, columns[tag_type], (old_value + delimiter + tag_value).c_str()); } else { table->SetValue(record_count, columns[tag_type], (old_value + " " + tag_value).c_str()); } } } */ 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; }