/*========================================================================= Program: Visualization Toolkit Module: vtkOpenFOAMReader.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. =========================================================================*/ // Thanks to Terry Jordan of SAIC at the National Energy // Technology Laboratory who developed this class. // Please address all comments to Terry Jordan (terry.jordan@sa.netl.doe.gov) // // Token-based FoamFile format lexer/parser, // performance/stability/compatibility enhancements, gzipped file // support, lagrangian field support, variable timestep support, // builtin cell-to-point filter, pointField support, polyhedron // decomposition support, OF 1.5 extended format support, multiregion // support, old mesh format support, parallelization support for // decomposed cases in conjunction with vtkPOpenFOAMReader, et. al. by // Takuya Oshima of Niigata University, Japan (oshima@eng.niigata-u.ac.jp) // // * GUI Based selection of mesh regions and fields available in the case // * Minor bug fixes / Strict memory allocation checks // * Minor performance enhancements // by Philippose Rajan (sarith@rocketmail.com) // Hijack the CRC routine of zlib to omit CRC check for gzipped files // (on OSes other than Windows where the mechanism doesn't work due // to pre-bound DLL symbols) if set to 1, or not (set to 0). Affects // performance by about 3% - 4%. #define VTK_FOAMFILE_OMIT_CRCCHECK 0 // The input/output buffer sizes for zlib in bytes. #define VTK_FOAMFILE_INBUFSIZE (16384) #define VTK_FOAMFILE_OUTBUFSIZE (131072) #define VTK_FOAMFILE_INCLUDE_STACK_SIZE (10) #if defined(_MSC_VER) #define _CRT_SECURE_NO_WARNINGS 1 // No strtoll on msvc: #define strtoll _strtoi64 #endif #if VTK_FOAMFILE_OMIT_CRCCHECK #define ZLIB_INTERNAL #endif // for possible future extension of linehead-aware directives #define VTK_FOAMFILE_RECOGNIZE_LINEHEAD 0 #include "vtkOpenFOAMReader.h" #include #include "vtksys/SystemTools.hxx" #include "vtksys/RegularExpression.hxx" #include #include "vtk_zlib.h" #include "vtkAssume.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkCharArray.h" #include "vtkCollection.h" #include "vtkConvexPointSet.h" #include "vtkDataArraySelection.h" #include "vtkDirectory.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkHexahedron.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkIntArray.h" #include "vtkMultiBlockDataSet.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkPolygon.h" #include "vtkPyramid.h" #include "vtkQuad.h" #include "vtkSortDataArray.h" #include "vtkStdString.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkStringArray.h" #include "vtkTetra.h" #include "vtkTriangle.h" #include "vtkTypeInt32Array.h" #include "vtkTypeInt64Array.h" #include "vtkTypeTraits.h" #include "vtkUnstructuredGrid.h" #include "vtkVertex.h" #include "vtkWedge.h" #if !(defined(_WIN32) && !defined(__CYGWIN__) || defined(__LIBCATAMOUNT__)) // for getpwnam() / getpwuid() #include #include // for getuid() #include #endif // for fabs() #include // for isalnum() / isspace() / isdigit() #include #include #include #if VTK_FOAMFILE_OMIT_CRCCHECK uLong ZEXPORT crc32(uLong, const Bytef *, uInt) { return 0; } #endif vtkStandardNewMacro(vtkOpenFOAMReader); namespace { // Given a data array and a flag indicating whether 64 bit labels are used, // lookup and return a single element in the array. The data array must // be either a vtkTypeInt32Array or vtkTypeInt64Array. vtkTypeInt64 GetLabelValue(vtkDataArray *array, vtkIdType idx, bool use64BitLabels) { if (!use64BitLabels) { vtkTypeInt64 result = static_cast( static_cast(array)->GetValue(idx)); assert(result >= -1); // some arrays store -1 == 'uninitialized'. return result; } else { vtkTypeInt64 result = static_cast(array)->GetValue(idx); assert(result >= -1); // some arrays store -1 == 'uninitialized'. return result; } } // Setter analogous to the above getter. void SetLabelValue(vtkDataArray *array, vtkIdType idx, vtkTypeInt64 value, bool use64BitLabels) { if (!use64BitLabels) { assert(static_cast(value) >= 0); static_cast(array)->SetValue( idx, static_cast(value)); } else { assert(value >= 0); static_cast(array)->SetValue(idx, value); } } // Similar to above, but increments the specified value by one. void IncrementLabelValue(vtkDataArray *array, vtkIdType idx, bool use64BitLabels) { if (!use64BitLabels) { vtkTypeInt32 val = static_cast(array)->GetValue(idx); assert(val + 1 >= 0); static_cast(array)->SetValue(idx, val + 1); } else { vtkTypeInt64 val = static_cast(array)->GetValue(idx); assert(val + 1 >= 0); static_cast(array)->SetValue(idx, val + 1); } } // Another helper for appending an id to a list void AppendLabelValue(vtkDataArray *array, vtkTypeInt64 val, bool use64BitLabels) { if (!use64BitLabels) { assert(static_cast(val) >= 0); static_cast(array)->InsertNextValue( static_cast(val)); } else { assert(val >= 0); static_cast(array)->InsertNextValue(val); } } // Another 64/32 bit label helper. Given a void* c-array, set/get element idx. // The array must be of vtkTypeInt32 or vtkTypeInt64. void SetLabelValue(void *array, size_t idx, vtkTypeInt64 value, bool use64BitLabels) { if (!use64BitLabels) { assert(static_cast(value) >= 0); static_cast(array)[idx] = static_cast(value); } else { assert(value >= 0); static_cast(array)[idx] = value; } } vtkTypeInt64 GetLabelValue(const void *array, size_t idx, bool use64BitLabels) { if (!use64BitLabels) { vtkTypeInt64 result = static_cast( static_cast(array)[idx]); assert(result >= 0); return result; } else { vtkTypeInt64 result = static_cast(array)[idx]; assert(result >= 0); return result; } } } // end anon namespace // forward declarations template struct vtkFoamArrayVector : public std::vector { private: typedef std::vector Superclass; public: ~vtkFoamArrayVector() { for(size_t arrayI = 0; arrayI < Superclass::size(); arrayI++) { if(Superclass::operator[](arrayI)) { Superclass::operator[](arrayI)->Delete(); } } } }; typedef vtkFoamArrayVector vtkFoamLabelArrayVector; typedef vtkFoamArrayVector vtkFoamIntArrayVector; typedef vtkFoamArrayVector vtkFoamFloatArrayVector; struct vtkFoamLabelVectorVector; template struct vtkFoamLabelVectorVectorImpl; typedef vtkFoamLabelVectorVectorImpl vtkFoamLabel32VectorVector; typedef vtkFoamLabelVectorVectorImpl vtkFoamLabel64VectorVector; struct vtkFoamError; struct vtkFoamToken; struct vtkFoamFileStack; struct vtkFoamFile; struct vtkFoamIOobject; template struct vtkFoamReadValue; struct vtkFoamEntryValue; struct vtkFoamEntry; struct vtkFoamDict; //----------------------------------------------------------------------------- // class vtkOpenFOAMReaderPrivate // the reader core of vtkOpenFOAMReader class vtkOpenFOAMReaderPrivate : public vtkObject { public: static vtkOpenFOAMReaderPrivate *New(); vtkTypeMacro(vtkOpenFOAMReaderPrivate, vtkObject); vtkDoubleArray *GetTimeValues() {return this->TimeValues;} vtkGetMacro(TimeStep, int); vtkSetMacro(TimeStep, int); const vtkStdString &GetRegionName() const {return this->RegionName;} // gather timestep information bool MakeInformationVector(const vtkStdString &, const vtkStdString &, const vtkStdString &, vtkOpenFOAMReader *); // read mesh/fields and create dataset int RequestData(vtkMultiBlockDataSet *, bool, bool, bool); void SetTimeValue(const double); int MakeMetaDataAtTimeStep(vtkStringArray *, vtkStringArray *, vtkStringArray *, const bool); void SetupInformation(const vtkStdString &, const vtkStdString &, const vtkStdString &, vtkOpenFOAMReaderPrivate *); private: struct vtkFoamBoundaryEntry { enum bt { PHYSICAL = 1, // patch, wall PROCESSOR = 2, // processor GEOMETRICAL = 0 // symmetryPlane, wedge, cyclic, empty, etc. }; vtkStdString BoundaryName; vtkIdType NFaces, StartFace, AllBoundariesStartFace; bool IsActive; bt BoundaryType; }; struct vtkFoamBoundaryDict : public std::vector { // we need to keep the path to time directory where the current mesh // is read from, since boundaryDict may be accessed multiple times // at a timestep for patch selections vtkStdString TimeDir; }; vtkOpenFOAMReader *Parent; // case and region vtkStdString CasePath; vtkStdString RegionName; vtkStdString ProcessorName; // time information vtkDoubleArray *TimeValues; int TimeStep; int TimeStepOld; vtkStringArray *TimeNames; int InternalMeshSelectionStatus; int InternalMeshSelectionStatusOld; // filenames / directories vtkStringArray *VolFieldFiles; vtkStringArray *PointFieldFiles; vtkStringArray *LagrangianFieldFiles; vtkStringArray *PolyMeshPointsDir; vtkStringArray *PolyMeshFacesDir; // for mesh construction vtkIdType NumCells; vtkIdType NumPoints; vtkDataArray *FaceOwner; // for cell-to-point interpolation vtkPolyData *AllBoundaries; vtkDataArray *AllBoundariesPointMap; vtkDataArray *InternalPoints; // for caching mesh vtkUnstructuredGrid *InternalMesh; vtkMultiBlockDataSet *BoundaryMesh; vtkFoamLabelArrayVector *BoundaryPointMap; vtkFoamBoundaryDict BoundaryDict; vtkMultiBlockDataSet *PointZoneMesh; vtkMultiBlockDataSet *FaceZoneMesh; vtkMultiBlockDataSet *CellZoneMesh; // for polyhedra handling int NumTotalAdditionalCells; vtkIdTypeArray *AdditionalCellIds; vtkIntArray *NumAdditionalCells; vtkFoamLabelArrayVector *AdditionalCellPoints; // constructor and destructor are kept private vtkOpenFOAMReaderPrivate(); ~vtkOpenFOAMReaderPrivate() override; vtkOpenFOAMReaderPrivate(const vtkOpenFOAMReaderPrivate &) = delete; void operator=(const vtkOpenFOAMReaderPrivate &) = delete; // clear mesh construction void ClearInternalMeshes(); void ClearBoundaryMeshes(); void ClearMeshes(); vtkStdString RegionPath() const {return (this->RegionName.empty() ? "" : "/") + this->RegionName;} vtkStdString TimePath(const int timeI) const {return this->CasePath + this->TimeNames->GetValue(timeI);} vtkStdString TimeRegionPath(const int timeI) const {return this->TimePath(timeI) + this->RegionPath();} vtkStdString CurrentTimePath() const {return this->TimePath(this->TimeStep);} vtkStdString CurrentTimeRegionPath() const {return this->TimeRegionPath(this->TimeStep);} vtkStdString CurrentTimeRegionMeshPath(vtkStringArray *dir) const {return this->CasePath + dir->GetValue(this->TimeStep) + this->RegionPath() + "/polyMesh/";} vtkStdString RegionPrefix() const {return this->RegionName + (this->RegionName.empty() ? "" : "/");} // search time directories for mesh void AppendMeshDirToArray(vtkStringArray *, const vtkStdString &, const int); void PopulatePolyMeshDirArrays(); // search a time directory for field objects void GetFieldNames(const vtkStdString &, const bool, vtkStringArray *, vtkStringArray *); void SortFieldFiles(vtkStringArray *, vtkStringArray *, vtkStringArray *); void LocateLagrangianClouds(vtkStringArray *, const vtkStdString &); // read controlDict bool ListTimeDirectoriesByControlDict(vtkFoamDict *dict); bool ListTimeDirectoriesByInstances(); // read mesh files vtkFloatArray* ReadPointsFile(); vtkFoamLabelVectorVector* ReadFacesFile (const vtkStdString &); vtkFoamLabelVectorVector* ReadOwnerNeighborFiles(const vtkStdString &, vtkFoamLabelVectorVector *); bool CheckFacePoints(vtkFoamLabelVectorVector *); // create mesh void InsertCellsToGrid(vtkUnstructuredGrid *, const vtkFoamLabelVectorVector *, const vtkFoamLabelVectorVector *, vtkFloatArray *, vtkIdTypeArray *, vtkDataArray *); vtkUnstructuredGrid *MakeInternalMesh(const vtkFoamLabelVectorVector *, const vtkFoamLabelVectorVector *, vtkFloatArray *); void InsertFacesToGrid(vtkPolyData *, const vtkFoamLabelVectorVector *, vtkIdType, vtkIdType, vtkDataArray *, vtkIdList *, vtkDataArray *, const bool); template bool ExtendArray(T1 *, vtkIdType); vtkMultiBlockDataSet* MakeBoundaryMesh(const vtkFoamLabelVectorVector *, vtkFloatArray *); void SetBlockName(vtkMultiBlockDataSet *, unsigned int, const char *); void TruncateFaceOwner(); // move additional points for decomposed cells vtkPoints *MoveInternalMesh(vtkUnstructuredGrid *, vtkFloatArray *); void MoveBoundaryMesh(vtkMultiBlockDataSet *, vtkFloatArray *); // cell-to-point interpolator void InterpolateCellToPoint(vtkFloatArray *, vtkFloatArray *, vtkPointSet *, vtkDataArray *, vtkTypeInt64); // read and create cell/point fields void ConstructDimensions(vtkStdString *, vtkFoamDict *); bool ReadFieldFile(vtkFoamIOobject *, vtkFoamDict *, const vtkStdString &, vtkDataArraySelection *); vtkFloatArray *FillField(vtkFoamEntry *, vtkIdType, vtkFoamIOobject *, const vtkStdString &); void GetVolFieldAtTimeStep(vtkUnstructuredGrid *, vtkMultiBlockDataSet *, const vtkStdString &); void GetPointFieldAtTimeStep(vtkUnstructuredGrid *, vtkMultiBlockDataSet *, const vtkStdString &); void AddArrayToFieldData(vtkDataSetAttributes *, vtkDataArray *, const vtkStdString &); // create lagrangian mesh/fields vtkMultiBlockDataSet *MakeLagrangianMesh(); // create point/face/cell zones vtkFoamDict *GatherBlocks(const char *, bool); bool GetPointZoneMesh(vtkMultiBlockDataSet *, vtkPoints *); bool GetFaceZoneMesh(vtkMultiBlockDataSet *, const vtkFoamLabelVectorVector *, vtkPoints *); bool GetCellZoneMesh(vtkMultiBlockDataSet *, const vtkFoamLabelVectorVector *, const vtkFoamLabelVectorVector *, vtkPoints *); }; vtkStandardNewMacro(vtkOpenFOAMReaderPrivate); //----------------------------------------------------------------------------- // struct vtkFoamLabelVectorVector struct vtkFoamLabelVectorVector { typedef std::vector CellType; virtual ~vtkFoamLabelVectorVector() {} virtual size_t GetLabelSize() const = 0; // in bytes virtual void ResizeBody(vtkIdType bodyLength) = 0; virtual void* WritePointer(vtkIdType i, vtkIdType bodyI, vtkIdType number) = 0; virtual void SetIndex(vtkIdType i, vtkIdType bodyI) = 0; virtual void SetValue(vtkIdType bodyI, vtkTypeInt64 value) = 0; virtual void InsertValue(vtkIdType bodyI, vtkTypeInt64 value) = 0; virtual const void* operator[](vtkIdType i) const = 0; virtual vtkIdType GetSize(vtkIdType i) const = 0; virtual void GetCell(vtkIdType i, CellType &cell) const = 0; virtual void SetCell(vtkIdType i, const CellType &cell) = 0; virtual vtkIdType GetNumberOfElements() const = 0; virtual vtkDataArray* GetIndices() = 0; virtual vtkDataArray* GetBody() = 0; bool Is64Bit() const { return this->GetLabelSize() == 8; } }; template struct vtkFoamLabelVectorVectorImpl : public vtkFoamLabelVectorVector { private: ArrayT *Indices; ArrayT *Body; public: typedef ArrayT LabelArrayType; typedef typename ArrayT::ValueType LabelType; ~vtkFoamLabelVectorVectorImpl() override { this->Indices->Delete(); this->Body->Delete(); } // Construct from base class: vtkFoamLabelVectorVectorImpl(const vtkFoamLabelVectorVector &ivv) : Indices(nullptr), Body(nullptr) { assert("LabelVectorVectors use the same label width." && this->GetLabelSize() == ivv.GetLabelSize()); typedef vtkFoamLabelVectorVectorImpl ThisType; const ThisType &ivvCast = static_cast(ivv); this->Indices = ivvCast.Indices; this->Body = ivvCast.Body; this->Indices->Register(nullptr); // ref count the copy this->Body->Register(nullptr); } vtkFoamLabelVectorVectorImpl(const vtkFoamLabelVectorVectorImpl &ivv) : Indices(ivv.Indices), Body(ivv.Body) { this->Indices->Register(0); // ref count the copy this->Body->Register(0); } vtkFoamLabelVectorVectorImpl() : Indices(LabelArrayType::New()), Body(LabelArrayType::New()) { } vtkFoamLabelVectorVectorImpl(vtkIdType nElements, vtkIdType bodyLength) : Indices(LabelArrayType::New()), Body(LabelArrayType::New()) { this->Indices->SetNumberOfValues(nElements + 1); this->Body->SetNumberOfValues(bodyLength); } size_t GetLabelSize() const override { return sizeof(LabelType); } // note that vtkIntArray::Resize() allocates (current size + new // size) bytes if current size < new size until 2010-06-27 // cf. commit c869c3d5875f503e757b64f2fd1ec349aee859bf void ResizeBody(vtkIdType bodyLength) override { this->Body->Resize(bodyLength); } void* WritePointer(vtkIdType i, vtkIdType bodyI, vtkIdType number) override { return this->Body->WritePointer(*this->Indices->GetPointer(i) = bodyI, number); } void SetIndex(vtkIdType i, vtkIdType bodyI) override { this->Indices->SetValue(i, static_cast(bodyI)); } void SetValue(vtkIdType bodyI, vtkTypeInt64 value) override { this->Body->SetValue(bodyI, static_cast(value)); } void InsertValue(vtkIdType bodyI, vtkTypeInt64 value) override { this->Body->InsertValue(bodyI, value); } const void* operator[](vtkIdType i) const override { return this->Body->GetPointer(this->Indices->GetValue(i)); } vtkIdType GetSize(vtkIdType i) const override { return this->Indices->GetValue(i + 1) - this->Indices->GetValue(i); } void GetCell(vtkIdType cellId, CellType &cell) const override { LabelType cellStart = this->Indices->GetValue(cellId); LabelType cellSize = this->Indices->GetValue(cellId + 1) - cellStart; cell.resize(cellSize); for (vtkIdType i = 0; i < cellSize; ++i) { cell[i] = this->Body->GetValue(cellStart + i); } } void SetCell(vtkIdType cellId, const CellType &cell) override { LabelType cellStart = this->Indices->GetValue(cellId); LabelType cellSize = this->Indices->GetValue(cellId + 1) - cellStart; for (vtkIdType i = 0; i < cellSize; ++i) { this->Body->SetValue(cellStart + i, cell[i]); } } vtkIdType GetNumberOfElements() const override { return this->Indices->GetNumberOfTuples() - 1; } vtkDataArray* GetIndices() override { return this->Indices; } vtkDataArray* GetBody() override { return this->Body; } }; //----------------------------------------------------------------------------- // class vtkFoamError // class for exception-carrying object struct vtkFoamError : public vtkStdString { private: typedef vtkStdString Superclass; public: // a super-easy way to make use of operator<<()'s defined in // std::ostringstream class template vtkFoamError& operator<<(const T& t) { std::ostringstream os; os << t; this->Superclass::operator+=(os.str()); return *this; } }; //----------------------------------------------------------------------------- // class vtkFoamToken // token class which also works as container for list types // - a word token is treated as a string token for simplicity // - handles only atomic types. Handling of list types are left to the // derived classes. struct vtkFoamToken { public: enum tokenType { // undefined type UNDEFINED, // atomic types PUNCTUATION, LABEL, SCALAR, STRING, IDENTIFIER, // vtkObject-derived list types STRINGLIST, LABELLIST, SCALARLIST, VECTORLIST, // original list types LABELLISTLIST, ENTRYVALUELIST, BOOLLIST, EMPTYLIST, DICTIONARY, // error state TOKEN_ERROR }; // Bitwidth of labels. enum labelType { NO_LABEL_TYPE = 0, // Used for assertions. INT32, INT64 }; protected: tokenType Type; labelType LabelType; union { char Char; vtkTypeInt64 Int; double Double; vtkStdString* String; vtkObjectBase *VtkObjectPtr; // vtkObject-derived list types vtkDataArray *LabelListPtr; vtkFloatArray *ScalarListPtr, *VectorListPtr; vtkStringArray *StringListPtr; // original list types vtkFoamLabelVectorVector *LabelListListPtr; std::vector *EntryValuePtrs; vtkFoamDict *DictPtr; }; void Clear() { if (this->Type == STRING || this->Type == IDENTIFIER) { delete this->String; } } void AssignData(const vtkFoamToken& value) { switch (value.Type) { case PUNCTUATION: this->Char = value.Char; break; case LABEL: this->Int = value.Int; break; case SCALAR: this->Double = value.Double; break; case STRING: case IDENTIFIER: this->String = new vtkStdString(*value.String); break; case UNDEFINED: case STRINGLIST: case LABELLIST: case SCALARLIST: case VECTORLIST: case LABELLISTLIST: case ENTRYVALUELIST: case BOOLLIST: case EMPTYLIST: case DICTIONARY: case TOKEN_ERROR: break; } } public: vtkFoamToken() : Type(UNDEFINED), LabelType(NO_LABEL_TYPE) { } vtkFoamToken(const vtkFoamToken& value) : Type(value.Type), LabelType(value.LabelType) { this->AssignData(value); } ~vtkFoamToken() { this->Clear(); } tokenType GetType() const { return this->Type; } void SetLabelType(labelType type) { this->LabelType = type; } labelType GetLabelType() const { return this->LabelType; } template bool Is() const; template T To() const; #if defined(_MSC_VER) // workaround for Win32-64ids-nmake70 template<> bool Is() const; template<> bool Is() const; template<> bool Is() const; template<> bool Is() const; template<> vtkTypeInt32 To() const; template<> vtkTypeInt64 To() const; template<> float To() const; template<> double To() const; #endif // workaround for SunOS-CC5.6-dbg vtkTypeInt64 ToInt() const { assert("Label type not set!" && this->LabelType != NO_LABEL_TYPE); return this->Int; } // workaround for SunOS-CC5.6-dbg float ToFloat() const { return this->Type == LABEL ? static_cast(this->Int) : static_cast(this->Double); } const vtkStdString ToString() const { return *this->String; } const vtkStdString ToIdentifier() const { return *this->String; } void SetBad() { this->Clear(); this->Type = TOKEN_ERROR; } void SetIdentifier(const vtkStdString& idString) { this->operator=(idString); this->Type = IDENTIFIER; } void operator=(const char value) { this->Clear(); this->Type = PUNCTUATION; this->Char = value; } void operator=(const vtkTypeInt32 value) { this->Clear(); assert("Label type not set!" && this->LabelType != NO_LABEL_TYPE); if (this->LabelType == INT64) { vtkGenericWarningMacro("Setting a 64 bit label from a 32 bit integer."); } this->Type = LABEL; this->Int = static_cast(value); } void operator=(const vtkTypeInt64 value) { this->Clear(); assert("Label type not set!" && this->LabelType != NO_LABEL_TYPE); if (this->LabelType == INT32) { vtkGenericWarningMacro("Setting a 32 bit label from a 64 bit integer. " "Precision loss may occur."); } this->Type = LABEL; this->Int = value; } void operator=(const double value) { this->Clear(); this->Type = SCALAR; this->Double = value; } void operator=(const char *value) { this->Clear(); this->Type = STRING; this->String = new vtkStdString(value); } void operator=(const vtkStdString& value) { this->Clear(); this->Type = STRING; this->String = new vtkStdString(value); } vtkFoamToken& operator=(const vtkFoamToken& value) { this->Clear(); this->Type = value.Type; this->LabelType = value.LabelType; this->AssignData(value); return *this; } bool operator==(const char value) const { return this->Type == PUNCTUATION && this->Char == value; } bool operator==(const vtkTypeInt32 value) const { assert("Label type not set!" && this->LabelType != NO_LABEL_TYPE); return this->Type == LABEL && this->Int == static_cast(value); } bool operator==(const vtkTypeInt64 value) const { assert("Label type not set!" && this->LabelType != NO_LABEL_TYPE); return this->Type == LABEL && this->Int == value; } bool operator==(const vtkStdString& value) const { return this->Type == STRING && *this->String == value; } bool operator!=(const vtkStdString& value) const { return this->Type != STRING || *this->String != value; } bool operator!=(const char value) const { return !this->operator==(value); } friend std::ostringstream& operator<<(std::ostringstream& str, const vtkFoamToken& value) { switch (value.GetType()) { case TOKEN_ERROR: str << "badToken (an unexpected EOF?)"; break; case PUNCTUATION: str << value.Char; break; case LABEL: assert("Label type not set!" && value.LabelType != NO_LABEL_TYPE); if (value.LabelType == INT32) { str << static_cast(value.Int); } else { str << value.Int; } break; case SCALAR: str << value.Double; break; case STRING: case IDENTIFIER: str << *value.String; break; case UNDEFINED: case STRINGLIST: case LABELLIST: case SCALARLIST: case VECTORLIST: case LABELLISTLIST: case ENTRYVALUELIST: case BOOLLIST: case EMPTYLIST: case DICTIONARY: break; } return str; } }; template<> inline bool vtkFoamToken::Is() const { // masquerade for bool return this->Type == LABEL; } template<> inline bool vtkFoamToken::Is() const { assert("Label type not set!" && this->LabelType != NO_LABEL_TYPE); return this->Type == LABEL && this->LabelType == INT32; } template<> inline bool vtkFoamToken::Is() const { assert("Label type not set!" && this->LabelType != NO_LABEL_TYPE); return this->Type == LABEL; } template<> inline bool vtkFoamToken::Is() const { return this->Type == LABEL || this->Type == SCALAR; } template<> inline bool vtkFoamToken::Is() const { return this->Type == SCALAR; } template<> inline char vtkFoamToken::To() const { return static_cast(this->Int); } template<> inline vtkTypeInt32 vtkFoamToken::To() const { assert("Label type not set!" && this->LabelType != NO_LABEL_TYPE); if (this->LabelType == INT64) { vtkGenericWarningMacro("Casting 64 bit label to int32. Precision loss " "may occur."); } return static_cast(this->Int); } template<> inline vtkTypeInt64 vtkFoamToken::To() const { assert("Label type not set!" && this->LabelType != NO_LABEL_TYPE); return this->Int; } template<> inline float vtkFoamToken::To() const { return this->Type == LABEL ? static_cast(this->Int) : static_cast(this->Double); } template<> inline double vtkFoamToken::To() const { return this->Type == LABEL ? static_cast(this->Int) : this->Double; } //----------------------------------------------------------------------------- // class vtkFoamFileStack // list of variables that have to be saved when a file is included. struct vtkFoamFileStack { protected: vtkOpenFOAMReader *Reader; vtkStdString FileName; FILE *File; bool IsCompressed; z_stream Z; int ZStatus; int LineNumber; #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD bool WasNewline; #endif // buffer pointers. using raw pointers for performance reason. unsigned char *Inbuf; unsigned char *Outbuf; unsigned char *BufPtr; unsigned char *BufEndPtr; vtkFoamFileStack(vtkOpenFOAMReader *reader) : Reader(reader), FileName(), File(nullptr), IsCompressed(false), ZStatus(Z_OK), LineNumber(0), #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD WasNewline(true), #endif Inbuf(nullptr), Outbuf(nullptr), BufPtr(nullptr), BufEndPtr(nullptr) { this->Z.zalloc = Z_NULL; this->Z.zfree = Z_NULL; this->Z.opaque = Z_NULL; } void Reset() { // this->FileName = ""; this->File = nullptr; this->IsCompressed = false; // this->ZStatus = Z_OK; this->Z.zalloc = Z_NULL; this->Z.zfree = Z_NULL; this->Z.opaque = Z_NULL; // this->LineNumber = 0; #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD this->WasNewline = true; #endif this->Inbuf = nullptr; this->Outbuf = nullptr; // this->BufPtr = nullptr; // this->BufEndPtr = nullptr; } public: const vtkStdString& GetFileName() const { return this->FileName; } int GetLineNumber() const { return this->LineNumber; } vtkOpenFOAMReader* GetReader() const { return this->Reader; } }; //----------------------------------------------------------------------------- // class vtkFoamFile // read and tokenize the input. struct vtkFoamFile : public vtkFoamFileStack { private: typedef vtkFoamFileStack Superclass; public: // #inputMode values enum inputModes { INPUT_MODE_MERGE, INPUT_MODE_OVERWRITE, INPUT_MODE_PROTECT, INPUT_MODE_WARN, INPUT_MODE_ERROR }; private: inputModes InputMode; // inclusion handling vtkFoamFileStack *Stack[VTK_FOAMFILE_INCLUDE_STACK_SIZE]; int StackI; vtkStdString CasePath; // declare and define as private vtkFoamFile(); bool InflateNext(unsigned char *buf, int requestSize, int *readSize = nullptr); int NextTokenHead(); // hacks to keep exception throwing / recursive codes out-of-line to make // putBack(), getc() and readExpecting() inline expandable void ThrowDuplicatedPutBackException(); void ThrowUnexpectedEOFException(); void ThrowUnexpectedNondigitCharExecption(const int c); void ThrowUnexpectedTokenException(const char, const int c); int ReadNext(); void PutBack(const int c) { if (--this->Superclass::BufPtr < this->Superclass::Outbuf) { this->ThrowDuplicatedPutBackException(); } *this->Superclass::BufPtr = static_cast(c); } // get a character int Getc() { return this->Superclass::BufPtr == this->Superclass::BufEndPtr ? this->ReadNext() : *this->Superclass::BufPtr++; } vtkFoamError StackString() { std::ostringstream os; if (this->StackI > 0) { os << "\n included"; for (int stackI = this->StackI - 1; stackI >= 0; stackI--) { os << " from line " << this->Stack[stackI]->GetLineNumber() << " of " << this->Stack[stackI]->GetFileName() << "\n"; } os << ": "; } return vtkFoamError() << os.str(); } bool CloseIncludedFile() { if (this->StackI == 0) { return false; } this->Clear(); this->StackI--; // use the default bitwise assignment operator this->Superclass::operator=(*this->Stack[this->StackI]); delete this->Stack[this->StackI]; return true; } void Clear() { if (this->Superclass::IsCompressed) { inflateEnd(&this->Superclass::Z); } delete [] this->Superclass::Inbuf; delete [] this->Superclass::Outbuf; this->Superclass::Inbuf = this->Superclass::Outbuf = nullptr; if (this->Superclass::File) { fclose(this->Superclass::File); this->Superclass::File = nullptr; } // don't reset the line number so that the last line number is // retained after close // lineNumber_ = 0; } //! Return file name (part beyond last /) vtkStdString ExtractName(const vtkStdString& path) const { #if defined(_WIN32) const vtkStdString pathFindSeparator = "/\\", pathSeparator = "\\"; #else const vtkStdString pathFindSeparator = "/", pathSeparator = "/"; #endif vtkStdString::size_type pos = path.find_last_of(pathFindSeparator); if (pos == vtkStdString::npos) { // no slash return path; } else if (pos+1 == path.size()) { // final trailing slash vtkStdString::size_type endPos = pos; pos = path.find_last_of(pathFindSeparator, pos-1); if (pos == vtkStdString::npos) { // no further slash return path.substr(0, endPos); } else { return path.substr(pos + 1, endPos - pos - 1); } } else { return path.substr(pos + 1, vtkStdString::npos); } } //! Return directory path name (part before last /) vtkStdString ExtractPath(const vtkStdString& path) const { #if defined(_WIN32) const vtkStdString pathFindSeparator = "/\\", pathSeparator = "\\"; #else const vtkStdString pathFindSeparator = "/", pathSeparator = "/"; #endif const vtkStdString::size_type pos = path.find_last_of(pathFindSeparator); return pos == vtkStdString::npos ? vtkStdString(".") + pathSeparator : path.substr(0, pos + 1); } public: vtkFoamFile(const vtkStdString& casePath, vtkOpenFOAMReader *reader) : vtkFoamFileStack(reader), InputMode(INPUT_MODE_ERROR), StackI(0), CasePath(casePath) { } ~vtkFoamFile() { this->Close(); } inputModes GetInputMode() const { return this->InputMode; } const vtkStdString GetCasePath() const { return this->CasePath; } const vtkStdString GetFilePath() const { return this->ExtractPath(this->FileName); } vtkStdString ExpandPath(const vtkStdString& pathIn, const vtkStdString& defaultPath) { vtkStdString expandedPath; bool isExpanded = false, wasPathSeparator = true; const size_t nChars = pathIn.length(); for (size_t charI = 0; charI < nChars;) { char c = pathIn[charI]; switch (c) { case '$': // $-variable expansion { vtkStdString variable; while (++charI < nChars && (isalnum(pathIn[charI]) || pathIn[charI] == '_')) { variable += pathIn[charI]; } if (variable == "FOAM_CASE") // discard path until the variable { expandedPath = this->CasePath; wasPathSeparator = true; isExpanded = true; } else if (variable == "FOAM_CASENAME") { // FOAM_CASENAME is the final directory name from CasePath expandedPath += this->ExtractName(this->CasePath); wasPathSeparator = false; isExpanded = true; } else { const char *value = getenv(variable.c_str()); if (value != nullptr) { expandedPath += value; } const vtkStdString::size_type len = expandedPath.length(); if (len > 0) { const char c2 = expandedPath[len - 1]; wasPathSeparator = (c2 == '/' || c2 == '\\'); } else { wasPathSeparator = false; } } } break; case '~': // home directory expansion // not using vtksys::SystemTools::ConvertToUnixSlashes() for // a bit better handling of "~" if (wasPathSeparator) { vtkStdString userName; while (++charI < nChars && (pathIn[charI] != '/' && pathIn[charI] != '\\') && pathIn[charI] != '$') { userName += pathIn[charI]; } if (userName.empty()) { const char *homePtr = getenv("HOME"); if (homePtr == nullptr) { #if defined(_WIN32) && !defined(__CYGWIN__) || defined(__LIBCATAMOUNT__) expandedPath = ""; #else const struct passwd *pwentry = getpwuid(getuid()); if (pwentry == nullptr) { throw this->StackString() << "Home directory path not found"; } expandedPath = pwentry->pw_dir; #endif } else { expandedPath = homePtr; } } else { #if defined(_WIN32) && !defined(__CYGWIN__) || defined(__LIBCATAMOUNT__) const char *homePtr = getenv("HOME"); expandedPath = this->ExtractPath(homePtr ? homePtr : "") + userName; #else if (userName == "OpenFOAM") { // so far only "~/.OpenFOAM" expansion is supported const char *homePtr = getenv("HOME"); if (homePtr == nullptr) { expandedPath = ""; } else { expandedPath = vtkStdString(homePtr) + "/.OpenFOAM"; } } else { const struct passwd *pwentry = getpwnam(userName.c_str()); if (pwentry == nullptr) { throw this->StackString() << "Home directory for user " << userName.c_str() << " not found"; } expandedPath = pwentry->pw_dir; } #endif } wasPathSeparator = false; isExpanded = true; break; } VTK_FALLTHROUGH; default: wasPathSeparator = (c == '/' || c == '\\'); expandedPath += c; charI++; } } if (isExpanded || expandedPath.substr(0, 1) == "/" || expandedPath.substr( 0, 1) == "\\") { return expandedPath; } else { return defaultPath + expandedPath; } } void IncludeFile(const vtkStdString& includedFileName, const vtkStdString& defaultPath) { if (this->StackI >= VTK_FOAMFILE_INCLUDE_STACK_SIZE) { throw this->StackString() << "Exceeded maximum #include recursions of " << VTK_FOAMFILE_INCLUDE_STACK_SIZE; } // use the default bitwise copy constructor this->Stack[this->StackI++] = new vtkFoamFileStack(*this); this->Superclass::Reset(); this->Open(this->ExpandPath(includedFileName, defaultPath)); } // the tokenizer // returns true if success, false if encountered EOF bool Read(vtkFoamToken& token) { token.SetLabelType(this->Reader->GetUse64BitLabels() ? vtkFoamToken::INT64 : vtkFoamToken::INT32); // expanded the outermost loop in nextTokenHead() for performance int c; while (isspace(c = this->Getc())) // isspace() accepts -1 as EOF { if (c == '\n') { ++this->Superclass::LineNumber; #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD this->Superclass::WasNewline = true; #endif } } if (c == '/') { this->PutBack(c); c = this->NextTokenHead(); } #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD if(c != '#') { this->Superclass::WasNewline = false; } #endif const int MAXLEN = 1024; char buf[MAXLEN + 1]; int charI = 0; switch (c) { case '(': case ')': // high-priority punctuation token token = static_cast(c); return true; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': case '-': // undetermined number token do { buf[charI++] = static_cast(c); } while (isdigit(c = this->Getc()) && charI < MAXLEN); if (c != '.' && c != 'e' && c != 'E' && charI < MAXLEN && c != EOF) { // label token buf[charI] = '\0'; if (this->Reader->GetUse64BitLabels()) { token = static_cast(strtoll(buf, nullptr, 10)); } else { token = static_cast(strtol(buf, nullptr, 10)); } this->PutBack(c); return true; } VTK_FALLTHROUGH; case '.': // scalar token if (c == '.' && charI < MAXLEN) { // read decimal fraction part buf[charI++] = static_cast(c); while (isdigit(c = this->Getc()) && charI < MAXLEN) { buf[charI++] = static_cast(c); } } if ((c == 'e' || c == 'E') && charI < MAXLEN) { // read exponent part buf[charI++] = static_cast(c); if (((c = this->Getc()) == '+' || c == '-') && charI < MAXLEN) { buf[charI++] = static_cast(c); c = this->Getc(); } while (isdigit(c) && charI < MAXLEN) { buf[charI++] = static_cast(c); c = this->Getc(); } } if (charI == 1 && buf[0] == '-') { token = '-'; this->PutBack(c); return true; } buf[charI] = '\0'; token = strtod(buf, nullptr); this->PutBack(c); break; case ';': case '{': case '}': case '[': case ']': case ':': case ',': case '=': case '+': case '*': case '/': // low-priority punctuation token token = static_cast(c); return true; case '"': { // string token bool wasEscape = false; while ((c = this->Getc()) != EOF && charI < MAXLEN) { if (c == '\\' && !wasEscape) { wasEscape = true; continue; } else if (c == '"' && !wasEscape) { break; } else if (c == '\n') { ++this->Superclass::LineNumber; if (!wasEscape) { throw this->StackString() << "Unescaped newline in string constant"; } } buf[charI++] = static_cast(c); wasEscape = false; } buf[charI] = '\0'; token = buf; } break; case EOF: // end of file token.SetBad(); return false; case '$': { vtkFoamToken identifierToken; if (!this->Read(identifierToken)) { throw this->StackString() << "Unexpected EOF reading identifier"; } if (identifierToken.GetType() != vtkFoamToken::STRING) { throw this->StackString() << "Expected a word, found " << identifierToken; } token.SetIdentifier(identifierToken.ToString()); return true; } case '#': { #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD // the OpenFOAM #-directives can indeed be placed in the // middle of a line if(!this->Superclass::WasNewline) { throw this->StackString() << "Encountered #-directive in the middle of a line"; } this->Superclass::WasNewline = false; #endif // read directive vtkFoamToken directiveToken; if (!this->Read(directiveToken)) { throw this->StackString() << "Unexpected EOF reading directive"; } if (directiveToken == "include") { vtkFoamToken fileNameToken; if (!this->Read(fileNameToken)) { throw this->StackString() << "Unexpected EOF reading filename"; } this->IncludeFile(fileNameToken.ToString(), this->ExtractPath(this->FileName)); } else if (directiveToken == "includeIfPresent") { vtkFoamToken fileNameToken; if (!this->Read(fileNameToken)) { throw this->StackString() << "Unexpected EOF reading filename"; } // special treatment since the file is allowed to be missing const vtkStdString fullName = this->ExpandPath(fileNameToken.ToString(), this->ExtractPath(this->FileName)); FILE *fh = fopen(fullName.c_str(), "rb"); if (fh) { fclose(fh); this->IncludeFile(fileNameToken.ToString(), this->ExtractPath(this->FileName)); } } else if (directiveToken == "inputMode") { vtkFoamToken modeToken; if (!this->Read(modeToken)) { throw this->StackString() << "Unexpected EOF reading inputMode specifier"; } if (modeToken == "merge" || modeToken == "default") { this->InputMode = INPUT_MODE_MERGE; } else if (modeToken == "overwrite") { this->InputMode = INPUT_MODE_OVERWRITE; } else if (modeToken == "protect") { // not properly supported - treat like "merge" for now // this->InputMode = INPUT_MODE_PROTECT; this->InputMode = INPUT_MODE_MERGE; } else if (modeToken == "warn") { // not properly supported - treat like "error" for now // this->InputMode = INPUT_MODE_WARN; this->InputMode = INPUT_MODE_ERROR; } else if (modeToken == "error") { this->InputMode = INPUT_MODE_ERROR; } else { throw this->StackString() << "Expected one of inputMode specifiers " "(merge, overwrite, protect, warn, error, default), found " << modeToken; } } else if (directiveToken == '{') { // '#{' verbatim/code block. swallow everything until a closing '#}' // This hopefully matches the first one... while (true) { c = this->NextTokenHead(); if (c == EOF) { throw this->StackString() << "Unexpected EOF while skipping over #{ directive"; } else if (c == '#') { c = this->Getc(); if (c == '/') { this->PutBack(c); } else if (c == '}') { break; } } } } else { throw this->StackString() << "Unsupported directive " << directiveToken; } return this->Read(token); } default: // parses as a word token, but gives the STRING type for simplicity int inBrace = 0; do { if (c == '(') { inBrace++; } else if (c == ')' && --inBrace == -1) { break; } buf[charI++] = static_cast(c); // valid characters that constitutes a word // cf. src/OpenFOAM/primitives/strings/word/wordI.H } while ((c = this->Getc()) != EOF && !isspace(c) && c != '"' && c != '/' && c != ';' && c != '{' && c != '}' && charI < MAXLEN); buf[charI] = '\0'; token = buf; this->PutBack(c); } if (c == EOF) { this->ThrowUnexpectedEOFException(); } if (charI == MAXLEN) { throw this->StackString() << "Exceeded maximum allowed length of " << MAXLEN << " chars"; } return true; } void Open(const vtkStdString& fileName) { // reset line number to indicate the beginning of the file when an // exception is thrown this->Superclass::LineNumber = 0; this->Superclass::FileName = fileName; if (this->Superclass::File) { throw this->StackString() << "File already opened within this object"; } if ((this->Superclass::File = fopen(this->Superclass::FileName.c_str(), "rb")) == nullptr) { throw this->StackString() << "Can't open"; } unsigned char zMagic[2]; if (fread(zMagic, 1, 2, this->Superclass::File) == 2 && zMagic[0] == 0x1f && zMagic[1] == 0x8b) { // gzip-compressed format this->Superclass::Z.avail_in = 0; this->Superclass::Z.next_in = Z_NULL; // + 32 to automatically recognize gzip format if (inflateInit2(&this->Superclass::Z, 15 + 32) == Z_OK) { this->Superclass::IsCompressed = true; this->Superclass::Inbuf = new unsigned char[VTK_FOAMFILE_INBUFSIZE]; } else { fclose(this->Superclass::File); this->Superclass::File = nullptr; throw this->StackString() << "Can't init zstream " << (this->Superclass::Z.msg ? this->Superclass::Z.msg : ""); } } else { // uncompressed format this->Superclass::IsCompressed = false; } rewind(this->Superclass::File); this->Superclass::ZStatus = Z_OK; this->Superclass::Outbuf = new unsigned char[VTK_FOAMFILE_OUTBUFSIZE + 1]; this->Superclass::BufPtr = this->Superclass::Outbuf + 1; this->Superclass::BufEndPtr = this->Superclass::BufPtr; this->Superclass::LineNumber = 1; } void Close() { while (this->CloseIncludedFile()) ; this->Clear(); } // gzread with buffering handling int Read(unsigned char *buf, const int len) { int readlen; const int buflen = static_cast(this->Superclass::BufEndPtr - this->Superclass::BufPtr); if (len > buflen) { memcpy(buf, this->Superclass::BufPtr, buflen); this->InflateNext(buf + buflen, len - buflen, &readlen); if (readlen >= 0) { readlen += buflen; } else { if (buflen == 0) // return EOF { readlen = -1; } else { readlen = buflen; } } this->Superclass::BufPtr = this->Superclass::BufEndPtr; } else { memcpy(buf, this->Superclass::BufPtr, len); this->Superclass::BufPtr += len; readlen = len; } for (int i = 0; i < readlen; i++) { if (buf[i] == '\n') { this->Superclass::LineNumber++; } } return readlen; } void ReadExpecting(const char expected) { // skip prepending invalid chars // expanded the outermost loop in nextTokenHead() for performance int c; while (isspace(c = this->Getc())) // isspace() accepts -1 as EOF { if (c == '\n') { ++this->Superclass::LineNumber; #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD this->Superclass::WasNewline = true; #endif } } if (c == '/') { this->PutBack(c); c = this->NextTokenHead(); } if (c != expected) { this->ThrowUnexpectedTokenException(expected, c); } } void ReadExpecting(const char* str) { vtkFoamToken t; if (!this->Read(t) || t != str) { throw this->StackString() << "Expected string \"" << str << "\", found " << t; } } vtkTypeInt64 ReadIntValue(); template FloatType ReadFloatValue(); }; int vtkFoamFile::ReadNext() { if (!this->InflateNext(this->Superclass::Outbuf + 1, VTK_FOAMFILE_OUTBUFSIZE)) { return this->CloseIncludedFile() ? this->Getc() : EOF; } return *this->Superclass::BufPtr++; } // specialized for reading an integer value. // not using the standard strtol() for speed reason. vtkTypeInt64 vtkFoamFile::ReadIntValue() { // skip prepending invalid chars // expanded the outermost loop in nextTokenHead() for performance int c; while (isspace(c = this->Getc())) // isspace() accepts -1 as EOF { if (c == '\n') { ++this->Superclass::LineNumber; #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD this->Superclass::WasNewline = true; #endif } } if (c == '/') { this->PutBack(c); c = this->NextTokenHead(); } // leading sign? const bool negNum = (c == '-'); if (negNum || c == '+') { c = this->Getc(); if (c == '\n') { ++this->Superclass::LineNumber; #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD this->Superclass::WasNewline = true; #endif } } if (!isdigit(c)) // isdigit() accepts -1 as EOF { if (c == EOF) { this->ThrowUnexpectedEOFException(); } else { this->ThrowUnexpectedNondigitCharExecption(c); } } vtkTypeInt64 num = c - '0'; while (isdigit(c = this->Getc())) { num = 10 * num + c - '0'; } if (c == EOF) { this->ThrowUnexpectedEOFException(); } this->PutBack(c); return negNum ? -num : num; } // extremely simplified high-performing string to floating point // conversion code based on // ParaView3/VTK/Utilities/vtksqlite/vtk_sqlite3.c template FloatType vtkFoamFile::ReadFloatValue() { // skip prepending invalid chars // expanded the outermost loop in nextTokenHead() for performance int c; while (isspace(c = this->Getc())) // isspace() accepts -1 as EOF { if (c == '\n') { ++this->Superclass::LineNumber; #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD this->Superclass::WasNewline = true; #endif } } if (c == '/') { this->PutBack(c); c = this->NextTokenHead(); } // leading sign? const bool negNum = (c == '-'); if (negNum || c == '+') { c = this->Getc(); if (c == '\n') { ++this->Superclass::LineNumber; #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD this->Superclass::WasNewline = true; #endif } } if (!isdigit(c) && c != '.') // Attention: isdigit() accepts EOF { this->ThrowUnexpectedNondigitCharExecption(c); } double num = 0; // read integer part (before '.') if (c != '.') { num = c - '0'; while (isdigit(c = this->Getc())) { num = num * 10.0 + (c - '0'); } } // read decimal part (after '.') if (c == '.') { double divisor = 1.0; while (isdigit(c = this->Getc())) { num = num * 10.0 + (c - '0'); divisor *= 10.0; } num /= divisor; } // read exponent part if (c == 'E' || c == 'e') { int esign = 1; int eval = 0; double scale = 1.0; c = this->Getc(); if (c == '-') { esign = -1; c = this->Getc(); } else if (c == '+') { c = this->Getc(); } while (isdigit(c)) { eval = eval * 10 + (c - '0'); c = this->Getc(); } // fast exponent multiplication! while (eval >= 64) { scale *= 1.0e+64; eval -= 64; } while (eval >= 16) { scale *= 1.0e+16; eval -= 16; } while (eval >= 4) { scale *= 1.0e+4; eval -= 4; } while (eval >= 1) { scale *= 1.0e+1; eval -= 1; } if (esign < 0) { num /= scale; } else { num *= scale; } } if (c == EOF) { this->ThrowUnexpectedEOFException(); } this->PutBack(c); return static_cast(negNum ? -num : num); } // hacks to keep exception throwing code out-of-line to make // putBack() and readExpecting() inline expandable void vtkFoamFile::ThrowUnexpectedEOFException() { throw this->StackString() << "Unexpected EOF"; } void vtkFoamFile::ThrowUnexpectedNondigitCharExecption(const int c) { throw this->StackString() << "Expected a number, found a non-digit character " << static_cast(c); } void vtkFoamFile::ThrowUnexpectedTokenException(const char expected, const int c) { vtkFoamError sstr; sstr << this->StackString() << "Expected punctuation token '" << expected << "', found "; if (c == EOF) { sstr << "EOF"; } else { sstr << static_cast(c); } throw sstr; } void vtkFoamFile::ThrowDuplicatedPutBackException() { throw this->StackString() << "Attempted duplicated putBack()"; } bool vtkFoamFile::InflateNext(unsigned char *buf, int requestSize, int *readSize) { if (readSize) { *readSize = -1; // Set to an error state for early returns } size_t size; if (this->Superclass::IsCompressed) { if (this->Superclass::ZStatus != Z_OK) { return false; } this->Superclass::Z.next_out = buf; this->Superclass::Z.avail_out = requestSize; do { if (this->Superclass::Z.avail_in == 0) { this->Superclass::Z.next_in = this->Superclass::Inbuf; this->Superclass::Z.avail_in = static_cast(fread(this->Superclass::Inbuf, 1, VTK_FOAMFILE_INBUFSIZE, this->Superclass::File)); if (ferror(this->Superclass::File)) { throw this->StackString() << "Fread failed"; } } this->Superclass::ZStatus = inflate(&this->Superclass::Z, Z_NO_FLUSH); if (this->Superclass::ZStatus == Z_STREAM_END #if VTK_FOAMFILE_OMIT_CRCCHECK // the dummy CRC function causes data error when finalizing // so we have to proceed even when a data error is detected || this->Superclass::ZStatus == Z_DATA_ERROR #endif ) { break; } if (this->Superclass::ZStatus != Z_OK) { throw this->StackString() << "Inflation failed: " << (this->Superclass::Z.msg ? this->Superclass::Z.msg : ""); } } while (this->Superclass::Z.avail_out > 0); size = requestSize - this->Superclass::Z.avail_out; } else { // not compressed size = fread(buf, 1, requestSize, this->Superclass::File); } if (size <= 0) { // retain the current location bufPtr_ to the end of the buffer so that // getc() returns EOF again when called next time return false; } // size > 0 // reserve the first byte for getback char this->Superclass::BufPtr = this->Superclass::Outbuf + 1; this->Superclass::BufEndPtr = this->Superclass::BufPtr + size; if (readSize) { // Cast size_t to int -- since requestSize is int, this should be ok. *readSize = static_cast(size); } return true; } // get next semantically valid character int vtkFoamFile::NextTokenHead() { for (;;) { int c; while (isspace(c = this->Getc())) // isspace() accepts -1 as EOF { if (c == '\n') { ++this->Superclass::LineNumber; #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD this->Superclass::WasNewline = true; #endif } } if (c == '/') { if ((c = this->Getc()) == '/') { while ((c = this->Getc()) != EOF && c != '\n') ; if (c == EOF) { return c; } ++this->Superclass::LineNumber; #if VTK_FOAMFILE_RECOGNIZE_LINEHEAD this->Superclass::WasNewline = true; #endif } else if (c == '*') { for (;;) { while ((c = this->Getc()) != EOF && c != '*') { if (c == '\n') { ++this->Superclass::LineNumber; } } if (c == EOF) { return c; } else if ((c = this->Getc()) == '/') { break; } this->PutBack(c); } } else { this->PutBack(c); // may be an EOF return '/'; } } else // may be an EOF { return c; } } #if defined(__hpux) return EOF; // this line should not be executed; workaround for HP-UXia64-aCC #endif } //----------------------------------------------------------------------------- // class vtkFoamIOobject // holds file handle, file format, name of the object the file holds and // type of the object. struct vtkFoamIOobject : public vtkFoamFile { private: typedef vtkFoamFile Superclass; public: enum fileFormat {UNDEFINED, ASCII, BINARY}; private: fileFormat Format; vtkStdString ObjectName; vtkStdString HeaderClassName; vtkFoamError E; bool Use64BitLabels; bool Use64BitFloats; // inform IO object if lagrangian/positions has extra data (OF 1.4 - 2.4) const bool LagrangianPositionsExtraData; void ReadHeader(); // defined later // Disallow default bitwise copy/assignment constructor vtkFoamIOobject(const vtkFoamIOobject&) = delete; void operator=(const vtkFoamIOobject&) = delete; vtkFoamIOobject() = delete; public: vtkFoamIOobject(const vtkStdString& casePath, vtkOpenFOAMReader *reader) : vtkFoamFile(casePath, reader), Format(UNDEFINED), E(), Use64BitLabels(reader->GetUse64BitLabels()), Use64BitFloats(reader->GetUse64BitFloats()), LagrangianPositionsExtraData(static_cast(!reader->GetPositionsIsIn13Format())) { } ~vtkFoamIOobject() { this->Close(); } bool Open(const vtkStdString& file) { try { this->Superclass::Open(file); } catch(vtkFoamError& e) { this->E = e; return false; } try { this->ReadHeader(); } catch(vtkFoamError& e) { this->Superclass::Close(); this->E = e; return false; } return true; } void Close() { this->Superclass::Close(); this->Format = UNDEFINED; this->ObjectName.erase(); this->HeaderClassName.erase(); this->E.erase(); this->Use64BitLabels = this->Reader->GetUse64BitLabels(); this->Use64BitFloats = this->Reader->GetUse64BitFloats(); } fileFormat GetFormat() const { return this->Format; } const vtkStdString& GetClassName() const { return this->HeaderClassName; } const vtkStdString& GetObjectName() const { return this->ObjectName; } const vtkFoamError& GetError() const { return this->E; } void SetError(const vtkFoamError& e) { this->E = e; } bool GetUse64BitLabels() const { return this->Use64BitLabels; } bool GetUse64BitFloats() const { return this->Use64BitFloats; } bool GetLagrangianPositionsExtraData() const { return this->LagrangianPositionsExtraData; } }; //----------------------------------------------------------------------------- // workarounding class for older compilers (gcc-3.3.x and possibly older) template struct vtkFoamReadValue { public: static T ReadValue(vtkFoamIOobject &io); }; template<> inline char vtkFoamReadValue::ReadValue(vtkFoamIOobject& io) { return static_cast(io.ReadIntValue()); } template<> inline vtkTypeInt32 vtkFoamReadValue::ReadValue(vtkFoamIOobject& io) { return static_cast(io.ReadIntValue()); } template<> inline vtkTypeInt64 vtkFoamReadValue::ReadValue(vtkFoamIOobject& io) { return io.ReadIntValue(); } template<> inline float vtkFoamReadValue::ReadValue(vtkFoamIOobject& io) { return io.ReadFloatValue(); } template<> inline double vtkFoamReadValue::ReadValue(vtkFoamIOobject& io) { return io.ReadFloatValue(); } //----------------------------------------------------------------------------- // class vtkFoamEntryValue // a class that represents a value of a dictionary entry that corresponds to // its keyword. note that an entry can have more than one value. struct vtkFoamEntryValue : public vtkFoamToken { private: typedef vtkFoamToken Superclass; bool IsUniform; bool Managed; const vtkFoamEntry *UpperEntryPtr; vtkFoamEntryValue(); vtkObjectBase *ToVTKObject() { return this->Superclass::VtkObjectPtr; } void Clear(); void ReadList(vtkFoamIOobject& io); public: // reads primitive int/float lists template class listTraits { listT *Ptr; public: listTraits() : Ptr(listT::New()) { } listT *GetPtr() { return this->Ptr; } void ReadUniformValues(vtkFoamIOobject& io, const vtkIdType size) { primitiveT value = vtkFoamReadValue::ReadValue(io); for (vtkIdType i = 0; i < size; i++) { this->Ptr->SetValue(i, value); } } void ReadAsciiList(vtkFoamIOobject& io, const vtkIdType size) { for (vtkIdType i = 0; i < size; i++) { this->Ptr->SetValue(i, vtkFoamReadValue::ReadValue(io)); } } void ReadBinaryList(vtkFoamIOobject& io, const int size) { typedef typename listT::ValueType ListValueType; if (typeid(ListValueType) == typeid(primitiveT)) { io.Read(reinterpret_cast(this->Ptr->GetPointer(0)), static_cast(size * sizeof(primitiveT))); } else { vtkDataArray *fileData = vtkDataArray::CreateDataArray( vtkTypeTraits::VTKTypeID()); fileData->SetNumberOfComponents(this->Ptr->GetNumberOfComponents()); fileData->SetNumberOfTuples(this->Ptr->GetNumberOfTuples()); io.Read(reinterpret_cast(fileData->GetVoidPointer(0)), static_cast(size * sizeof(primitiveT))); this->Ptr->DeepCopy(fileData); fileData->Delete(); } } void ReadValue(vtkFoamIOobject&, vtkFoamToken& currToken) { if (!currToken.Is()) { throw vtkFoamError() << "Expected an integer or a (, found " << currToken; } this->Ptr->InsertNextValue(currToken.To()); } }; // reads rank 1 lists of types vector, sphericalTensor, symmTensor // and tensor. if isPositions is true it reads Cloud type of data as // particle positions. cf. (the positions format) // src/lagrangian/basic/particle/particleIO.C - writePosition() template class vectorListTraits { listT *Ptr; public: vectorListTraits() : Ptr(listT::New()) { this->Ptr->SetNumberOfComponents(nComponents); } listT *GetPtr() { return this->Ptr; } void ReadUniformValues(vtkFoamIOobject& io, const vtkIdType size) { io.ReadExpecting('('); primitiveT vectorValue[nComponents]; for (int j = 0; j < nComponents; j++) { vectorValue[j] = vtkFoamReadValue::ReadValue(io); } for (vtkIdType i = 0; i < size; i++) { this->Ptr->SetTuple(i, vectorValue); } io.ReadExpecting(')'); if (isPositions) { // skip label celli vtkFoamReadValue::ReadValue(io); } } void ReadAsciiList(vtkFoamIOobject& io, const vtkIdType size) { typedef typename listT::ValueType ListValueType; for (vtkIdType i = 0; i < size; i++) { io.ReadExpecting('('); ListValueType *vectorTupleI = this->Ptr->GetPointer(nComponents * i); for (int j = 0; j < nComponents; j++) { vectorTupleI[j] = static_cast( vtkFoamReadValue::ReadValue(io)); } io.ReadExpecting(')'); if (isPositions) { // skip label celli vtkFoamReadValue::ReadValue(io); } } } void ReadBinaryList(vtkFoamIOobject& io, const int size) { if (isPositions) // lagrangian/positions (class Cloud) { // xyz (3*scalar) + celli (label) // in OpenFOAM 1.4 -> 2.4 also had facei (label) and stepFraction (scalar) const unsigned labelSize = (io.GetUse64BitLabels() ? 8 : 4); const unsigned tupleLength = ( sizeof(primitiveT)*nComponents + labelSize + ( io.GetLagrangianPositionsExtraData() ? (labelSize + sizeof(primitiveT)) : 0 ) ); // MSVC doesn't support variable-sized stack arrays (JAN-2017) // memory management via std::vector std::vector bufferContainer; bufferContainer.resize(tupleLength); primitiveT *buffer = reinterpret_cast(&bufferContainer[0]); for (int i = 0; i < size; i++) { io.ReadExpecting('('); io.Read(reinterpret_cast(buffer), tupleLength); io.ReadExpecting(')'); this->Ptr->SetTuple(i, buffer); } } else { typedef typename listT::ValueType ListValueType; // Compiler hint for better unrolling: VTK_ASSUME(this->Ptr->GetNumberOfComponents() == nComponents); const int tupleLength = sizeof(primitiveT)*nComponents; primitiveT buffer[nComponents]; for (int i = 0; i < size; i++) { const int readLength = io.Read(reinterpret_cast(buffer), tupleLength); if (readLength != tupleLength) { throw vtkFoamError() << "Failed to read tuple " << i << " of " << size << ": Expected " << tupleLength << " bytes, got " << readLength << " bytes."; } for (int c = 0; c < nComponents; ++c) { this->Ptr->SetTypedComponent(i, c, static_cast(buffer[c])); } } } } void ReadValue(vtkFoamIOobject& io, vtkFoamToken& currToken) { if (currToken != '(') { throw vtkFoamError() << "Expected '(', found " << currToken; } primitiveT v[nComponents]; for (int j = 0; j < nComponents; j++) { v[j] = vtkFoamReadValue::ReadValue(io); } this->Ptr->InsertNextTuple(v); io.ReadExpecting(')'); } }; vtkFoamEntryValue(const vtkFoamEntry *upperEntryPtr) : vtkFoamToken(), IsUniform(false), Managed(true), UpperEntryPtr(upperEntryPtr) { } vtkFoamEntryValue(vtkFoamEntryValue&, const vtkFoamEntry *); ~vtkFoamEntryValue() { this->Clear(); } void SetEmptyList() { this->Clear(); this->IsUniform = false; this->Superclass::Type = EMPTYLIST; } bool GetIsUniform() const { return this->IsUniform; } int Read(vtkFoamIOobject& io); void ReadDictionary(vtkFoamIOobject& io, const vtkFoamToken& firstKeyword); const vtkDataArray& LabelList() const { return *this->Superclass::LabelListPtr; } vtkDataArray& LabelList() { return *this->Superclass::LabelListPtr; } const vtkFoamLabelVectorVector& LabelListList() const { return *this->Superclass::LabelListListPtr; } const vtkFloatArray& ScalarList() const { return *this->Superclass::ScalarListPtr; } vtkFloatArray& ScalarList() { return *this->Superclass::ScalarListPtr; } const vtkFloatArray& VectorList() const { return *this->Superclass::VectorListPtr; } const vtkFoamDict& Dictionary() const { return *this->Superclass::DictPtr; } vtkFoamDict& Dictionary() { return *this->Superclass::DictPtr; } void *Ptr() { this->Managed = false; // returned pointer will not be deleted by the d'tor // all list pointers are in a single union return (void *)this->Superclass::LabelListPtr; } vtkStdString ToString() const { return this->Superclass::Type == STRING ? this->Superclass::ToString() : vtkStdString(); } float ToFloat() const { return this->Superclass::Type == SCALAR || this->Superclass::Type == LABEL ? this->Superclass::To() : 0.0F; } double ToDouble() const { return this->Superclass::Type == SCALAR || this->Superclass::Type == LABEL ? this->Superclass::To() : 0.0; } // TODO is it ok to always use a 64bit int here? vtkTypeInt64 ToInt() const { return this->Superclass::Type == LABEL ? this->Superclass::To() : 0; } // the following two are for an exceptional expression of // `LABEL{LABELorSCALAR}' without type prefix (e. g. `2{-0}' in // mixedRhoE B.C. in rhopSonicFoam/shockTube) void MakeLabelList(const vtkTypeInt64 labelValue, const vtkIdType size) { assert("Label type not set!" && this->GetLabelType() != NO_LABEL_TYPE); this->Superclass::Type = LABELLIST; if (this->LabelType == INT32) { vtkTypeInt32Array *array = vtkTypeInt32Array::New(); array->SetNumberOfValues(size); for (vtkIdType i = 0; i < size; ++i) { array->SetValue(i, static_cast(labelValue)); } this->Superclass::LabelListPtr = array; } else { vtkTypeInt64Array *array = vtkTypeInt64Array::New(); array->SetNumberOfValues(size); for (vtkIdType i = 0; i < size; ++i) { array->SetValue(i, labelValue); } this->Superclass::LabelListPtr = array; } } void MakeScalarList(const float scalarValue, const vtkIdType size) { this->Superclass::ScalarListPtr = vtkFloatArray::New(); this->Superclass::Type = SCALARLIST; this->Superclass::ScalarListPtr->SetNumberOfValues(size); for (int i = 0; i < size; i++) { this->Superclass::ScalarListPtr->SetValue(i, scalarValue); } } // reads dimensionSet void ReadDimensionSet(vtkFoamIOobject& io) { assert("Label type not set!" && this->GetLabelType() != NO_LABEL_TYPE); const int nDims = 7; this->Superclass::Type = LABELLIST; if (this->LabelType == INT32) { vtkTypeInt32Array *array = vtkTypeInt32Array::New(); array->SetNumberOfValues(nDims); for (vtkIdType i = 0; i < nDims; ++i) { array->SetValue(i, vtkFoamReadValue::ReadValue(io)); } this->Superclass::LabelListPtr = array; } else { vtkTypeInt64Array *array = vtkTypeInt64Array::New(); array->SetNumberOfValues(nDims); for (vtkIdType i = 0; i < nDims; ++i) { array->SetValue(i, vtkFoamReadValue::ReadValue(io)); } this->Superclass::LabelListPtr = array; } io.ReadExpecting(']'); } template void ReadNonuniformList(vtkFoamIOobject& io); // reads a list of labelLists. requires size prefix of the listList // to be present. size of each sublist must also be present in the // stream if the format is binary. void ReadLabelListList(vtkFoamIOobject& io) { assert("Label type not set!" && this->GetLabelType() != NO_LABEL_TYPE); bool use64BitLabels = this->LabelType == INT64; vtkFoamToken currToken; currToken.SetLabelType(this->LabelType); if (!io.Read(currToken)) { throw vtkFoamError() << "Unexpected EOF"; } if (currToken.GetType() == vtkFoamToken::LABEL) { const vtkTypeInt64 sizeI = currToken.To(); if (sizeI < 0) { throw vtkFoamError() << "List size must not be negative: size = " << sizeI; } // gives initial guess for list size if (use64BitLabels) { this->LabelListListPtr = new vtkFoamLabel64VectorVector(sizeI, 4 * sizeI); } else { this->LabelListListPtr = new vtkFoamLabel32VectorVector(sizeI, 4 * sizeI); } this->Superclass::Type = LABELLISTLIST; io.ReadExpecting('('); vtkIdType bodyI = 0; for (int i = 0; i < sizeI; i++) { if (!io.Read(currToken)) { throw vtkFoamError() << "Unexpected EOF"; } if (currToken.GetType() == vtkFoamToken::LABEL) { const vtkTypeInt64 sizeJ = currToken.To(); if (sizeJ < 0) { throw vtkFoamError() << "List size must not be negative: size = " << sizeJ; } void *listI = this->LabelListListPtr->WritePointer(i, bodyI, sizeJ); if (io.GetFormat() == vtkFoamIOobject::ASCII) { io.ReadExpecting('('); for (int j = 0; j < sizeJ; j++) { SetLabelValue(listI, j, vtkFoamReadValue::ReadValue(io), use64BitLabels); } io.ReadExpecting(')'); } else { if (sizeJ > 0) // avoid invalid reference to labelListI.at(0) { io.ReadExpecting('('); io.Read(reinterpret_cast(listI), static_cast(sizeJ * this->LabelListListPtr->GetLabelSize())); io.ReadExpecting(')'); } } bodyI += sizeJ; } else if (currToken == '(') { this->Superclass::LabelListListPtr->SetIndex(i, bodyI); while (io.Read(currToken) && currToken != ')') { if (currToken.GetType() != vtkFoamToken::LABEL) { throw vtkFoamError() << "Expected an integer, found " << currToken; } this->Superclass::LabelListListPtr ->InsertValue(bodyI++, currToken.To()); } } else { throw vtkFoamError() << "Expected integer or '(', found " << currToken; } } // set the next index of the last element to calculate the last // subarray size this->Superclass::LabelListListPtr->SetIndex(sizeI, bodyI); // shrink to the actually used size this->Superclass::LabelListListPtr->ResizeBody(bodyI); io.ReadExpecting(')'); } else { throw vtkFoamError() << "Expected integer, found " << currToken; } } // reads compact list of labels. void ReadCompactIOLabelList(vtkFoamIOobject& io) { if (io.GetFormat() != vtkFoamIOobject::BINARY) { this->ReadLabelListList(io); return; } assert("Label type not set!" && this->GetLabelType() != NO_LABEL_TYPE); bool use64BitLabels = this->LabelType == INT64; if (use64BitLabels) { this->LabelListListPtr = new vtkFoamLabel64VectorVector; } else { this->LabelListListPtr = new vtkFoamLabel32VectorVector; } this->Superclass::Type = LABELLISTLIST; for(int arrayI = 0; arrayI < 2; arrayI++) { vtkFoamToken currToken; if (!io.Read(currToken)) { throw vtkFoamError() << "Unexpected EOF"; } if (currToken.GetType() == vtkFoamToken::LABEL) { vtkTypeInt64 sizeI = currToken.To(); if (sizeI < 0) { throw vtkFoamError() << "List size must not be negative: size = " << sizeI; } if (sizeI > 0) // avoid invalid reference { vtkDataArray *array = (arrayI == 0 ? this->Superclass::LabelListListPtr->GetIndices() : this->Superclass::LabelListListPtr->GetBody()); array->SetNumberOfValues(static_cast(sizeI)); io.ReadExpecting('('); io.Read(reinterpret_cast(array->GetVoidPointer(0)), static_cast(sizeI * array->GetDataTypeSize())); io.ReadExpecting(')'); } } else { throw vtkFoamError() << "Expected integer, found " << currToken; } } } bool ReadField(vtkFoamIOobject& io) { try { // lagrangian labels (cf. gnemdFoam/nanoNozzle) if(io.GetClassName() == "labelField") { assert("Label type not set!" && this->GetLabelType() != NO_LABEL_TYPE); if (this->LabelType == INT64) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } // lagrangian scalars else if(io.GetClassName() == "scalarField") { if (io.GetUse64BitFloats()) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } else if(io.GetClassName() == "sphericalTensorField") { if (io.GetUse64BitFloats()) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } // polyMesh/points, lagrangian vectors else if(io.GetClassName() == "vectorField") { if (io.GetUse64BitFloats()) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } else if(io.GetClassName() == "symmTensorField") { if (io.GetUse64BitFloats()) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } else if(io.GetClassName() == "tensorField") { if (io.GetUse64BitFloats()) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } else { throw vtkFoamError() << "Non-supported field type " << io.GetClassName(); } } catch(vtkFoamError& e) { io.SetError(e); return false; } return true; } }; // I'm removing this method because it looks like a hack and is preventing // well-formed datasets from loading. This method overrides ReadBinaryList // for float data by assuming that the data is really stored as doubles, and // converting each value to float as it's read. Leaving this here in case // someone knows why it exists... // // specialization for reading double precision binary into vtkFloatArray. // Must precede ReadNonuniformList() below (HP-UXia64-aCC). //template<> //void vtkFoamEntryValue::listTraits::ReadBinaryList( // vtkFoamIOobject& io, const int size) //{ // for (int i = 0; i < size; i++) // { // double buffer; // io.Read(reinterpret_cast(&buffer), sizeof(double)); // this->Ptr->SetValue(i, static_cast(buffer)); // } //} // generic reader for nonuniform lists. requires size prefix of the // list to be present in the stream if the format is binary. template void vtkFoamEntryValue::ReadNonuniformList(vtkFoamIOobject& io) { vtkFoamToken currToken; if (!io.Read(currToken)) { throw vtkFoamError() << "Unexpected EOF"; } traitsT list; this->Superclass::Type = listType; this->Superclass::VtkObjectPtr = list.GetPtr(); if (currToken.Is()) { const vtkTypeInt64 size = currToken.To(); if (size < 0) { throw vtkFoamError() << "List size must not be negative: size = " << size; } list.GetPtr()->SetNumberOfTuples(size); if (io.GetFormat() == vtkFoamIOobject::ASCII) { if (!io.Read(currToken)) { throw vtkFoamError() << "Unexpected EOF"; } // some objects have lists with only one element enclosed by {} // e. g. simpleFoam/pitzDaily3Blocks/constant/polyMesh/faceZones if (currToken == '{') { list.ReadUniformValues(io, size); io.ReadExpecting('}'); return; } else if (currToken != '(') { throw vtkFoamError() << "Expected '(', found " << currToken; } list.ReadAsciiList(io, size); io.ReadExpecting(')'); } else { if (size > 0) { // read parentheses only when size > 0 io.ReadExpecting('('); list.ReadBinaryList(io, static_cast(size)); io.ReadExpecting(')'); } } } else if (currToken == '(') { while (io.Read(currToken) && currToken != ')') { list.ReadValue(io, currToken); } list.GetPtr()->Squeeze(); } else { throw vtkFoamError() << "Expected integer or '(', found " << currToken; } } //----------------------------------------------------------------------------- // class vtkFoamEntry // a class that represents an entry of a dictionary. note that an // entry can have more than one value. struct vtkFoamEntry : public std::vector { private: typedef std::vector Superclass; vtkStdString Keyword; vtkFoamDict *UpperDictPtr; vtkFoamEntry(); public: vtkFoamEntry(vtkFoamDict *upperDictPtr) : UpperDictPtr(upperDictPtr) { } vtkFoamEntry(const vtkFoamEntry& entry, vtkFoamDict *upperDictPtr) : Superclass(entry.size()), Keyword(entry.GetKeyword()), UpperDictPtr(upperDictPtr) { for (size_t valueI = 0; valueI < entry.size(); valueI++) { this->Superclass::operator[](valueI) = new vtkFoamEntryValue(*entry[valueI], this); } } ~vtkFoamEntry() { this->Clear(); } void Clear() { for (size_t i = 0; i < this->Superclass::size(); i++) { delete this->Superclass::operator[](i); } this->Superclass::clear(); } const vtkStdString& GetKeyword() const { return this->Keyword; } void SetKeyword(const vtkStdString& keyword) { this->Keyword = keyword; } const vtkFoamEntryValue& FirstValue() const { return *this->Superclass::operator[](0); } vtkFoamEntryValue& FirstValue() { return *this->Superclass::operator[](0); } const vtkDataArray& LabelList() const { return this->FirstValue().LabelList(); } vtkDataArray& LabelList() { return this->FirstValue().LabelList(); } const vtkFoamLabelVectorVector& LabelListList() const { return this->FirstValue().LabelListList(); } const vtkFloatArray& ScalarList() const { return this->FirstValue().ScalarList(); } vtkFloatArray& ScalarList() { return this->FirstValue().ScalarList(); } const vtkFloatArray& VectorList() const { return this->FirstValue().VectorList(); } const vtkFoamDict& Dictionary() const { return this->FirstValue().Dictionary(); } vtkFoamDict& Dictionary() { return this->FirstValue().Dictionary(); } void *Ptr() { return this->FirstValue().Ptr(); } const vtkFoamDict *GetUpperDictPtr() const { return this->UpperDictPtr; } vtkStdString ToString() const { return !this->empty() ? this->FirstValue().ToString() : vtkStdString(); } float ToFloat() const { return !this->empty() ? this->FirstValue().ToFloat() : 0.0F; } double ToDouble() const { return !this->empty() ? this->FirstValue().ToDouble() : 0.0; } vtkTypeInt64 ToInt() const { return !this->empty() ? this->FirstValue().ToInt() : 0; } void ReadDictionary(vtkFoamIOobject& io) { this->Superclass::push_back(new vtkFoamEntryValue(this)); this->Superclass::back()->ReadDictionary(io, vtkFoamToken()); } // read values of an entry void Read(vtkFoamIOobject& io); }; //----------------------------------------------------------------------------- // class vtkFoamDict // a class that holds a FoamFile data structure struct vtkFoamDict : public std::vector { private: typedef std::vector Superclass; vtkFoamToken Token; const vtkFoamDict *UpperDictPtr; vtkFoamDict(const vtkFoamDict &); public: vtkFoamDict(const vtkFoamDict *upperDictPtr = nullptr) : Superclass(), Token(), UpperDictPtr(upperDictPtr) { } vtkFoamDict(const vtkFoamDict& dict, const vtkFoamDict *upperDictPtr) : Superclass(dict.size()), Token(), UpperDictPtr(upperDictPtr) { if (dict.GetType() == vtkFoamToken::DICTIONARY) { for (size_t entryI = 0; entryI < dict.size(); entryI++) { this->operator[](entryI) = new vtkFoamEntry(*dict[entryI], this); } } } ~vtkFoamDict() { if (this->Token.GetType() == vtkFoamToken::UNDEFINED) { for (size_t i = 0; i < this->Superclass::size(); i++) { delete this->operator[](i); } } } vtkFoamToken::labelType GetLabelType() const { return this->Token.GetLabelType(); } void SetLabelType(vtkFoamToken::labelType lt) { this->Token.SetLabelType(lt); } vtkFoamToken::tokenType GetType() const { return this->Token.GetType() == vtkFoamToken::UNDEFINED ? vtkFoamToken::DICTIONARY : this->Token.GetType(); } const vtkFoamToken &GetToken() const { return this->Token; } const vtkFoamDict *GetUpperDictPtr() const { return this->UpperDictPtr; } vtkFoamEntry *Lookup(const vtkStdString& keyword) const { if (this->Token.GetType() == vtkFoamToken::UNDEFINED) { for (size_t i = 0; i < this->Superclass::size(); i++) { if (this->operator[](i)->GetKeyword() == keyword) // found { return this->operator[](i); } } } // not found return nullptr; } // reads a FoamFile or a subdictionary. if the stream to be read is // a subdictionary the preceding '{' is assumed to have already been // thrown away. bool Read(vtkFoamIOobject& io, const bool isSubDictionary = false, const vtkFoamToken& firstToken = vtkFoamToken()) { try { vtkFoamToken currToken; if(firstToken.GetType() == vtkFoamToken::UNDEFINED) { // read the first token if(!io.Read(currToken)) { throw vtkFoamError() << "Unexpected EOF"; } if(isSubDictionary) { // the following if clause is for an exceptional expression // of `LABEL{LABELorSCALAR}' without type prefix // (e. g. `2{-0}' in mixedRhoE B.C. in // rhopSonicFoam/shockTube) if(currToken.GetType() == vtkFoamToken::LABEL || currToken.GetType() == vtkFoamToken::SCALAR) { this->Token = currToken; io.ReadExpecting('}'); return true; } // return as empty dictionary else if(currToken == '}') { return true; } } else { // list of dictionaries is read as a usual dictionary // polyMesh/boundary, point/face/cell-Zones if(currToken.GetType() == vtkFoamToken::LABEL) { io.ReadExpecting('('); if(currToken.To() > 0) { if(!io.Read(currToken)) { throw vtkFoamError() << "Unexpected EOF"; } // continue to read as a usual dictionary } else // return as empty dictionary { io.ReadExpecting(')'); return true; } } // some boundary files does not have the number of boundary // patches (e.g. settlingFoam/tank3D). in this case we need to // explicitly read the file as a dictionary. else if(currToken == '(' && io.GetClassName() == "polyBoundaryMesh") // polyMesh/boundary { if(!io.Read(currToken)) // read the first keyword { throw vtkFoamError() << "Unexpected EOF"; } if(currToken == ')') // return as empty dictionary { return true; } } } } // if firstToken is given as string read the following stream as // subdictionary else if(firstToken.GetType() == vtkFoamToken::STRING) { this->Superclass::push_back(new vtkFoamEntry(this)); this->Superclass::back()->SetKeyword(firstToken.ToString()); this->Superclass::back()->ReadDictionary(io); if(!io.Read(currToken) || currToken == '}' || currToken == ')') { return true; } } else // quite likely an identifier { currToken = firstToken; } if(currToken == ';' || currToken.GetType() == vtkFoamToken::STRING || currToken.GetType() == vtkFoamToken::IDENTIFIER) { // general dictionary do { if(currToken.GetType() == vtkFoamToken::STRING) { vtkFoamEntry *previousEntry = this->Lookup(currToken.ToString()); if(previousEntry != nullptr) { if(io.GetInputMode() == vtkFoamFile::INPUT_MODE_MERGE) { if(previousEntry->FirstValue().GetType() == vtkFoamToken::DICTIONARY) { io.ReadExpecting('{'); previousEntry->FirstValue().Dictionary().Read(io, true); } else { previousEntry->Clear(); previousEntry->Read(io); } } else if(io.GetInputMode() == vtkFoamFile::INPUT_MODE_OVERWRITE) { previousEntry->Clear(); previousEntry->Read(io); } else // INPUT_MODE_ERROR { throw vtkFoamError() << "Found duplicated entries with keyword " << currToken.ToString(); } } else { this->Superclass::push_back(new vtkFoamEntry(this)); this->Superclass::back()->SetKeyword(currToken.ToString()); this->Superclass::back()->Read(io); } if(currToken == "FoamFile") { // delete the FoamFile header subdictionary entry delete this->Superclass::back(); this->Superclass::pop_back(); } else if(currToken == "include") { // include the named file. Exiting the included file at // EOF will be handled automatically by // vtkFoamFile::closeIncludedFile() if(this->Superclass::back()->FirstValue().GetType() != vtkFoamToken::STRING) { throw vtkFoamError() << "Expected string as the file name to be included, found " << this->Superclass::back()->FirstValue(); } const vtkStdString includeFileName( this->Superclass::back()->ToString()); delete this->Superclass::back(); this->Superclass::pop_back(); io.IncludeFile(includeFileName, io.GetFilePath()); } } else if(currToken.GetType() == vtkFoamToken::IDENTIFIER) { // substitute identifier const vtkStdString identifier(currToken.ToIdentifier()); for(const vtkFoamDict *uDictPtr = this;;) { const vtkFoamEntry *identifiedEntry = uDictPtr->Lookup(identifier); if(identifiedEntry != nullptr) { if(identifiedEntry->FirstValue().GetType() != vtkFoamToken::DICTIONARY) { throw vtkFoamError() << "Expected dictionary for substituting entry " << identifier; } const vtkFoamDict& identifiedDict = identifiedEntry->FirstValue().Dictionary(); for(size_t entryI = 0; entryI < identifiedDict.size(); entryI++) { // I think #inputMode handling should be done here // as well, but the genuine FoamFile parser for OF // 1.5 does not seem to be doing it. this->Superclass::push_back( new vtkFoamEntry(*identifiedDict[entryI], this)); } break; } else { uDictPtr = uDictPtr->GetUpperDictPtr(); if(uDictPtr == nullptr) { throw vtkFoamError() << "Substituting entry " << identifier << " not found"; } } } } // skip empty entry only with ';' }while(io.Read(currToken) && (currToken.GetType() == vtkFoamToken::STRING || currToken.GetType() == vtkFoamToken::IDENTIFIER || currToken == ';')); if(currToken.GetType() == vtkFoamToken::TOKEN_ERROR || currToken == '}' || currToken == ')') { return true; } throw vtkFoamError() << "Expected keyword, closing brace, ';' or EOF, found " << currToken; } throw vtkFoamError() << "Expected keyword or identifier, found " << currToken; } catch(vtkFoamError& e) { if(isSubDictionary) { throw; } else { io.SetError(e); return false; } } } }; void vtkFoamIOobject::ReadHeader() { vtkFoamToken firstToken; firstToken.SetLabelType( this->Reader->GetUse64BitLabels() ? vtkFoamToken::INT64 : vtkFoamToken::INT32); this->Superclass::ReadExpecting("FoamFile"); this->Superclass::ReadExpecting('{'); vtkFoamDict headerDict; headerDict.SetLabelType(firstToken.GetLabelType()); // throw exception in case of error headerDict.Read(*this, true, vtkFoamToken()); const vtkFoamEntry *formatEntry = headerDict.Lookup("format"); if (formatEntry == nullptr) { throw vtkFoamError() << "format entry (binary/ascii) not found in FoamFile header"; } // case does matter (e. g. "BINARY" is treated as ascii) // cf. src/OpenFOAM/db/IOstreams/IOstreams/IOstream.C this->Format = (formatEntry->ToString() == "binary" ? BINARY : ASCII); // Newer (binary) files have 'arch' entry with "label=(32|64) scalar=(32|64)" // If this entry does not exist, or is incomplete, uses the fallback values // that come from the reader (defined in constructor and Close) const vtkFoamEntry *archEntry = headerDict.Lookup("arch"); if (archEntry) { const vtkStdString archValue = archEntry->ToString(); vtksys::RegularExpression re; if (re.compile("^.*label *= *(32|64).*$") && re.find(archValue.c_str())) { this->Use64BitLabels = ("64" == re.match(1)); } if (re.compile("^.*scalar *= *(32|64).*$") && re.find(archValue.c_str())) { this->Use64BitFloats = ("64" == re.match(1)); } } const vtkFoamEntry *classEntry = headerDict.Lookup("class"); if (classEntry == nullptr) { throw vtkFoamError() << "class name not found in FoamFile header"; } this->HeaderClassName = classEntry->ToString(); const vtkFoamEntry *objectEntry = headerDict.Lookup("object"); if (objectEntry == nullptr) { throw vtkFoamError() << "object name not found in FoamFile header"; } this->ObjectName = objectEntry->ToString(); } vtkFoamEntryValue::vtkFoamEntryValue( vtkFoamEntryValue& value, const vtkFoamEntry *upperEntryPtr) : vtkFoamToken(value), IsUniform(value.GetIsUniform()), Managed(true), UpperEntryPtr(upperEntryPtr) { switch (this->Superclass::Type) { case VECTORLIST: { vtkFloatArray *fa = vtkFloatArray::SafeDownCast(value.ToVTKObject()); if(fa->GetNumberOfComponents() == 6) { // create deepcopies for vtkObjects to avoid duplicated mainpulation vtkFloatArray *newfa = vtkFloatArray::New(); newfa->DeepCopy(fa); this->Superclass::VtkObjectPtr = newfa; } else { this->Superclass::VtkObjectPtr = value.ToVTKObject(); this->Superclass::VtkObjectPtr->Register(nullptr); } } break; case LABELLIST: case SCALARLIST: case STRINGLIST: this->Superclass::VtkObjectPtr = value.ToVTKObject(); this->Superclass::VtkObjectPtr->Register(nullptr); break; case LABELLISTLIST: assert("Label type not set!" && this->GetLabelType() != NO_LABEL_TYPE); if (this->LabelType == INT32) { this->LabelListListPtr = new vtkFoamLabel32VectorVector(*value.LabelListListPtr); } else { this->LabelListListPtr = new vtkFoamLabel64VectorVector(*value.LabelListListPtr); } break; case ENTRYVALUELIST: { const size_t nValues = value.EntryValuePtrs->size(); this->EntryValuePtrs = new std::vector(nValues); for (size_t valueI = 0; valueI < nValues; valueI++) { this->EntryValuePtrs->operator[](valueI) = new vtkFoamEntryValue( *value.EntryValuePtrs->operator[](valueI), upperEntryPtr); } } break; case DICTIONARY: // UpperEntryPtr is null when called from vtkFoamDict constructor if (this->UpperEntryPtr != nullptr) { this->DictPtr = new vtkFoamDict(*value.DictPtr, this->UpperEntryPtr->GetUpperDictPtr()); this->DictPtr->SetLabelType(value.GetLabelType()); } else { this->DictPtr = nullptr; } break; case BOOLLIST: break; case EMPTYLIST: break; case UNDEFINED: case PUNCTUATION: case LABEL: case SCALAR: case STRING: case IDENTIFIER: case TOKEN_ERROR: default: break; } } void vtkFoamEntryValue::Clear() { if (this->Managed) { switch (this->Superclass::Type) { case LABELLIST: case SCALARLIST: case VECTORLIST: case STRINGLIST: this->VtkObjectPtr->Delete(); break; case LABELLISTLIST: delete this->LabelListListPtr; break; case ENTRYVALUELIST: for (size_t valueI = 0; valueI < this->EntryValuePtrs->size() ; valueI++) { delete this->EntryValuePtrs->operator[](valueI); } delete this->EntryValuePtrs; break; case DICTIONARY: delete this->DictPtr; break; case UNDEFINED: case PUNCTUATION: case LABEL: case SCALAR: case STRING: case IDENTIFIER: case TOKEN_ERROR: case BOOLLIST: case EMPTYLIST: default: break; } } } // general-purpose list reader - guess the type of the list and read // it. only supports ascii format and assumes the preceding '(' has // already been thrown away. the reader supports nested list with // variable lengths (e. g. `((token token) (token token token)).' // also supports compound of tokens and lists (e. g. `((token token) // token)') only if a list comes as the first value. void vtkFoamEntryValue::ReadList(vtkFoamIOobject& io) { assert("Label type not set!" && this->GetLabelType() != NO_LABEL_TYPE); vtkFoamToken currToken; currToken.SetLabelType(this->LabelType); io.Read(currToken); // initial guess of the list type if (currToken.GetType() == this->Superclass::LABEL) { // if the first token is of type LABEL it might be either an element of // a labelList or the size of a sublist so proceed to the next token vtkFoamToken nextToken; nextToken.SetLabelType(this->LabelType); if (!io.Read(nextToken)) { throw vtkFoamError() << "Unexpected EOF"; } if (nextToken.GetType() == this->Superclass::LABEL) { if (this->LabelType == INT32) { vtkTypeInt32Array *array = vtkTypeInt32Array::New(); array->InsertNextValue(currToken.To()); array->InsertNextValue(nextToken.To()); this->Superclass::LabelListPtr = array; } else { vtkTypeInt64Array *array = vtkTypeInt64Array::New(); array->InsertNextValue(currToken.To()); array->InsertNextValue(nextToken.To()); this->Superclass::LabelListPtr = array; } this->Superclass::Type = LABELLIST; } else if (nextToken.GetType() == this->Superclass::SCALAR) { this->Superclass::ScalarListPtr = vtkFloatArray::New(); this->Superclass::ScalarListPtr->InsertNextValue(currToken.To()); this->Superclass::ScalarListPtr->InsertNextValue(nextToken.To()); this->Superclass::Type = SCALARLIST; } else if (nextToken == '(') // list of list: read recursively { this->Superclass::EntryValuePtrs = new std::vector; this->Superclass::EntryValuePtrs->push_back(new vtkFoamEntryValue( this->UpperEntryPtr)); this->Superclass::EntryValuePtrs->back()->SetLabelType(this->LabelType); this->Superclass::EntryValuePtrs->back()->ReadList(io); this->Superclass::Type = ENTRYVALUELIST; } else if (nextToken == ')') // list with only one label element { if (this->LabelType == INT32) { vtkTypeInt32Array *array = vtkTypeInt32Array::New(); array->SetNumberOfValues(1); array->SetValue(0, currToken.To()); this->Superclass::LabelListPtr = array; } else { vtkTypeInt64Array *array = vtkTypeInt64Array::New(); array->SetNumberOfValues(1); array->SetValue(0, currToken.To()); this->Superclass::LabelListPtr = array; } this->Superclass::Type = LABELLIST; return; } else { throw vtkFoamError() << "Expected number, '(' or ')', found " << nextToken; } } else if (currToken.GetType() == this->Superclass::SCALAR) { this->Superclass::ScalarListPtr = vtkFloatArray::New(); this->Superclass::ScalarListPtr->InsertNextValue(currToken.To()); this->Superclass::Type = SCALARLIST; } // if the first word is a string we have to read another token to determine // if the first word is a keyword for the following dictionary else if (currToken.GetType() == this->Superclass::STRING) { vtkFoamToken nextToken; nextToken.SetLabelType(this->LabelType); if (!io.Read(nextToken)) { throw vtkFoamError() << "Unexpected EOF"; } if (nextToken.GetType() == this->Superclass::STRING) // list of strings { this->Superclass::StringListPtr = vtkStringArray::New(); this->Superclass::StringListPtr->InsertNextValue(currToken.ToString()); this->Superclass::StringListPtr->InsertNextValue(nextToken.ToString()); this->Superclass::Type = STRINGLIST; } // dictionary with the already read stringToken as the first keyword else if (nextToken == '{') { if (currToken.ToString().empty()) { throw "Empty string is invalid as a keyword for dictionary entry"; } this->ReadDictionary(io, currToken); // the dictionary read as list has the entry terminator ';' so // we have to skip it return; } else if (nextToken == ')') // list with only one string element { this->Superclass::StringListPtr = vtkStringArray::New(); this->Superclass::StringListPtr->SetNumberOfValues(1); this->Superclass::StringListPtr->SetValue(0, currToken.ToString()); this->Superclass::Type = STRINGLIST; return; } else { throw vtkFoamError() << "Expected string, '{' or ')', found " << nextToken; } } // list of lists or dictionaries: read recursively else if (currToken == '(' || currToken == '{') { this->Superclass::EntryValuePtrs = new std::vector; this->Superclass::EntryValuePtrs->push_back(new vtkFoamEntryValue( this->UpperEntryPtr)); this->Superclass::EntryValuePtrs->back()->SetLabelType(this->LabelType); if(currToken == '(') { this->Superclass::EntryValuePtrs->back()->ReadList(io); } else // currToken == '{' { this->Superclass::EntryValuePtrs->back()->ReadDictionary(io, vtkFoamToken()); } // read all the following values as arbitrary entryValues // the alphaContactAngle b.c. in multiphaseInterFoam/damBreak4phase // reaquires this treatment (reading by readList() is not enough) do { this->Superclass::EntryValuePtrs->push_back(new vtkFoamEntryValue( this->UpperEntryPtr)); this->Superclass::EntryValuePtrs->back()->Read(io); } while (*this->Superclass::EntryValuePtrs->back() != ')' && *this->Superclass::EntryValuePtrs->back() != '}' && *this->Superclass::EntryValuePtrs->back() != ';'); if (*this->Superclass::EntryValuePtrs->back() != ')') { throw vtkFoamError() << "Expected ')' before " << *this->Superclass::EntryValuePtrs->back(); } // delete ')' delete this->Superclass::EntryValuePtrs->back(); this->EntryValuePtrs->pop_back(); this->Superclass::Type = ENTRYVALUELIST; return; } else if (currToken == ')') // empty list { this->Superclass::Type = EMPTYLIST; return; } // FIXME: may (or may not) need identifier handling while (io.Read(currToken) && currToken != ')') { if (this->Superclass::Type == LABELLIST) { if (currToken.GetType() == this->Superclass::SCALAR) { // switch to scalarList // LabelListPtr and ScalarListPtr are packed into a single union so // we need a temporary pointer vtkFloatArray* slPtr = vtkFloatArray::New(); vtkIdType size = this->Superclass::LabelListPtr->GetNumberOfTuples(); slPtr->SetNumberOfValues(size + 1); for (int i = 0; i < size; i++) { slPtr->SetValue(i, static_cast( GetLabelValue(this->LabelListPtr, i, this->LabelType == INT64))); } this->LabelListPtr->Delete(); slPtr->SetValue(size, currToken.To()); // copy after LabelListPtr is deleted this->Superclass::ScalarListPtr = slPtr; this->Superclass::Type = SCALARLIST; } else if (currToken.GetType() == this->Superclass::LABEL) { assert("Label type not set!" && currToken.GetLabelType() != NO_LABEL_TYPE); if (currToken.GetLabelType() == INT32) { assert(vtkTypeInt32Array::FastDownCast(this->LabelListPtr) != nullptr); static_cast(this->LabelListPtr)->InsertNextValue( currToken.To()); } else { assert(vtkTypeInt64Array::FastDownCast(this->LabelListPtr) != nullptr); static_cast(this->LabelListPtr)->InsertNextValue( currToken.To()); } } else { throw vtkFoamError() << "Expected a number, found " << currToken; } } else if (this->Superclass::Type == this->Superclass::SCALARLIST) { if (currToken.Is()) { this->Superclass::ScalarListPtr->InsertNextValue(currToken.To()); } else if (currToken == '(') { vtkGenericWarningMacro("Found a list containing scalar data followed " "by a nested list, but this reader only " "supports nested lists that precede all " "scalars. Discarding nested list data."); vtkFoamEntryValue tmp(this->UpperEntryPtr); tmp.SetLabelType(this->LabelType); tmp.ReadList(io); } else { throw vtkFoamError() << "Expected a number, found " << currToken; } } else if (this->Superclass::Type == this->Superclass::STRINGLIST) { if (currToken.GetType() == this->Superclass::STRING) { this->Superclass::StringListPtr->InsertNextValue(currToken.ToString()); } else { throw vtkFoamError() << "Expected a string, found " << currToken; } } else if (this->Superclass::Type == this->Superclass::ENTRYVALUELIST) { if (currToken.GetType() == this->Superclass::LABEL) { // skip the number of elements to make things simple if (!io.Read(currToken)) { throw vtkFoamError() << "Unexpected EOF"; } } if (currToken != '(') { throw vtkFoamError() << "Expected '(', found " << currToken; } this->Superclass::EntryValuePtrs->push_back(new vtkFoamEntryValue(this->UpperEntryPtr)); this->Superclass::EntryValuePtrs->back()->ReadList(io); } else { throw vtkFoamError() << "Unexpected token " << currToken; } } if (this->Superclass::Type == this->Superclass::LABELLIST) { this->Superclass::LabelListPtr->Squeeze(); } else if (this->Superclass::Type == this->Superclass::SCALARLIST) { this->Superclass::ScalarListPtr->Squeeze(); } else if (this->Superclass::Type == this->Superclass::STRINGLIST) { this->Superclass::StringListPtr->Squeeze(); } } // a list of dictionaries is actually read as a dictionary void vtkFoamEntryValue::ReadDictionary(vtkFoamIOobject& io, const vtkFoamToken& firstKeyword) { this->Superclass::DictPtr = new vtkFoamDict(this->UpperEntryPtr->GetUpperDictPtr()); this->DictPtr->SetLabelType( io.GetUse64BitLabels() ? vtkFoamToken::INT64 : vtkFoamToken::INT32); this->Superclass::Type = this->Superclass::DICTIONARY; this->Superclass::DictPtr->Read(io, true, firstKeyword); } // guess the type of the given entry value and read it // return value: 0 if encountered end of entry (';') during parsing // composite entry value, 1 otherwise int vtkFoamEntryValue::Read(vtkFoamIOobject& io) { this->SetLabelType(io.GetUse64BitLabels() ? vtkFoamToken::INT64 : vtkFoamToken::INT32); vtkFoamToken currToken; currToken.SetLabelType(this->LabelType); if (!io.Read(currToken)) { throw vtkFoamError() << "Unexpected EOF"; } if (currToken == '{') { this->ReadDictionary(io, vtkFoamToken()); return 1; } // for reading sublist from vtkFoamEntryValue::readList() or there // are cases where lists without the (non)uniform keyword appear // (e. g. coodles/pitsDaily/0/U, uniformFixedValue b.c.) else if (currToken == '(') { this->ReadList(io); return 1; } else if (currToken == '[') { this->ReadDimensionSet(io); return 1; } else if (currToken == "uniform") { if (!io.Read(currToken)) { throw vtkFoamError() << "Expected a uniform value or a list, found unexpected EOF"; } if (currToken == '(') { this->ReadList(io); } else if (currToken == ';') { this->Superclass::operator=("uniform"); return 0; } else if (currToken.GetType() == this->Superclass::LABEL || currToken.GetType() == this->Superclass::SCALAR || currToken.GetType() == this->Superclass::STRING) { this->Superclass::operator=(currToken); } else // unexpected punctuation token { throw vtkFoamError() << "Expected number, string or (, found " << currToken; } this->IsUniform = true; } else if (currToken == "nonuniform") { if (!io.Read(currToken)) { throw vtkFoamError() << "Expected list type specifier, found EOF"; } this->IsUniform = false; if (currToken == "List") { if (io.GetUse64BitFloats()) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } else if (currToken == "List") { if (io.GetUse64BitFloats()) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } else if (currToken == "List") { if (io.GetUse64BitFloats()) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } else if (currToken == "List") { if (io.GetUse64BitFloats()) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } else if (currToken == "List") { if (io.GetUse64BitFloats()) { this->ReadNonuniformList >(io); } else { this->ReadNonuniformList >(io); } } // List may or may not be read as List