// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
/**
* @class vtkXMLReader
* @brief Superclass for VTK's XML format readers.
*
* vtkXMLReader uses vtkXMLDataParser to parse a
* VTK XML input file.
* Concrete subclasses then traverse the parsed file structure and extract data.
*/
#ifndef vtkXMLReader_h
#define vtkXMLReader_h
#include "vtkAlgorithm.h"
#include "vtkIOXMLModule.h" // For export macro
#include "vtkSmartPointer.h" // for vtkSmartPointer.
#include // for std::string
VTK_ABI_NAMESPACE_BEGIN
class vtkAbstractArray;
class vtkCallbackCommand;
class vtkCharArray;
class vtkCommand;
class vtkDataArray;
class vtkDataArraySelection;
class vtkDataSet;
class vtkDataSetAttributes;
class vtkXMLDataElement;
class vtkXMLDataParser;
class vtkInformationVector;
class vtkInformation;
class vtkStringArray;
class VTKIOXML_EXPORT vtkXMLReader : public vtkAlgorithm
{
public:
vtkTypeMacro(vtkXMLReader, vtkAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent) override;
enum FieldType
{
POINT_DATA,
CELL_DATA,
OTHER
};
///@{
/**
* Get/Set the name of the input file.
*/
vtkSetFilePathMacro(FileName);
vtkGetFilePathMacro(FileName);
///@}
///@{
/**
* Enable reading from an InputString instead of the default, a file.
*/
vtkSetMacro(ReadFromInputString, vtkTypeBool);
vtkGetMacro(ReadFromInputString, vtkTypeBool);
vtkBooleanMacro(ReadFromInputString, vtkTypeBool);
///@{
/**
* Specify the InputString for use when reading from a character array.
* Optionally include the length for binary strings. Note that a copy
* of the string is made and stored. If this causes exceedingly large
* memory consumption, consider using InputArray instead.
*/
void SetInputString(const char* in);
void SetInputString(const char* in, int len);
void SetBinaryInputString(const char*, int len);
void SetInputString(const std::string& input)
{
this->SetBinaryInputString(input.c_str(), static_cast(input.length()));
}
///@}
///@{
/**
* Specify the vtkCharArray to be used when reading from a string.
* If set, this array has precedence over InputString.
* Use this instead of InputString to avoid the extra memory copy.
* It should be noted that if the underlying char* is owned by the
* user ( vtkCharArray::SetArray(array, 1); ) and is deleted before
* the reader, bad things will happen during a pipeline update.
*/
virtual void SetInputArray(vtkCharArray*);
///@}
/**
* Test whether the file (type) with the given name can be read by this
* reader. If the file has a newer version than the reader, we still say
* we can read the file type and we fail later, when we try to read the file.
* This enables clients (ParaView) to distinguish between failures when we
* need to look for another reader and failures when we don't.
*/
virtual int CanReadFile(VTK_FILEPATH const char* name);
///@{
/**
* Get the output as a vtkDataSet pointer.
*/
vtkDataSet* GetOutputAsDataSet();
vtkDataSet* GetOutputAsDataSet(int index);
///@}
///@{
/**
* Get the data array selection tables used to configure which data
* arrays are loaded by the reader.
*/
vtkGetObjectMacro(PointDataArraySelection, vtkDataArraySelection);
vtkGetObjectMacro(CellDataArraySelection, vtkDataArraySelection);
vtkGetObjectMacro(ColumnArraySelection, vtkDataArraySelection);
///@}
///@{
/**
* Get the number of point, cell or column arrays available in the input.
*/
int GetNumberOfPointArrays();
int GetNumberOfCellArrays();
int GetNumberOfColumnArrays();
///@}
///@{
/**
* Getters for time data array candidates.
*/
int GetNumberOfTimeDataArrays() const;
const char* GetTimeDataArray(int idx) const;
vtkGetObjectMacro(TimeDataStringArray, vtkStringArray);
///@}
///@{
/**
* Setter / Getter on ActiveTimeDataArrayName. This string
* holds the selected time array name. If set to `nullptr`,
* time values are the sequence of positive integers starting at zero.
* Default value is `TimeValue` for legacy reasons.
*/
vtkGetStringMacro(ActiveTimeDataArrayName);
vtkSetStringMacro(ActiveTimeDataArrayName);
///@}
///@{
/**
* Get the name of the point, cell, column or time array with the given index in
* the input.
*/
const char* GetPointArrayName(int index);
const char* GetCellArrayName(int index);
const char* GetColumnArrayName(int index);
///@}
///@{
/**
* Get/Set whether the point, cell, column or time array with the given name is to
* be read.
*/
int GetPointArrayStatus(const char* name);
int GetCellArrayStatus(const char* name);
void SetPointArrayStatus(const char* name, int status);
void SetCellArrayStatus(const char* name, int status);
int GetColumnArrayStatus(const char* name);
void SetColumnArrayStatus(const char* name, int status);
///@}
// For the specified port, copy the information this reader sets up in
// SetupOutputInformation to outInfo
virtual void CopyOutputInformation(vtkInformation* vtkNotUsed(outInfo), int vtkNotUsed(port)) {}
///@{
/**
* Which TimeStep to read.
*/
vtkSetMacro(TimeStep, int);
vtkGetMacro(TimeStep, int);
///@}
vtkGetMacro(NumberOfTimeSteps, int);
///@{
/**
* Which TimeStepRange to read
*/
vtkGetVector2Macro(TimeStepRange, int);
vtkSetVector2Macro(TimeStepRange, int);
///@}
/**
* Returns the internal XML parser. This can be used to access
* the XML DOM after RequestInformation() was called.
*/
vtkXMLDataParser* GetXMLParser() { return this->XMLParser; }
vtkTypeBool ProcessRequest(vtkInformation* request, vtkInformationVector** inputVector,
vtkInformationVector* outputVector) override;
///@{
/**
* Set/get the ErrorObserver for the internal reader
* This is useful for applications that want to catch error messages.
*/
void SetReaderErrorObserver(vtkCommand*);
vtkGetObjectMacro(ReaderErrorObserver, vtkCommand);
///@}
///@{
/**
* Set/get the ErrorObserver for the internal xml parser
* This is useful for applications that want to catch error messages.
*/
void SetParserErrorObserver(vtkCommand*);
vtkGetObjectMacro(ParserErrorObserver, vtkCommand);
///@}
protected:
vtkXMLReader();
~vtkXMLReader() override;
///@{
/**
* Pipeline execution methods to be defined by subclass. Called by
* corresponding RequestData methods after appropriate setup has been
* done.
*/
virtual int ReadXMLInformation();
virtual void ReadXMLData();
///@}
/**
* Get the name of the data set being read.
*/
virtual const char* GetDataSetName() = 0;
/**
* Test if the reader can read a file with the given version number.
*/
virtual int CanReadFileVersion(int major, int minor);
/**
* Setup the output with no data available. Used in error cases.
*/
virtual void SetupEmptyOutput() = 0;
/**
* Setup the output's information.
*/
virtual void SetupOutputInformation(vtkInformation* vtkNotUsed(outInfo)) {}
/**
* Setup the output's data with allocation.
*/
virtual void SetupOutputData();
/**
* Read the primary element from the file. This is the element
* whose name is the value returned by GetDataSetName().
*/
virtual int ReadPrimaryElement(vtkXMLDataElement* ePrimary);
/**
* Read the top-level element from the file. This is always the
* VTKFile element.
*/
virtual int ReadVTKFile(vtkXMLDataElement* eVTKFile);
/**
* If the IdType argument is present in the provided XMLDataElement
* and the provided dataType has the same size with VTK_ID_TYPE on this build of VTK,
* returns VTK_ID_TYPE. Returns dataType in any other cases.
*/
int GetLocalDataType(vtkXMLDataElement* da, int datatype);
/**
* Create a vtkAbstractArray from its corresponding XML representation.
* Does not allocate.
*/
vtkAbstractArray* CreateArray(vtkXMLDataElement* da);
/**
* Create a vtkInformationKey from its corresponding XML representation.
* Stores it in the instance of vtkInformationProvided. Does not allocate.
*/
int CreateInformationKey(vtkXMLDataElement* eInfoKey, vtkInformation* info);
/**
* Populates the info object with the InformationKey children in infoRoot.
* Returns false if errors occur.
*/
bool ReadInformation(vtkXMLDataElement* infoRoot, vtkInformation* info);
///@{
/**
* Internal utility methods.
*/
virtual int OpenStream();
virtual void CloseStream();
virtual int OpenVTKFile();
virtual void CloseVTKFile();
virtual int OpenVTKString();
virtual void CloseVTKString();
virtual void CreateXMLParser();
virtual void DestroyXMLParser();
void SetupCompressor(const char* type);
int CanReadFileVersionString(const char* version);
///@}
/**
* This method is used by CanReadFile() to check if the reader can read an XML
* with the primary element with the given name. Default implementation
* compares the name with the text returned by this->GetDataSetName().
*/
virtual int CanReadFileWithDataType(const char* dsname);
/**
* Returns the major version for the file being read. -1 when invalid.
*/
vtkGetMacro(FileMajorVersion, int);
/**
* Returns the minor version for the file being read. -1 when invalid.
*/
vtkGetMacro(FileMinorVersion, int);
///@{
/**
* Utility methods for subclasses.
*/
int IntersectExtents(int* extent1, int* extent2, int* result);
int Min(int a, int b);
int Max(int a, int b);
void ComputePointDimensions(int* extent, int* dimensions);
void ComputePointIncrements(int* extent, vtkIdType* increments);
void ComputeCellDimensions(int* extent, int* dimensions);
void ComputeCellIncrements(int* extent, vtkIdType* increments);
vtkIdType GetStartTuple(int* extent, vtkIdType* increments, int i, int j, int k);
void ReadAttributeIndices(vtkXMLDataElement* eDSA, vtkDataSetAttributes* dsa);
char** CreateStringArray(int numStrings);
void DestroyStringArray(int numStrings, char** strings);
///@}
/**
* Read an Array values starting at the given index and up to numValues.
* This method assumes that the array is of correct size to
* accommodate all numValues values. arrayIndex is the value index at which the read
* values will be put in the array.
*/
virtual int ReadArrayValues(vtkXMLDataElement* da, vtkIdType arrayIndex, vtkAbstractArray* array,
vtkIdType startIndex, vtkIdType numValues, FieldType type = OTHER);
/**
* Read an Array values starting at the given tuple index and up to numTuples
* taking into account the number of components declared in array.
* This method assumes that the array is of correct size to
* accommodate all numTuples multiplied by number of components.
* arrayTupleIndex is the tuple index at which the read
* values will be put in the array.
*/
virtual int ReadArrayTuples(vtkXMLDataElement* da, vtkIdType arrayTupleIndex,
vtkAbstractArray* array, vtkIdType startTupleIndex, vtkIdType numTuples,
FieldType type = OTHER);
/**
* Setup the data array selections for the input's set of arrays.
*/
void SetDataArraySelections(vtkXMLDataElement* eDSA, vtkDataArraySelection* sel);
int SetFieldDataInfo(vtkXMLDataElement* eDSA, int association, vtkIdType numTuples,
vtkInformationVector*(&infoVector));
///@{
/**
* Check whether the given array element is an enabled array.
*/
int PointDataArrayIsEnabled(vtkXMLDataElement* ePDA);
int CellDataArrayIsEnabled(vtkXMLDataElement* eCDA);
///@}
/**
* Callback registered with the SelectionObserver.
*/
static void SelectionModifiedCallback(
vtkObject* caller, unsigned long eid, void* clientdata, void* calldata);
/**
* Give concrete classes an option to squeeze any output arrays
* at the end of RequestData.
*/
virtual void SqueezeOutputArrays(vtkDataObject*) {}
/**
* XML files have not consistently saved out adequate meta-data in past to
* correctly create vtkIdTypeArray for global ids and pedigree ids. This was
* fixed in vtk/vtk!4819, but all older files don't recreated vtkIdTypeArray
* correctly. If global ids or pedigree ids are not of type vtkIdTypeArray VTK
* does not handle them correctly, resulting in paraview/paraview#20239. This
* methods "annotates" the XML for arrays that are tagged as global/pedigree
* ids so they are read properly.
*/
void MarkIdTypeArrays(vtkXMLDataElement* da);
// The vtkXMLDataParser instance used to hide XML reading details.
vtkXMLDataParser* XMLParser;
// The FieldData element representation.
vtkXMLDataElement* FieldDataElement;
// The input file's name.
char* FileName;
// The stream used to read the input.
istream* Stream;
// Whether this object is reading from a string or a file.
// Default is 0: read from file.
vtkTypeBool ReadFromInputString;
// The input string.
std::string InputString;
// The input array. Keeps a low memory footprint by sourcing StringStream from contents of this
// array
vtkCharArray* InputArray;
// The array selections.
vtkDataArraySelection* PointDataArraySelection;
vtkDataArraySelection* CellDataArraySelection;
vtkDataArraySelection* ColumnArraySelection;
vtkStringArray* TimeDataStringArray;
/**
* Name of the field-data array used to determine the time for the dataset
* being read.
*/
char* ActiveTimeDataArrayName;
/**
* Populated in `ReadXMLInformation` from the field data for the array chosen
* using ActiveTimeDataArrayName, if any. `nullptr` otherwise.
*/
vtkSmartPointer TimeDataArray;
// The observer to modify this object when the array selections are
// modified.
vtkCallbackCommand* SelectionObserver;
// Whether there was an error reading the file in RequestInformation.
int InformationError;
// Whether there was an error reading the file in RequestData.
int DataError;
// incrementally fine-tuned progress updates.
virtual void GetProgressRange(float* range);
virtual void SetProgressRange(const float range[2], int curStep, int numSteps);
virtual void SetProgressRange(const float range[2], int curStep, const float* fractions);
virtual void UpdateProgressDiscrete(float progress);
float ProgressRange[2];
virtual int RequestData(vtkInformation* request, vtkInformationVector** inputVector,
vtkInformationVector* outputVector);
virtual int RequestDataObject(vtkInformation* vtkNotUsed(request),
vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* vtkNotUsed(outputVector))
{
return 1;
}
virtual int RequestInformation(vtkInformation* request, vtkInformationVector** inputVector,
vtkInformationVector* outputVector);
vtkTimeStamp ReadMTime;
// Whether there was an error reading the XML.
int ReadError;
// For structured data keep track of dimensions empty of cells. For
// unstructured data these are always zero. This is used to support
// 1-D and 2-D cell data.
int AxesEmpty[3];
// The timestep currently being read.
int TimeStep;
int CurrentTimeStep;
int NumberOfTimeSteps;
void SetNumberOfTimeSteps(int num);
// buffer for reading timestep from the XML file the length is of
// NumberOfTimeSteps and therefore is always long enough
int* TimeSteps;
// Store the range of time steps
int TimeStepRange[2];
// Now we need to save what was the last time read for each kind of
// data to avoid rereading it that is to say we need a var for
// e.g. PointData/CellData/Points/Cells...
// See SubClass for details with member vars like PointsTimeStep/PointsOffset
// Helper function useful to know if a timestep is found in an array of timestep
static int IsTimeStepInArray(int timestep, int* timesteps, int length);
vtkDataObject* GetCurrentOutput();
vtkInformation* GetCurrentOutputInformation();
// Flag for whether DataProgressCallback should actually update
// progress.
int InReadData;
virtual void ConvertGhostLevelsToGhostType(FieldType, vtkAbstractArray*, vtkIdType, vtkIdType) {}
/*
* Populate the output's FieldData with the file's FieldData tags content
*/
void ReadFieldData();
private:
// The stream used to read the input if it is in a file.
istream* FileStream;
// The stream used to read the input if it is in a string.
std::istringstream* StringStream;
int TimeStepWasReadOnce;
int FileMajorVersion;
int FileMinorVersion;
vtkDataObject* CurrentOutput;
vtkInformation* CurrentOutputInformation;
vtkXMLReader(const vtkXMLReader&) = delete;
void operator=(const vtkXMLReader&) = delete;
vtkCommand* ReaderErrorObserver;
vtkCommand* ParserErrorObserver;
};
VTK_ABI_NAMESPACE_END
#endif